编译用于Android的FFmpeg&x264

本文介绍了在编译用于Android端的FFmpeg与x264库

本次编译环境:MacOs操作系统,FFmpeg-3.3.4,x264,NDK:r15c

0x00 资源准备

下载Android NDK : Google中国开发者网站
terminal
mkdir ~/FFmpeg
cd ~/FFmpeg
git clone http://git.videolan.org/git/x264.git
git clone https://git.ffmpeg.org/ffmpeg.git

0x01 配置NDK环境变量

解压下载好的ndk.tar.gz至~/
terminal
subl ~/.bash_profile

NDK_HOME=~/android-ndk-r15c
export NDK_HOME
export PATH=${PATH}:$NDK_HOME/toolchains:$NDK_HOME
export PREBUILT=$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt
export PLATFORM=$NDK_HOME/platforms/android-14/arch-arm
export TOOLCHAIN=$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
# cpu 架构平台,若要编译 x86 则指定 x86
export CPU=armv7-a

0x02 编译x264

编写脚本build_x264.sh
注:编者系统重定向 subl -> 打开sublime text
terminal
subl ~/FFmpeg/build_x264.sh

cd x264

export NDK=$NDK_HOME
#编译生成库路径
export PREFIX=../libx264
export SYSROOT=$TOOLCHAINS/arm/sysroot 

./configure \
    --prefix=$PREFIX \
    --enable-static \
    --enable-shared \
    --enable-pic \
    --disable-asm \
    --disable-cli \
    --host=arm-linux-androideabi \
    --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
    --sysroot=$PLATFORM \
    --disable-avs \
    --disable-swscale \
    --disable-lavf \
    --disable-ffms \
    --disable-gpac \
    --disable-lsmash 

make -j8
make install

cd ..

terminal
chmod +x ~/FFmpeg/build_x264.sh

sh ~/FFmpeg/build_x264.sh

该步骤结束后在FFmpeg文件夹下会生成一个libx264文件夹

0x03 编译FFmpeg

terminal
subl ~/FFmpeg/FFmpeg-${version}/build.sh

#!/bin/bash
export TMPDIR=/Users/${uesr}/FFmpeg/ffmpeg-${version} #指向FFmpeg根目录

function build_one
{

EXTRA_CFLAGS="-I./libx264/include"
EXTRA_LDFLAGS="-L./libx264/lib"

./configure \
    --prefix=$PREFIX \
    --target-os=android \
    --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
    --disable-stripping \
    --disable-asm \
    --disable-doc \
    --arch=arm \
    --sysroot=$PLATFORM \
    --extra-cflags="-I$PLATFORM/usr/include" \
    --cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
    --nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
    --disable-shared \
    --enable-runtime-cpudetect \
    --enable-gpl \
    --enable-small \
    --enable-cross-compile \
    --enable-static \
    --enable-version3 \
    --disable-vda \
    --disable-iconv \
    --disable-encoders \
    --enable-libx264 \
    --enable-encoder=libx264 \
    --disable-muxers \
    --enable-muxer=mov \
    --enable-muxer=ipod \
    --enable-muxer=psp \
    --enable-muxer=mp4 \
    --enable-muxer=avi \
    --disable-decoders \
    --enable-decoder=aac \
    --enable-decoder=aac_latm \
    --enable-decoder=h264 \
    --enable-decoder=mpeg4 \
    --disable-demuxers \
    --enable-demuxer=h264 \
    --enable-demuxer=mov \
    --disable-parsers \
    --enable-parser=aac \
    --enable-parser=ac3 \
    --enable-parser=h264 \
    --disable-protocols \
    --enable-protocol=file \
    --enable-protocol=rtmp \
    --disable-bsfs \
    --enable-bsf=aac_adtstoasc \
    --enable-bsf=h264_mp4toannexb \
    --disable-indevs \
    --enable-zlib \
    --disable-outdevs \
    --disable-ffprobe \
    --disable-ffplay \
    --disable-ffmpeg \
    --disable-postproc \
    --disable-avdevice \
    --disable-symver \
    --disable-ffserver \
    --disable-debug \
    --extra-cflags=$EXTRA_CFLAGS \
    --extra-ldflags=$EXTRA_LDFLAGS    
$ADDITIONAL_CONFIGURE_FLAG
sed -i '' 's/HAVE_LRINT 0/HAVE_LRINT 1/g' config.h
sed -i '' 's/HAVE_LRINTF 0/HAVE_LRINTF 1/g' config.h
sed -i '' 's/HAVE_ROUND 0/HAVE_ROUND 1/g' config.h
sed -i '' 's/HAVE_ROUNDF 0/HAVE_ROUNDF 1/g' config.h
sed -i '' 's/HAVE_TRUNC 0/HAVE_TRUNC 1/g' config.h
sed -i '' 's/HAVE_TRUNCF 0/HAVE_TRUNCF 1/g' config.h
sed -i '' 's/HAVE_CBRT 0/HAVE_CBRT 1/g' config.h
sed -i '' 's/HAVE_RINT 0/HAVE_RINT 1/g' config.h
make clean
make -j8
make install
$TOOLCHAIN/bin/arm-linux-androideabi-ld \
-rpath-link=$PLATFORM/usr/lib \
-L$PLATFORM/usr/lib \
-L$PREFIX/lib \
-soname libffmpeg.so -shared -nostdlib -Bsymbolic --whole-archive --no-undefined -o \
$PREFIX/libffmpeg.so \
    libx264/lib/libx264.a \
    libavcodec/libavcodec.a \
    libavfilter/libavfilter.a \
    libswresample/libswresample.a \
    libavformat/libavformat.a \
    libavutil/libavutil.a \
    libswscale/libswscale.a \
    -lc -lm -lz -ldl -llog --dynamic-linker=/system/bin/linker \
    $TOOLCHAIN/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a
}
# arm v7vfp
CPU=armv7-a
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
PREFIX=./android/$CPU-vfp
ADDITIONAL_CONFIGURE_FLAG=
build_one

