基于Android O8.1的ffmpeg NDK 开发 - 1 - Hello World!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yanbixing123/article/details/81228400

很多做NDK开发的人(像我这样从底层转过来的 >_<!)对于Android app的开发不是很理解,而ffmpeg的NDK开发现在又离不开Andorid app。网上虽然教程虽多,但是很多过时或者与NDK开发需求的不契合,或者ffmpeg与Android Studio一直在更新,从而造成了很多困扰,故写此教程,希望用户可以直接从github上面拉下来就能编译使用,同时一步一步讲解编写过程,对其中的一些大坑进行规避。

Android Studio Version: 3.1.3

ffmpeg Version:4.0

Android Version:O8.1

一. 编译ffmpeg

1. 从https://www.ffmpeg.org/上面下载4.0版本的ffmpeg

2. 编译ffmpeg的环境为:

Ubuntu 16.04 LTS, 64位

ndk version:android-ndk-r14b (需要自己下载)

abi support: armeabi armeabi-v7a arm64-v8a

3. 编写编译脚本,对于不同arm结构的编译脚本不同,对于armeabi-v7a架构的编译脚本,内容如下:

(其中xxx为android-ndk-r14b 的路径)

#!/bin/bash
PLATFORM=/xxx/android-ndk-r14b/platforms/android-19/arch-arm/
TOOLCHAIN=/xxx/android-ndk-r14b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
PREFIX=./android/armeabi-v7a


function build_android
{
./configure \
--prefix=$PREFIX \
--target-os=android \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--arch=arm \
--sysroot=$PLATFORM \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--disable-shared \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-symver \
--enable-small \
--enable-gpl \
--enable-asm \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--enable-decoder=hevc_mediacodec \
--enable-decoder=mpeg4_mediacodec \
--enable-decoder=vp8_mediacodec \
--enable-decoder=vp9_mediacodec \
--enable-nonfree \
--enable-version3 \
--extra-cflags="-Os -fpic $ADDI_CFLAGS -I$PLATFORM/usr/include" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG


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 \
libavcodec/libavcodec.a \
libavfilter/libavfilter.a \
libswresample/libswresample.a \
libavformat/libavformat.a \
libavutil/libavutil.a \
libswscale/libswscale.a \
libavdevice/libavdevice.a \
libpostproc/libpostproc.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=arm
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -marm -march=$CPU "
ADDI_CFLAGS="-marm"
build_android

对于arm64-v8a架构的编译脚本如下:

#/bin/bash
PLATFORM=/xxx/android-ndk-r14b/platforms/android-21/arch-arm64/
TOOLCHAIN=/xxx/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64
PREFIX=./android/arm64-v8a


function build_android
{
./configure \
--prefix=$PREFIX \
--target-os=android \
--cross-prefix=$TOOLCHAIN/bin/aarch64-linux-android- \
--arch=aarch64 \
--sysroot=$PLATFORM \
--cc=$TOOLCHAIN/bin/aarch64-linux-android-gcc \
--nm=$TOOLCHAIN/bin/aarch64-linux-android-nm \
--disable-shared \
--enable-static \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-symver \
--enable-small \
--enable-gpl \
--enable-asm \
--enable-jni \
--enable-mediacodec \
--enable-decoder=h264_mediacodec \
--enable-hwaccel=h264_mediacodec \
--enable-decoder=hevc_mediacodec \
--enable-decoder=mpeg4_mediacodec \
--enable-decoder=vp8_mediacodec \
--enable-decoder=vp9_mediacodec \
--enable-nonfree \
--enable-version3 \
--extra-cflags="-Os -fpic $ADDI_CFLAGS -I$PLATFORM/usr/include" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG


make clean
make -j8
make install


$TOOLCHAIN/bin/aarch64-linux-android-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 \
libavcodec/libavcodec.a \
libavfilter/libavfilter.a \
libswresample/libswresample.a \
libavformat/libavformat.a \
libavutil/libavutil.a \
libswscale/libswscale.a \
libavdevice/libavdevice.a \
libpostproc/libpostproc.a \
-lc -lm -lz -ldl -llog --dynamic-linker=/system/bin/linker \
$TOOLCHAIN/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a
}

# arm64-v8a 
CPU=arm64-v8a
OPTIMIZE_CFLAGS="-mfloat-abi=softfp -mfpu=vfp -march=$CPU "
build_android

需要注意的是,这两个不同架构的编译脚本中,我都添加了h264_mediacodec硬件解码,这是以后需要讲解的一项内容。

而我这个版本也不是最全的版本,根据自己的需求来编译对应的ffmpeg,还是需要自己学习如何配置编译的,后面也会继续讲ffmpeg configure,暂时可以直接复制我的编译脚本来编译。

同时,这个脚本编译出来的是一个libffmpeg.so库,而不是分开的库,还是为了方便操作。

4. 直接执行./build_android_armeabi-v7a.sh,稍等片刻,就会在ffmpeg/android/armeabi-v7a/目录下生成libffmpeg.so 和 include目录,就是我们所需的lib库和头文件。

二. 将ffmpeg集成到Android Studio中

1. 新建工程,增加C++支持:

然后一路Next,最后可以添加上这两个选项:

点击Finish即可。

2. 这时候也就可以编译执行,放到板子上面执行了,可以看到屏幕上面出现了Hello C++的字符。

其实我们也没做什么,Android Studio就帮我们实现了,实在是太强大了。

3. 切换成Project视图,在main处右键,新建一个jniLibs目录,把刚编译好的lib库和头文件复制到该目录下。需要挑选对应abi的include目录,把里面所有的文件复制过来。(比如,对于armeabi-v7a架构,就把ffmpeg/android/armeabi-v7a/include目录的所有文件复制过去。)

4. 修改build.gradle文件,添加如下内容:

ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
        }

