-
Notifications
You must be signed in to change notification settings - Fork 7
Build your own tiny FFMPEG
FFMPEG is known to be a swiss knife for all things video related. Decoding, encoding, demuxing, remuxing, resizing, and anything else you can think of regarding video - FFMPEG does it! That said, there are times when you want FFMPEG to do something really simple instead of doing everything. This is the guide that will help you out with that goal! (With this guide, I was able to get the file size down to ~3 MBs!)
If you don't feel like following this tutorial, simply grab the repo and run the my_tiny_ffmpeg.sh
script inside the FFMPEG_Minimum_Build_Helper_Script
directory to build everything from this tutorial!
For this tutorial, our goal is to achieve the following:
- FFMPEG should be optimized for final binary size, not speed.
- FFMPEG should only be able to decode H.264 video.
- FFMPEG should only be able to encode H.264 video. Optionally, it can just copy the incoming video codec to the destination file.
- FFMPEG should be able to just copy the incoming audio codec to the destination file.
- FFMPEG should be able to resize the incoming video.
- FFMPEG should be able to demux and (re)mux MP4 files. (MP4s are containers that can hold audio and video, in this case H.264 video and arbitrary audio.)
Our target command will look like this:
# Resize "The Simpsons Movie - Trailer.mp4" to half its original width and height,
# then re-encode the result to H.264, copy the audio from the original file, and
# store the result in Simpsons.mp4.
build/ffmpeg -i The\ Simpsons\ Movie\ -\ Trailer.mp4 -vf scale=iw*.5:ih*.5 -vcodec h264 -acodec copy Simpsons.mp4
The source MP4 file can be downloaded from here.
Ready, set, go!
For this build, you really only need the following:
- Linux machine - but may work on other OSes.
- GCC Compiler - with C/C++ support, should be relatively recent.
- YASM x86/amd64 assembler
- Make
- BASH
- Python 2 or 3 (for custom build option script)
- Autoconf (maybe)
No external libraries are needed - if we need any libraries, we will be building them ourselves and explicitly avoiding any system libraries.
The modern day FFMPEG distribution includes the following libraries:
- libavcodec - codec handling
- libavdevice - audio/video drivers for recording, playback, capturing, etc. (webcam is a particular example)
- libavfilter - filters for your video and audio once it has been decoded
- libavformat - mux and demux handler (e.g. MP4 container file format)
- libavresample - audio resampling
- libavutil - utilities library for FFMPEG. Always built and required.
- libpostproc - ???
- libswresample - (better?) audio resampling
- libswscale - image/video scaling
When enabling/disabling features in FFMPEG, configuration for each of these libraries are updated in order for the correct features and tools to be built.
That said, there are some capabilities that are NOT included in FFMPEG. For our example, H.264 encoding is not handled at all in FFMPEG - instead, it is handled with another library called libx264, which provides optimized H.264 encoding for FFMPEG.
More likely than not, your encoding/decoding of a certain codec may very well require external libraries in order for them to work. For a rough idea of what's out there, run:
./configure -h | grep coding
Steps are long, but depending on your computer build times may not be too bad. Again, we are trying to build a very minimalist FFMPEG here!
-
Download and Install libx264
First things first, we need a library to handle encoding H.264. Note that if you are not doing anything special (e.g. you are just reading in H.264 data, and not doing any conversions or filtering/resizing), you do NOT need this library. Instead,
-vcodec copy
should work just fine for you!Download libx264 here. You'll want the latest git snapshot for the latest fixes.
Extract libx264 to a separate working directory, say
~/x264
. You should now have a folder resemblingx264-snapshot-YYYYMMDD-XXXX
. Enter that directory, and then type the following commands:mkdir build cd build ../configure --enable-static --disable-cli --disable-gpl --disable-opencl --disable-avs --disable-swscale --disable-lavf --disable-ffms --disable-gpac --disable-lsmash --disable-thread make -j4
NOTE: If you want multithreading support, you'll need to remove
--disable-thread
from the options, and then add in the following FFMPEG--extra-ldflags
:-lpthread
.If everything works well, you should now have a
libx264.a
in your folder. This will be your libx264 static library to link with from FFMPEG. For convenience, copy this out of your build folder into your main x264 folder, as well as the necessary headers. Assuming~/x264
is your main x264 folder:cp libx264.a x264_config.h ../*.h ~/x264
-
Download and Install FFMPEG
Now you can go and install FFMPEG! To make things a bit easier, there's a script I wrote that will help you disable unnecessary options that may accidentally cause the build to become larger (and more dependent on your system's libraries)!
Download FFMPEG from here, and then extract it to a separate working directory, e.g.
~/ffmpeg
.Then, download my script from my repo (here) and place it within your FFMPEG source directory, e.g.
~/ffmpeg/ffmpeg-3.2.4/
. Name the filenameget_autodetect_options.py
.This script simply groks the
../configure --help
output, and searches for options marked with "autodetect". It then outputs--disable-FEATURE
options to allow for easier disabling of all autodetected 3rd party library features, since they are not disabled with the given--disable-all
. (FFMPEG's configure script will still autodetect and add 3rd party libraries if they are not manually disabled by hand, even after a--disable-all
.)Once the script is saved in the source directory, run the following commands within said directory:
mkdir build cd build ../configure --disable-all `python ../get_autodetect_options.py --opts` --enable-ffmpeg --enable-small --enable-avcodec --enable-avformat --enable-avfilter --enable-swresample --enable-swscale --enable-decoder=h264 --enable-encoder=rawvideo,libx264 --enable-parser=h264 --enable-protocol=file --enable-demuxer=mov --enable-muxer=rawvideo,mp4 --enable-filter=scale --enable-gpl --enable-libx264 --extra-cflags="-I../x264" --extra-cxxflags="-I../x264" --extra-ldflags="-L../x264" make -j4
What do these options do? Breaking them down:
-
--disable-all
: disable building everything - libraries and programs included. -
python ../get_autodetect_options.py --opts
- script that automatically extracts the 3rd party autodetected library dependencies and creates--disable-FEATURE
options to disable them. More details above. -
--enable-ffmpeg
- enable the FFMPEG program. -
--enable-small
- optimize for final binary size (not speed) -
--enable-avcodec
- enable building libavcodec (codec support) -
--enable-avformat
- enable building libavformat (mux/demux support) -
--enable-avfilter
- enable building libavfilter (filter/resize support) -
--enable-swresample
- enable building libswresample (audio resampling support) -
--enable-swscale
- enable building libswscale (video/image resizing support) -
--enable-decoder=h264
- enable building libavcodec with H.264 decoding support -
--enable-encoder=rawvideo,libx264
- enable building libavcodec with raw video and H.264 (via libx264) encoding support -
--enable-parser=h264
- enable H.264 packet parsing - required for H.264 decoding -
--enable-protocol=file
- enable file read/write support -
--enable-demuxer=mov
- enable demuxing of MOV-type files (includes MP4) -
--enable-muxer=rawvideo,mp4
- enable muxing to raw video and MP4 -
--enable-filter=scale
- enable scaling (resizing) filter for videos in libavfilter -
--enable-gpl
- enable use of GPL licensed code in FFMPEG/libav*- Required for libx264 usage - otherwise
configure
will silently remove it from the available encoders.
- Required for libx264 usage - otherwise
-
--enable-libx264
- enable linking to libx264 library- Required for libx264 encoder - otherwise
configure
will silently remove it from the available encoders.
- Required for libx264 encoder - otherwise
-
--extra-cflags="-I~/x264" --extra-cxxflags="-I~/x264" --extra-ldflags="-L~/x264"
- addCFLAGS
,CXXFLAGS
, andLDFLAGS
compiler options to FFMPEG's build to ensure that bothconfigure
andmake
will find our previously build libx264 static library.- From above note: if you are using
pthreads
, make sure to append-lpthreads
to your LDFLAGS.
- From above note: if you are using
At this point, if you set everything up correctly, you should now have a tiny little build of FFMPEG!
-
-
Testing FFMPEG
Let's see if our FFMPEG has our requested features! Put the sample H.264/MP4 file in your build directory, and then run:
# Resize "The Simpsons Movie - Trailer.mp4" to half its original width and height, # then re-encode the result to H.264, copy the audio from the original file, and # store the result in Simpsons.mp4. ./ffmpeg -i The\ Simpsons\ Movie\ -\ Trailer.mp4 -vf scale=iw*.5:ih*.5 -vcodec h264 -acodec copy Simpsons.mp4
If all goes well, you should now have a smaller Simpsons.mp4 to watch on your favorite media player, with sound and everything!
The resulting build is nice and tiny, and has minimal dependencies:
albert@debian:~/ffmpeg/ffmpeg-3.2.4/build$ ls -lh ffmpeg
-rwxrwxrwx 1 albert root 3.1M Apr 5 00:57 ffmpeg
albert@debian:~/ffmpeg/ffmpeg-3.2.4/build$ ldd ffmpeg
linux-vdso.so.1 (0x00007ffd5df70000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4464ae2000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4464737000)
/lib64/ld-linux-x86-64.so.2 (0x00007f4464de3000)
albert@debian:~/ffmpeg/ffmpeg-3.2.4/build$ ./ffmpeg -i The\ Simpsons\ Movie\ -\ Trailer.mp4 -vf scale=iw*.5:ih*.5 -vcodec h264 -acodec copy Simpsons.mp4
ffmpeg version 3.2.4 Copyright (c) 2000-2017 the FFmpeg developers
built with gcc 4.9.2 (Debian 4.9.2-10)
configuration: --disable-all --disable-pthreads --disable-w32threads --disable-os2threads --disable-bzlib --disable-iconv --disable-libxcb --disable-libxcb-shm --disable-libxcb-xfixes --disable-libxcb-shape --disable-lzma --disable-schannel --disable-sdl2 --disable-securetransport --disable-xlib --disable-zlib --disable-audiotoolbox --disable-cuvid --disable-d3d11va --disable-dxva2 --disable-nvenc --disable-vaapi --disable-vda --disable-vdpau --disable-videotoolbox --enable-ffmpeg --enable-small --enable-avcodec --enable-avformat --enable-avfilter --enable-swresample --enable-swscale --enable-decoder=h264 --enable-encoder='rawvideo,libx264' --enable-parser=h264 --enable-protocol=file --enable-demuxer=mov --enable-muxer='rawvideo,mp4' --enable-filter=scale --enable-gpl --enable-libx264 --extra-cflags=-I../x264 --extra-cxxflags=-I../x264 --extra-ldflags=-L../x264
libavutil 55. 34.101 / 55. 34.101
libavcodec 57. 64.101 / 57. 64.101
libavformat 57. 56.101 / 57. 56.101
libavfilter 6. 65.100 / 6. 65.100
libswscale 4. 2.100 / 4. 2.100
libswresample 2. 3.100 / 2. 3.100
[h264 @ 0x2627840] Warning: not compiled with thread support, using thread emulation
Guessed Channel Layout for Input Stream #0.1 : stereo
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'The Simpsons Movie - Trailer.mp4':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isomavc1
creation_time : 2007-02-19T05:03:04.000000Z
Duration: 00:02:17.30, start: 0.000000, bitrate: 4283 kb/s
Stream #0:0(und): Video: h264 (avc1 / 0x31637661), yuv420p, 1280x544, 4221 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
Metadata:
creation_time : 2007-02-19T05:03:04.000000Z
handler_name : GPAC ISO Video Handler
Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, 64 kb/s (default)
Metadata:
creation_time : 2007-02-19T05:03:08.000000Z
handler_name : GPAC ISO Audio Handler
[h264 @ 0x2638200] Warning: not compiled with thread support, using thread emulation
[libx264 @ 0x26524a0] Warning: not compiled with thread support, using thread emulation
[libx264 @ 0x26524a0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX
[libx264 @ 0x26524a0] profile High, level 2.1
[libx264 @ 0x26524a0] 264 - core 148 - H.264/MPEG-4 AVC codec - Copyright 2003-2017 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=1 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=23 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
[mp4 @ 0x2638d40] track 1: codec frame size is not set
Output #0, mp4, to 'Simpsons.mp4':
Metadata:
major_brand : isom
minor_version : 1
compatible_brands: isomavc1
encoder : Lavf57.56.101
Stream #0:0(und): Video: h264 (libx264) ([33][0][0][0] / 0x0021), yuv420p, 640x272, q=-1--1, 23.98 fps, 24k tbn, 23.98 tbc (default)
Metadata:
creation_time : 2007-02-19T05:03:04.000000Z
handler_name : GPAC ISO Video Handler
encoder : Lavc57.64.101 libx264
Side data:
cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
Stream #0:1(und): Audio: aac ([64][0][0][0] / 0x0040), 48000 Hz, stereo, 64 kb/s (default)
Metadata:
creation_time : 2007-02-19T05:03:08.000000Z
handler_name : GPAC ISO Audio Handler
Stream mapping:
Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264))
Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame= 3289 fps= 64 q=28.0 Lsize= 11109kB time=00:02:17.25 bitrate= 663.0kbits/s dup=1 drop=0 speed=2.66x
video:9957kB audio:1075kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.702286%
[libx264 @ 0x26524a0] frame I:108 Avg QP:19.11 size: 24063
[libx264 @ 0x26524a0] frame P:1060 Avg QP:23.44 size: 4280
[libx264 @ 0x26524a0] frame B:2121 Avg QP:26.72 size: 1443
[libx264 @ 0x26524a0] consecutive B-frames: 10.9% 7.8% 5.1% 76.3%
[libx264 @ 0x26524a0] mb I I16..4: 16.9% 28.0% 55.0%
[libx264 @ 0x26524a0] mb P I16..4: 2.8% 7.6% 5.5% P16..4: 18.2% 9.2% 6.0% 0.0% 0.0% skip:50.8%
[libx264 @ 0x26524a0] mb B I16..4: 0.3% 0.7% 0.9% B16..8: 15.7% 4.9% 2.4% direct: 1.6% skip:73.5% L0:44.9% L1:45.7% BI: 9.4%
[libx264 @ 0x26524a0] 8x8 transform intra:39.4% inter:51.3%
[libx264 @ 0x26524a0] coded y,uvDC,uvAC intra: 54.8% 72.0% 53.1% inter: 8.5% 8.9% 3.3%
[libx264 @ 0x26524a0] i16 v,h,dc,p: 37% 37% 12% 15%
[libx264 @ 0x26524a0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 22% 22% 29% 4% 4% 4% 5% 4% 6%
[libx264 @ 0x26524a0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 26% 23% 17% 5% 5% 6% 6% 5% 6%
[libx264 @ 0x26524a0] i8c dc,h,v,p: 48% 26% 19% 6%
[libx264 @ 0x26524a0] Weighted P-Frames: Y:5.5% UV:4.2%
[libx264 @ 0x26524a0] ref P L0: 65.1% 11.6% 14.0% 9.0% 0.3%
[libx264 @ 0x26524a0] ref B L0: 85.2% 10.9% 3.9%
[libx264 @ 0x26524a0] ref B L1: 95.9% 4.1%
[libx264 @ 0x26524a0] kb/s:594.57
If you want to completely eliminate dependencies, add -static
to your configure
's LDFLAGS
. Note that your executable will grow by a few MBs, so beware!