FFmpeg
Installation
Usage
Transcoding
We want to convert a video to a smaller one, of constant size. Let's find out what we have:
$ ls -hgo file.mkv -rw-r--r--. 1 2.5G Dec 29 2012 file.mkv $ ffmpeg -i file.mkv 2>&1 | grep -E 'Duration|Video|Audio' Duration: 01:29:31.28, start: 0.000000, bitrate: 3883 kb/s Stream #0:0(eng): Video: h264 (High), yuv420p(tv, bt709), 1280x720, SAR 1:1 DAR 16:9, 25 fps, 25 tbr, 1k tbn, 50 tbc (default) Stream #0:1(ger): Audio: ac3, 48000 Hz, stereo, fltp, 448 kb/s (default)
Let's see if can convert it to maybe 800 MB. First, calculate the duration of the video in seconds:
$ echo "01:29:31.28" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'
5371.28
Our 800 MB output file should contain a 160 kbps audio track too, so let's do some math here:
800 MB = 819200 kB
5371.28 * 160 / 8 = 107425.6 kB ← audio
711774.4 kB / 5371.28 * 8 = 1060.1 kbps ← video
With that information we can now begin the two-pass encoding[1] process. First we analyze the video track, ignore the audio and discard all output:
ffmpeg -i file.mkv -pass 1 -c:v libx264 -b:v 1060k -an -f rawvideo -y /dev/null
While the output is discarded, two files are generated, ffmpeg2pass-0.log and ffmpeg2pass-0.log.mbtree:
$ ls -hgo ffmpeg2pass-0.log* -rw-------. 1 16M Jan 20 09:15 ffmpeg2pass-0.log -rw-------. 1 603M Jan 20 09:15 ffmpeg2pass-0.log.mbtree
Both will be used in the next step:
ffmpeg -i file.mkv -pass 2 -c:v libx264 -b:v 1060k -c:a libvorbis -b:a 160k -ac 2 file.mp4
The result is slightly below 800 MB:
$ ls -hgo file.mp4 -rw-------. 1 770M Jan 21 10:46 file.mp4
$ ffmpeg -i file.mp4 2>&1 | grep -E 'Duration|Stream'
Duration: 01:29:31.36, start: 0.002667, bitrate: 1201 kb/s
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1059 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc (default)
Stream #0:1(ger): Audio: vorbis (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 133 kb/s (default)
Apparently our audio track encoded by libvorbis is using VBR by default[2].
Results (on a very slow machine, throttled to 800 MHz):
One Pass Encoding $ ffmpeg -i file.mkv -c:v libx264 -b:v 1060k -c:a libvorbis -b:a 160k -ac 2 file.mp4 => finished after 29h, 768 MB file Tow Pass Encoding $ ffmpeg -i file.mkv -pass 1 -c:v libx264 -b:v 1060k -an -f rawvideo -y /dev/null $ ffmpeg -i file.mkv -pass 2 -c:v libx264 -b:v 1060k -c:a libvorbis -b:a 160k -ac 2 file.mp4 => finished after 35h (10h for pass-1, 25h for pass-2), 770 MB file
On a more recent machine, converting a similar file should take no longer than 2-3 hours.
The files from both encoding jobs shared the same properties:
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1059 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc (default) Stream #0:1(ger): Audio: vorbis (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 133 kb/s (default)
Combining
Here we wanted to speed up a video (25min15) so that it could be merged together with an MP3 file (4min22):
ffmpeg -i a.mov -i b.mp3 -acodec copy -ab 128k -ar 44100 -map 0:0 -map 1:0 -vf "setpts=(1/6)*PTS" c.mp4
The order of the arguments matter:
-i video input, audio input -acdodec copy audio stream -ab audio bitrate (bps) -ar audio sampling rate (Hz) -map 0:0 get video from the video file -map 1:0 get audio from the audio file -vf apply a filter graph to the input video
The map and vf options are kinda advanced and the setpts parameter was kinda hard to get right. Basically it increases video speed by 6. The audio input is not affected by this, as it is located on a different (internal) stream, see the map option above. Increasing the video speed by 6 meant that the video would be ~4 minutes long, a bit shorter than the audio track. But for now this was good enough.
Merging
Merging video files is a bit more complicated than it is for audio files. Luckily it's all explained in the official documentation. So, let's assume we want to merge 4 MP4 files into one:
mkfifo temp{1..4}
i=1; ls file*.mp4 | while read f; do ffmpeg -y -i "$f" -c copy -bsf:v h264_mp4toannexb -f mpegts temp${i} 2>/dev/null & i=$((i+1)); done
At this point we have 4 ffmpeg
processes running, waiting for the FIFOs to be read from:
$ ps -f -p `pgrep ffmpeg` UID PID PPID C STIME TTY STAT TIME CMD dummy 10852 1 0 00:34 pts/3 S 0:00 ffmpeg -y -i file1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp1 dummy 10853 1 0 00:34 pts/3 S 0:00 ffmpeg -y -i file2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp2 dummy 10854 1 0 00:34 pts/3 S 0:00 ffmpeg -y -i file3.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp3 dummy 10855 1 0 00:34 pts/3 S 0:00 ffmpeg -y -i file4.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp4
Start another ffmpeg
to read from these FIFO files and produce the output file:
ffmpeg -f mpegts -i "concat:$(ls temp*|xargs|sed 's/ /|/g')" -c copy -bsf:a aac_adtstoasc combined.mp4
rm -f temp{1..4}
Container Formats
To change the container format (instead of re-encoding[3]), we can use:
ffmpeg -i input.mkv -c:v copy -c:a copy output.mp4
Audio
Converting[4] audio files to another format, e.g. Vorbis[5]
ffmpeg -y -i file.wav -c:a libvorbis -qscale:a 3 file.ogg # qscale:a 3 is the default for libvorbis[6] ffmpeg -y -i file.wav -c:a libmp3lame -qscale:a 2 file.mp3 # qscale:a 0 translates to a bitrate of ~220-260 kbps[7] ffmpeg -y -i file.wav -c:a libopus -vbr on file.opus # ?
Notes:
- To get a list of all supported encoders, use ffmpeg -encoders.
- When used in a script, ffmpeg sometimes attempts to read stdin[8][9]:
Press [q] to stop, [?] for help Enter command: <target>|all
Use -nostdin or read from /dev/null to prevent that, e.g.:
ls wav/ | while read f; do ffmpeg -y -vn -i wav/"$f" -c:a libvorbis -qscale:a 3 ogg/"${f/%wav/ogg}" < /dev/null; done
Encode to MP3 with ffmpeg[7][10]
ffmpeg -i file.flac -c:a libmp3lame -qscale:a 0 file.mp3
Slideshow
Make a slideshow video from images:
ffmpeg -pattern_type glob -i 'image*.jpg' -c:v libx264 slideshow.mp4
The single quotes are important, as ffmpeg
will do the globbing, not the shell.
DVD Rip
Let the DVD play once, then select all the parts containing the movie (i.e. skipping VTS_01_0.VOB):
cat VTS_01_[1-8].VOB | ffmpeg -i - -codec:a libvorbis -b:a 128k -codec:v libx264 -b:v 1024k out.mp4
Trim
Trim a long (audio) file to 45 minutes:
ffmpeg -i long.mp3 -t $((45*60)) -c copy short.mp3
But, now our short file will end abpruptly. Let's add a 5 seconds fade out, and trim the file afterwards, and leave some room at the end:
ffmpeg -i long.mp3 -af "afade=t=out:st=$((45*60)):d=5" short.mp3 ffmpeg -i short.mp3 -t $((45*60+10)) -c copy short_fadeout.mp3
Links
- MP3 errors
- Subtitles
- How can I add audio (mp3) to a flv (just video) with ffmpeg?
- How-To: Alter Video Speed with FFmpeg and mjpegtools
- Fast and slow-motion video with ffmpeg
- How to slowdown or speed up a video using FFmpeg and Yuvfps
References
- ↑ FFmpeg and x264 Encoding Guide
- ↑ libvorbis: use VBR by default, with default quality of 3
- ↑ Handbrake settings to convert MKV to MP4 while retaining the original quality
- ↑ Guidelines for high quality lossy audio encoding
- ↑ A Brief Theora and Vorbis Encoding Guide
- ↑ FFmpeg Codecs Documentation: Audio Encoders
- ↑ 7.0 7.1 FFmpeg MP3 Encoding Guide
- ↑ Trouble with ffmpeg in bash script
- ↑ I'm reading a file line by line and running ssh or ffmpeg, only the first line gets processed!
- ↑ FFmpeg