如图所示:

5. 修改CMakeLists.txt,把ffmpeg的lib库添加进去:


#CMake版本信息
cmake_minimum_required(VERSION 3.4.1)

#ffmpeg so文件路径
set(lib_src_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})

#配置加载native依赖
include_directories(${CMAKE_SOURCE_DIR}/src/main/jniLibs/include)

#动态方式加载ffmepg的so文件 第三方库加载方式
add_library(ffmpeg SHARED IMPORTED)

#引入libffmpeg.so文件
set_target_properties(ffmpeg PROPERTIES IMPORTED_LOCATION
${lib_src_DIR}/libffmpeg.so)

#CPP文件夹下待编译的c文件
add_library(native-lib SHARED ${CMAKE_SOURCE_DIR}/src/main/cpp/native-lib.cpp)

#C 日志 ndk官方库
find_library(log-lib log)

#静态库与动态库进行链接 相当于gcc命令行参数 -l。
target_link_libraries(native-lib
                      android
                      ffmpeg
                      ${log-lib})

6. 添加第一个测试代码:

在MainActivity中仿照stringFromJNI,添加一个native方法string2FromJNI,然后点击左侧的红色感叹号,点击Create function xxx 让AS自动生成C++的对应方法,如图所示:

然后就会在 native-lib.cpp文件中,生成如下的函数模板:

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_nxf31081_ffmpeg_1demo_11_MainActivity_string2FromJNI(JNIEnv *env,
                                                                      jobject instance) {

    // TODO


    return env->NewStringUTF(returnValue);
}

然后我们对其进行稍加修改,返回ffmpeg的编译信息,如下所示:

JNIEXPORT jstring JNICALL
Java_com_example_nxf31081_ffmpeg_1android_1demo_11_MainActivity_string2FromJNI(JNIEnv *env,
                                                                               jobject instance) {

    // TODO
    char info[10000] = {0};
    sprintf(info, "%s \n", avcodec_configuration());


    return env->NewStringUTF(info);
}

然后修改MainActivity.java,把string2FromJNI()函数添加进去,如下所示:

tv.setText(string2FromJNI());

最后,直接编译执行,就可以在APP上看到ffmpeg的编译信息了:

项目下载地址为:https://github.com/ZER0000/ffmpeg_android_demo.git

三. 总结

本篇文章实际的内容不多,主要是详细讲解了操作步骤,为以后的讲解做一个比较详细的铺垫,更主要的目的是为自己做一个记录,谁都知道我写博客的目的就是为了自己,哈哈~

猜你喜欢

转载自blog.csdn.net/yanbixing123/article/details/81228400