How to build FFmpeg for Android

Hello.
 
I have decided that I want to build FFmpeg libraries from source for Android. And, yes ... as you can imagine it's not that easy as it seems. But finally I did it! (at least I got no compilation errors) and I want to share my approach with you.
 
 

First things first

 
Get Linux and VirtualBox
I used Linux Mint 18.2 "Sonya" - Cinnamon (64-bit) on the latest version of VirtualBox for this purpose.
Then I've installed git on this Linux using terminal and this comand:

 
The Source Code
When you have git you can clone source code with this command:

 
Now you need Android NDK. In my case it's been android-ndk-r15c-linux-x86_64. Download it and uncompress the android-ndk-r15c-linux-x86_64.zip file.
 
 

Building

 
When you are building for Linux it's easy. Just type standard ./configure, make, make install. When building for Android you need provide additional settings for configure script. That's why it's good idea to create building script like this:
 
build_ffmpeg.sh

Keep in mind that you should set --sysroot path to sysroot folder inside android-ndk-r15c-linux-x86_64. In my case, the path is: /home/alien/Desktop/android-ndk-r15c/sysroot. Place this script in ffmpeg folder. Then add executable attribute to the file with chmod +x build_ffmpeg.sh. Finally run the script by typing: ./build_ffmpeg.sh.
 
Problem #1
After running the script I got this:
 
arm-linux-androideabi-gcc is unable to create an executable file.
C compiler test failed.

If you think configure made a mistake, make sure you are using the latest version from Git. If the latest version fails, report the problem to the ffmpeg-user@ffmpeg.org mailing list or IRC #ffmpeg on irc.freenode.net. Include the log file "ffbuild/config.log" produced by configure as this will help solve the problem.
 
Solution to that is to install gcc-arm-linux-androideabi by typing:

 
Problem #2
After rerunning the script I got this:
 
libavcodec/aaccoder.c: In function 'search_for_ms':
libavcodec/aaccoder.c:803:25: error: expected identifier or '(' before numeric constant
libavcodec/aaccoder.c:865:28: error: lvalue required as left operand of assignment
libavcodec/aaccoder.c:866:25: error: 'B1' undeclared (first use in this function)
libavcodec/aaccoder.c:866:25: note: each undeclared identifier is reported only once for each function it appears in
ffbuild/common.mak:60: recipe for target 'libavcodec/aaccoder.o' failed
make: *** [libavcodec/aaccoder.o] Error 1

 
And here is where crazy things are happening. The only important line is 803 in aaccoder.c. The rest of errors are consequences of that very first one. The line about which compiler complains is this:

Don't see anything wrong ? Me too! Because it's correct. The code here is ok. Problem is in file /usr/arm-linux-androideabi/include/asm/termbits.h. It contains ugly #define in line 116:

Now, if we rewrite line from aaccoder.c according to this #define we will get this:

Clearly that's wrong. That's why compiler expected identifier (but got number 0000000). This happens through sequence of including header files:
 
ffmpeg/libavcodec/aaccoder.c file includes:
libavcodec/avcodec.h file includes:
libavutil/samplefmt.h file includes:
libavutil/avutil.h file includes:
libavutil/common.h file includes:
libavutil/internal.h file includes:
libavutil/timer.h file includes:
/usr/arm-linux-androideabi/include/sys/ioctl.h file includes:
/usr/arm-linux-androideabi/include/asm/termbits.h
 
I don't know how to solve it "properly", so I just did very simple fix. I have replaced every occurance of B0 by b0 in aaccoder.c and typed make. It helped.
 
Problem #3
But that's not all. Same problem causes this error:
 
libavcodec/hevc_mvs.c: In function 'derive_spatial_merge_candidates':
libavcodec/hevc_mvs.c:368:23: error: 'y0000000' undeclared (first use in this function)
libavcodec/hevc_mvs.c:368:23: note: each undeclared identifier is reported only once for each function it appears in
libavcodec/hevc_mvs.c:368:23: error: 'x0000000' undeclared (first use in this function)
libavcodec/hevc_mvs.c: In function 'ff_hevc_luma_mv_mvp_mode':
libavcodec/hevc_mvs.c:683:24: error: 'y0000000' undeclared (first use in this function)
libavcodec/hevc_mvs.c:683:24: error: 'x0000000' undeclared (first use in this function)
ffbuild/common.mak:60: recipe for target 'libavcodec/hevc_mvs.o' failed

 
Solution here is the same. Just replace B0 by b0 in hevc_mvs.c and type make.
 
Problem #4
Same story here:
 
libavcodec/opus_pvq.c: In function 'quant_band_template':
libavcodec/opus_pvq.c:499:9: error: expected identifier or '(' before numeric constant
libavcodec/opus_pvq.c:560:12: error: lvalue required as left operand of assignment
ffbuild/common.mak:60: recipe for target 'libavcodec/opus_pvq.o' failed
make: *** [libavcodec/opus_pvq.o] Error 1

 
Replace B0 by b0 in opus_pvq.c and type make.
 
Problem #5
WTF ?! stdio.h ???
 
doc/print_options.c:26:19: fatal error: stdio.h: No such file or directory
compilation terminated.
ffbuild/common.mak:152: recipe for target 'doc/print_options.o' failed
make: *** [doc/print_options.o] Error 1

 
Ooops. It seems that I have forgot about build essentials for Linux. To install this type:

 
And, of course, once again make.
 

It works!

 
Or, at least it seems so. There is no more errors and in subfolders of ffmpeg you can find *.a files, which are static libraries like libavcodec.a.
 
If you found the same errors I hope that this post gave you at least a hint how to solve it or where to look for the problem.