NDK21编译ffmpeg5.0.1 | FFmpeg音视频开发14

对于想要学习音视频开发的android开发者来说,使用NDK对FFmpeg进行交叉编译是一道必须迈过去的坎,网上关于使用NDK对FFmpeg进行交叉编译的教程有很多, 但是不经修改能顺利编译通过的比较少。

其实参照网上的教程不能编译通过很多时候不是人家的教程写的有问题,很多时候更多的是因为环境的差异导致了编译出错,而对于一个入门者来说编译报错了自己却不知道怎么改。

NDK编译FFmpeg

今天我们来使用NDK对FFmpeg进行交叉编译并集成到Android Studio中去。

笔者的开发环境是:

  • 电脑系统  Mac OS
  • NDK 21.1.6352462
  • FFmpeg源码5.0.1

1、编写编译脚本

首先我们需要下载好对应版本的NDK和FFmpeg源码,然后我们新建一个编译脚本文件build_ffmpeg_android.sh:

#清空上次的编译
make clean
#配置你的NDK路径
export NDK=/Users/flyer/Documents/Android/sdk/ndk/21.1.6352462
TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/darwin-x86_64

function build_android
{
./configure 
--prefix=$PREFIX 
--disable-postproc 
--disable-debug 
--disable-doc 
--disable-ffmpeg 
--disable-ffplay 
--disable-ffprobe 
--disable-symver 
--disable-doc 
--disable-avdevice 
--disable-static 
--enable-shared 
--enable-neon 
--enable-hwaccels 
--enable-jni 
--enable-mediacodec 
--enable-decoder=h264_mediacodec 
--enable-decoder=hevc_mediacodec 
--enable-decoder=mpeg4_mediacodec 
--enable-hwaccel=h264_mediacodec 
--cross-prefix=$CROSS_PREFIX 
--target-os=android 
--arch=$ARCH 
--cpu=$CPU 
--cc=$CC 
--cxx=$CXX 
--enable-cross-compile 
--sysroot=$SYSROOT 
--extra-cflags="-Os -fpic $OPTIMIZE_CFLAGS" 
--extra-ldflags="$ADDI_LDFLAGS"

make clean
make -j16
make install

echo "============================build android ffmpeg end=========================="

}

#arm64-v8a 参数配置
ARCH=arm64
CPU=armv8-a
API=21
CC=$TOOLCHAIN/bin/aarch64-linux-android$API-clang
CXX=$TOOLCHAIN/bin/aarch64-linux-android$API-clang++
SYSROOT=$NDK/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
CROSS_PREFIX=$TOOLCHAIN/bin/aarch64-linux-android-
PREFIX=$(pwd)/android/$CPU
OPTIMIZE_CFLAGS="-march=$CPU"

# 函数调用
build_android

注意脚本文件中的注释,要把NDK的路径改为自己的NDK路径,尽可能使用与笔者相同版本的NDK,比如使用NDKr23的版本就可能编译不通过,貌似是因为NDKr23的改掉导致了toolchains下一些列工具找不到了。

2、赋予脚本运行权限

将脚本文件拷贝到下载好的FFmpeg源码目录之下,然后使用命令行chmod +x build_ffmpeg_android.sh赋予脚本可执行权限。

3、运行编译脚本

运行命令行./build_ffmpeg_android.sh即可进行编译,如果编译成功可以在FFmpeg的源码目录下的android文件夹内找到对于的动态库和FFmpeg相关的头文件。因为上述脚本通过PREFIX=$(pwd)/android/$CPU配置了编译的输出路径。

注意上述的脚本只编译了arm64-v8a架构的动态库,童鞋们可以尝试下如何编译其他架构的动态库。

集成到Android Studio中

1、 新建Android Studio Native工程

交叉编译成功后,我们通过Android Studio新建一个Native工程,不同的AS版本文件路径可能不一样,比如笔者的项目路径是这样的:

2、拷贝动态库和头文件到工程

然后我们在工程的libs目录下新建一个arm64-v8a目录,然后将我们编译出来的动态库文件拷贝到新建的arm64-v8a目录中去;

然后我们在cpp目录下新建一个ffmpeg_include目录用于存放FFmpeg的头文件,创建好之后我们将交叉编译目录include下头文件拷贝到新建的ffmpeg_include中去。

3、修改CMakeLists.txt

下面修改以下CMakeLists.txt配置文件,主要是配置FFmpeg动态库的搜索路径和头文件的搜索路径:


cmake_minimum_required(VERSION 3.10.2)

# 引入FFmpeg的头文件
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg_include)

# 动态链接库或静态链接库的搜索路径
link_directories(${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI})

#找到包含所有的cpp文件
file(GLOB allCpp src/main/cpp/*.*)

add_library(
        # 生成的库的名字
        flyffmpeg-lib

        # 动态库
        SHARED

        # 源文件
        ${allCpp} )


target_link_libraries( #目标库
        flyffmpeg-lib

        # 把ffmpeg的动态库依赖进来
        avformat
        avcodec
        avutil
        avfilter
        swscale
        swresample

        # NDK中的log库
        log )

注意上面的文件修改了最终生成的动态库的名字flyffmpeg-lib,所以在使用的时候需要注意一下加载正确的动态库。

4、修改build.gradle

这一步的目的主要是为了将libs目录下so文件打包进APK,我们将app目录下build.gradle修改成:

plugins {
    id 'com.android.application'
}

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.fly.ffmpeg.practice"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags '-std=c++11'
            }

            // abiFilters
            ndk {
                abiFilters "arm64-v8a"
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    externalNativeBuild {
        cmake {
            // 指定CMakeLists.txt路径
            path file('CMakeLists.txt')
            version '3.10.2'
        }
    }
    buildFeatures {
        viewBinding true
    }

    sourceSets {
        main {
            //将依赖库打进apk,否则可能出现找不到库
            jniLibs.srcDirs = ['libs']
        }
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

注意注释部分即可。

5、修改native-lib.cpp

最后我们修改一下native-lib.cpp,在这里返回FFmpeg的配置:

#include <jni.h>
#include <string>

extern "C"{
#include <libavcodec/avcodec.h>
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_fly_ffmpeg_practice_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    // 返回ffmpeg配置信息
    return env->NewStringUTF(avcodec_configuration());
}

运行如果可以能看到正确的配置信息则说明集成成功。图片

关注我,一起进步,人生不止coding!!!

思想觉悟
思想觉悟

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/yinshipin/7072.html

(0)

相关推荐

发表回复

登录后才能评论