So you’ve got a collection of videos that you want to view on your mobile device or tablet. It doesn’t need to be high quality – but you’ve found some files just won’t play back on your device.
The great news is that the open-source tool FFmpeg can convert almost any format video into one that your tablet/phone will support. In addition you can use this tool to potentially make a file smaller and also amplify the audio if the source was too quiet.
The FFmpeg tool runs on Linux and Windows – for the purposes of this article the Windows version will be referenced – but the command line arguments will be almost identical if run from Linux.
Firstly – you need a copy of FFmpeg. I suggest you get a static build. This is a larger executable because it has all the dependent libraries compiled in – this makes the executable slower to load – but run speed will be the same as the leaner version without the libraries built-in and you don’t have to worry about having other dependencies on your system.
The Windows static builds can be downloaded from the Zeranoe FFmpeg Builds page. If you don’t know what you want then get the latest 32-bit static build.
Command Line for Tablet/Phone Encoding
Here is a suggested command line to use (imagine the file you’re converting from is input.avi and you’re writing to output.mp4):
ffmpeg.exe -i "input.avi" -vcodec libx264 -b:v 500000 -g 50 -r 25 -acodec aac -ac 2 -ar 44100 -ab 128k -strict -2 -y "output.mp4"
The parameters mean:
- -i "input.avi" – input file name
- -vcodec libx264 – use the H.264 encoding video codec
- -b:v 500000 – specify the output bitrate for video at 500Kbps
- -g 50 – put a keyframe in every 50 frames
- -r 25 – output frame rate will be 25 frames per second
- -acodec aac – output using the AAC encoding audio codec
- -ac 2 – allow 2 channel output (stereo), necessary because some videos are 5.1 and do not play on CyanogenMod
- -ar 44100 – audio rate in Hz, 44.1KHz is CD-audio
- -ab 128k – bit rate of the output audio, 128k is a compromise between acceptable and high quality
- -strict – allows the H.264 codec
- -2 – allows the H.264 codec
- -y – overwrite the output file if it already exists
- "output.mp4" – output file name, should end in .mp4
I’ve experimented a lot and these values produce video that will play back on CyanogenMod for me. A big lesson was the necessity to force the audio channel count to 2 – some tablet players will simply not play a video with more audio channels than that.
I also use a low video bitrate (500Kbps) which looks blocky on a high-definition monitor – but I find perfectly acceptable on a handheld tablet.
Note that I do not scale the video. I only do scaling when my source video is very big (video I’ve taken on my 1080p Handycam). The options required for this are -vf scale=-1:600 where -1:600 means calculate width and force height to 600 pixels.
There is a function in FFmpeg that can measure volume over a specified period in a video. You can use this information in the above command-line to amplify the audio during transcoding. I do this because watching a quiet video on noisy public transport isn’t an option for me.
So to get information about the volume in, say, the first 10 minutes of the video (after the first 30 seconds in case the first 30 seconds isn’t representative of the overall volume in the video):
ffmpeg.exe -i "input.avi" -af volumedetect -f null -ss 00:00:30 -t 00:10:00 -
This will output a histogram – you can decide how you want to normalise audio based on this histogram.
If you decide you want to amplify your transcoded video then you can specify the dB you want to amplify by using the command line option e.g. -af volume=3.0 for a 3dB volume increase (2x).
Audio compression (also known as companding) is available in FFmpeg. It takes some experimentation to get the values working the way you’d like – but it means you can just feed a video in and get louder audio out without distortion.
The settings I’ve used have been:
- attacks=0.1 0.1 – fast response to audio transients
- decays=3.0 3.0 – slower wait before increasing volume again
- points=-900/-900 -80/-500 -70/-70 -45/-45 -40/-15 -20/-9 -10/-6 0/-3 – graph mapping volume points
- soft-knee=0.50 – unknown
- gain=0 – never got this working
- volume=-900 – starting point for assumptions about average volume
- delay=3.0 – how much audio to process before making decisions, should be the same as decays
Put together, the audio filter I recommend is:
-af "aformat=channel_layouts=stereo,compand=attacks=0.1 0.1:decays=3.0 3.0:points=-900/-900 -80/-500 -70/-70 -45/-45 -40/-15 -20/-9 -10/-6 0/-3:soft-knee=0.50:gain=0:volume=-30:delay=3.0,volume=1.9"
I also added a volume audio filter rather than setting the gain parameter of the compand filter.
Note that the points are set in decibels – and 3dB is a multiplication factor of 2. So by compressing to a maximum of -3dB we limit the compressed volume to half the maximum. This allows us to then multiply the volume by just under 2 to avoid clipping.
It seemed it was necessary to add the aformat before compressing to fix noisy output.