terminal
chmod +x ~/FFmpeg/build.sh
sh ~/FFmpeg/build.sh

0x04 Android工程

创建一个Android工程
在app/src/main下创建文件夹jni
复制文件 ~/FFmpeg下的android/arm…/libffmpeg.so到jni/
复制文件 ffmpeg.c ffmpeg.h ffmpeg_filter.c cmdutils.c cmdutils.h cmdutils_common_opt.c ffmpeg_opt.c 到jni/
修改文件:ffmpeg.c

int main(int argc,char **argv) 
//改变为
int run(int argc,char **argv)

//在函数 ffmpeg_cleanup 的最后添加
ffmpeg_exited = 1;
nb_filtergraphs = 0;
nb_output_files = 0;
nb_output_streams = 0;
nb_input_files = 0;
nb_input_streams = 0;

修改文件:ffmpeg.h

//在定义函数的末添加
int run(int argc,char **argv);

修改文件cmdutils.c

//函数exit_program
void exit_program(int ret){
    if(program_exit){
        program_exit(ret)
    }
    exit(ret);
}
//改变为
void exit_program(int ret){
    if(program_exit){
        program_exit(ret)
    }
}

创建一个调用类如:FFmpegUtil.java
并在类中声明原生方法

    private static native int run(String[] recommend);

此处打开AndroidStudio中的终端
terminal
cd app/src/main/java
// javah ${包名}.FFmpegUtil

如:javah com.exmaple.ffmpegsimple.FFmpegUtil
会在app/src/main/java目录下生成c头文件,将其移动到jni/
创建文件${刚才创建的头文件}.c
编写该文件

#include "com.example.ffmpegsimple.h"
#include "ffmpeg.h"
#include 
/*
 * Class:     com_example_ffmpegsimple_FFmpegUtil
 * Method:    run
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_example_ffmpegsimple_FFmpegUtil_run(JNIEnv *env,
        jclass obj, jobjectArray commands) {

    int argc = (*env)->GetArrayLength(env, commands);
    char *argv[argc];

    int i;
    for (i = 0; i < argc; i++) {
        jstring js = (jstring) (*env)->GetObjectArrayElement(env, commands, i);
        argv[i] = (char*) (*env)->GetStringUTFChars(env, js, 0);
    }
    return run(argc, argv);
}

terminal
cd app/src/main/jni
ndk-build
等待执行完成
会在app/src/main下生成两个文件夹
编写app的build.gradle

sourceSets{
        main{
            jniLibs.srcDir(['src/main/libs'])
        }
    }

0x05 最后说两句

在sh build_x264.sh、sh build.sh、ndk-build三步中,一旦出现error代表着编译失败,应谨慎分析原因并排查,祝大家使用愉快

你可能感兴趣的:(Android)