Android FFmpeg集成

本文详细介绍了如何在Android项目中集成FFmpeg库,包括新建C++项目,引入so库,配置app/build.gradle,编写CMakeLists.txt以链接so库,以及在native-lib.cpp中添加测试代码并加载到应用中。通过这些步骤,开发者可以成功地在Android应用中使用FFmpeg进行音视频处理。

FFmpeg生成Android so库

        上篇介绍了如何生成so库,这次介绍如何集成。

一、新建一个Android C++项目

这时候主工程目录下会有cpp文件夹,包含如下两个文件:

  • CMakeLists.txt:cmake脚本配置文件,cmake会根据该脚本文件中的指令去编译相关的C/C++源文件,并将编译后产物生成共享库或静态块,然后Gradle将其打包到APK中。
  • native-lib.cpp:用来写C相关的代码。

二、引入so库

  • app/src/main/cpp:将生成的include整体复制进去
  • src/main/jniLibs/arm64-v8a:创建文件路径,将生成的lib中的so库复制进去

三、配置app/build.gradle 

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"
    defaultConfig {
        applicationId "com.simple.ffmpeg"
        minSdkVersion 19
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        //自动生成
        externalNativeBuild {
            cmake {
                cppFlags ''
            }
        }
        //1、手动添加
        ndk {
            abiFilters "arm64-v8a"
            //abiFilters "armeabi-v7a"
        }
        //2、手动添加
        packagingOptions {
            pickFirst 'lib/arm64-v8a/libswscale.so'
            pickFirst 'lib/arm64-v8a/libavcodec.so'
            pickFirst 'lib/lib/arm64-v8a/libavutil.so'
            pickFirst 'lib/arm64-v8a/libavutil.so'
            pickFirst 'lib/arm64-v8a/libavformat.so'
            pickFirst 'lib/arm64-v8a/libavfilter.so'
            pickFirst 'lib/arm64-v8a/libswresample.so'
            pickFirst 'lib/arm64-v8a/libavdevice.so'
        }
    }
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    //自动生成
    externalNativeBuild {
        cmake {
            path file('src/main/cpp/CMakeLists.txt')
            version '3.10.2'
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {

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

第一个手动添加如果没有会报:

Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
  Error while executing process ../Android/sdk/cmake/3.10.2.4988404/bin/ninja with arguments {-C /Users/kewang/code/code_test/Ffmpeg/app/.cxx/cmake/debug/armeabi-v7a native-lib}
  ninja: Entering directory `/Users/kewang/code/code_test/Ffmpeg/app/.cxx/cmake/debug/armeabi-v7a'

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

第二个手动添加如果没有会报:

Execution failed for task ':app:mergeDebugNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
   > More than one file was found with OS independent path 'lib/arm64-v8a/libswscale.so'. If you are using jniLibs and CMake IMPORTED targets, see https://developer.android.com/studio/preview/features#automatic_packaging_of_prebuilt_dependencies_used_by_cmake

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

四、CMakeLists.txt链接so库

        需要在CMakeLists.txt中把相关的 so 添加和链接起来,要不然没法使用。

cmake_minimum_required(VERSION 3.10.2)

# 支持gnu++11
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

# 1. 定义so库和头文件所在目录,方面后面使用
set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
set(ffmpeg_head_dir ${CMAKE_SOURCE_DIR})

# 2. 添加头文件目录
include_directories(${ffmpeg_head_dir}/include)

# 3. 添加ffmpeg相关的so库
add_library( avutil
        SHARED
        IMPORTED )
set_target_properties( avutil
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavutil.so )

add_library( swresample
        SHARED
        IMPORTED )
set_target_properties( swresample
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libswresample.so )

add_library( avcodec
        SHARED
        IMPORTED )
set_target_properties( avcodec
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavcodec.so )

add_library( avfilter
        SHARED
        IMPORTED)
set_target_properties( avfilter
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavfilter.so )

add_library( swscale
        SHARED
        IMPORTED)
set_target_properties( swscale
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libswscale.so )

add_library( avformat
        SHARED
        IMPORTED)
set_target_properties( avformat
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavformat.so )

add_library( avdevice
        SHARED
        IMPORTED)
set_target_properties( avdevice
        PROPERTIES IMPORTED_LOCATION
        ${ffmpeg_lib_dir}/libavdevice.so )

# 查找代码中使用到的系统库
find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log )

# 配置目标so库编译信息
add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        native-lib.cpp
        )

# 指定编译目标库时,cmake要链接的库
target_link_libraries(

        # 指定目标库,native-lib 是在上面 add_library 中配置的目标库
        native-lib

        # 4. 连接 FFmpeg 相关的库
        avutil
        swresample
        avcodec
        avfilter
        swscale
        avformat
        avdevice

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib} )

五、native-lib.cpp添加测试代码

        完成好CMakeLists之后需要测试下到底成功没,这块打印输出FFmpeg的信息。

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

extern "C" JNIEXPORT jstring JNICALL
Java_com_simple_ffmpeg_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavcodec/jni.h>

JNIEXPORT jstring JNICALL
Java_com_simple_ffmpeg_MainActivity_ffmpegInfo(JNIEnv *env, jobject  /* this */) {

    char info[40000] = {0};
    AVCodec *c_temp = av_codec_next(NULL);
    while (c_temp != NULL) {
        if (c_temp->decode != NULL) {
            sprintf(info, "%sdecode:", info);
        } else {
            sprintf(info, "%sencode:", info);
        }
        switch (c_temp->type) {
            case AVMEDIA_TYPE_VIDEO:
                sprintf(info, "%s(video):", info);
                break;
            case AVMEDIA_TYPE_AUDIO:
                sprintf(info, "%s(audio):", info);
                break;
            default:
                sprintf(info, "%s(other):", info);
                break;
        }
        sprintf(info, "%s[%s]\n", info, c_temp->name);
        c_temp = c_temp->next;
    }

    return env->NewStringUTF(info);
}
}

注意这个函数名称:Java_com_simple_ffmpeg_MainActivity_stringFromJNI,Java_包名的下划线格式_Java需要调用的方法名称。

六、加载native-lib.cpp测试代码

public class MainActivity extends AppCompatActivity {

    // 加载so库
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.sample_text);
        //调用JNI方法
        tv.setText(ffmpegInfo());
    }

    /**
     * A native method that is implemented by the 'ffmpeg' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public native String ffmpegInfo();
}

结果如下:

<think>我们正在处理一个关于在Android项目中集成FFmpeg的问题。根据提供的引用,我们可以总结出以下步骤: 1. **核心思路**:由于FFmpeg是用C语言编写的,我们需要将其编译为Android可用的动态链接库(.so文件),然后通过JNI(Java Native Interface)调用FFmpeg的功能[^1]。 2. **获取预编译的FFmpeg库**:我们可以从一些开源项目中获取预编译好的FFmpeg库,例如引用[2]中提到的项目:https://github.com/WritingMinds/ffmpeg-android。在该项目的releases页面(https://github.com/WritingMinds/ffmpeg-android/releases)可以直接下载预编译的包[^2]。 3. **集成Android Studio项目**: - 将下载的预编译库(包含不同CPU架构的.so文件)放入项目的`jniLibs`目录(通常在`src/main/jniLibs`下,按架构分目录存放)。 - 配置CMakeLists.txt或Android.mk(如果使用ndk-build)来链接这些库。 - 在native代码中调用FFmpeg函数,例如在`native-lib.cpp`中添加测试代码:`avutil_version()`[^3]。 4. **测试集成**:在JNI方法中调用FFmpeg函数,例如获取版本号,然后在Java层调用该native方法并输出,以验证是否集成成功。 5. **注意许可证**:FFmpeg采用LGPL或GPL许可证,使用时需遵守相应的许可证要求[^4]。 下面我们给出详细步骤: ### 步骤1:下载预编译的FFmpeg库 从[WritingMinds/ffmpeg-android](https://github.com/WritingMinds/ffmpeg-android/releases)下载预编译的FFmpeg库(例如:ffmpeg-android-armeabi-v7a.tar.gz等)。解压后,你会得到不同架构(如armeabi-v7a, arm64-v8a, x86等)的文件夹,每个文件夹里包含`include`(头文件)和`lib`(.so文件)两个子目录。 ### 步骤2:将库文件放入Android项目 在项目的`src/main`目录下创建`jniLibs`文件夹(如果不存在),然后将各架构的`lib`目录下的所有.so文件复制到`jniLibs`对应的架构目录中。例如: - `src/main/jniLibs/armeabi-v7a/*.so` - `src/main/jniLibs/arm64-v8a/*.so` - 等等 同时,将`include`文件夹(包含FFmpeg的头文件)复制到`src/main/cpp`目录下(或其他目录,但需要配置CMakeLists.txt正确包含)。 ### 步骤3:配置CMakeLists.txt 在项目的`app`模块中,配置CMakeLists.txt文件以链接FFmpeg库。以下是一个示例: ```cmake cmake_minimum_required(VERSION 3.4.1) # 设置FFmpeg头文件路径 include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include) # 设置FFmpeg库路径 set(ffmpeg_lib_dir ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}) # 添加FFmpeg库(这里以avcodec、avfilter、avformat、avutil、swresample、swscale为例) add_library(avcodec SHARED IMPORTED) set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavcodec.so) add_library(avfilter SHARED IMPORTED) set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavfilter.so) add_library(avformat SHARED IMPORTED) set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavformat.so) add_library(avutil SHARED IMPORTED) set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libavutil.so) add_library(swresample SHARED IMPORTED) set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libswresample.so) add_library(swscale SHARED IMPORTED) set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${ffmpeg_lib_dir}/libswscale.so) # 添加你自己的native库 add_library(native-lib SHARED src/main/cpp/native-lib.cpp) # 链接FFmpeg库到你的native库 target_link_libraries(native-lib avcodec avfilter avformat avutil swresample swscale log) ``` ### 步骤4:在native代码中调用FFmpeg 在`native-lib.cpp`中,包含FFmpeg头文件,并调用一个函数(例如获取avutil版本): ```cpp #include <jni.h> #include <string> extern "C" { #include <libavutil/avutil.h> } extern "C" JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_stringFromJNI( JNIEnv* env, jobject /* this */) { std::string hello = "Hello from C++ and FFmpeg avutil version: "; hello += std::to_string(avutil_version()); return env->NewStringUTF(hello.c_str()); } ``` ### 步骤5:在Java层调用native方法 在MainActivity中: ```java public class MainActivity extends AppCompatActivity { static { System.loadLibrary("native-lib"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv = findViewById(R.id.sample_text); tv.setText(stringFromJNI()); } public native String stringFromJNI(); } ``` ### 步骤6:配置build.gradle 确保在`build.gradle`中配置了NDK和CMake,并指定了支持的ABI(与下载的预编译库的架构一致): ```groovy android { ... defaultConfig { ... ndk { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } externalNativeBuild { cmake { path "CMakeLists.txt" } } } ``` ### 注意事项 - 如果使用预编译库,请确保库的版本与你的项目兼容。 - 如果遇到问题,可以尝试自己编译FFmpeg,以获得更好的控制和兼容性。 通过以上步骤,你应该可以在Android项目中成功集成FFmpeg并调用其功能。 ### 相关问题 1. 如何自己编译FFmpeg以用于Android平台? 2. 在Android中使用FFmpeg进行视频转码的基本步骤是什么? 3. 如何解决在集成FFmpeg时遇到的常见链接错误?</think>### Android项目集成FFmpeg步骤 #### 1. **获取预编译的FFmpeg库** - 从GitHub下载预编译包(推荐): - 访问 [WritingMinds/ffmpeg-android](https://github.com/WritingMinds/ffmpeg-android/releases) - 下载对应架构的压缩包(如 `ffmpeg-android-armeabi-v7a.tar.gz`)[^2] - 或自行编译(复杂,需配置NDK交叉编译环境) #### 2. **添加库文件到项目** ```markdown app/ └── src/ └── main/ ├── jniLibs/ # 新建此目录 │ ├── armeabi-v7a/ # 放入对应.so文件 │ ├── arm64-v8a/ │ └── x86/ └── cpp/ └── include/ # 放入FFmpeg头文件 ``` #### 3. **配置CMakeLists.txt** ```cmake cmake_minimum_required(VERSION 3.4.1) # 添加头文件路径 include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include) # 链接FFmpeg库 add_library(lib_ffmpeg SHARED IMPORTED) set_target_properties(lib_ffmpeg PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec.so) # 其他库需重复添加 add_library(native-lib SHARED native-lib.cpp) target_link_libraries(native-lib lib_ffmpeg log) ``` #### 4. **配置build.gradle** ```groovy android { defaultConfig { externalNativeBuild { cmake { cppFlags "-std=c++11" abiFilters 'armeabi-v7a', 'arm64-v8a' # 与下载的库架构匹配 } } } externalNativeBuild { cmake { path "CMakeLists.txt" } } } ``` #### 5. **JNI接口调用测试** ```cpp #include <jni.h> #include <string> extern "C" { #include <libavutil/avutil.h> // FFmpeg头文件 } extern "C" JNIEXPORT jstring JNICALL Java_com_example_app_MainActivity_getFFmpegVersion(JNIEnv* env, jobject) { return env->NewStringUTF(av_version_info()); // 调用FFmpeg函数 } ``` #### 6. **Java层调用** ```java public class MainActivity extends AppCompatActivity { static { System.loadLibrary("native-lib"); // 加载native库 } public native String getFFmpegVersion(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d("FFmpegVersion", getFFmpegVersion()); // 打印版本信息 } } ``` #### 关键注意事项 1. **ABI兼容性**:确保`.so`文件架构与项目匹配(如arm64-v8a适配新设备) 2. **许可证问题**:FFmpeg使用LGPL/GPL,需遵守开源协议[^4] 3. **版本冲突**:避免同时引入多个FFmpeg版本 4. **压缩优化**:使用`android:extractNativeLibs="true"`减小APK体积 > 测试成功标志:日志输出类似`"n4.4.1"`的版本信息[^3] ### 备选方案:使用封装库 - **[mobile-ffmpeg](https://github.com/tanersener/mobile-ffmpeg)**:提供更简单的集成方式 ```gradle dependencies { implementation 'com.arthenica:mobile-ffmpeg-full:4.4.LTS' } ``` - 直接Java调用: ```java long rc = FFmpeg.execute("-i input.mp4 output.avi"); ``` ### 常见问题解决 - **`UnsatisfiedLinkError`**:检查`.so`文件路径和ABI配置 - **头文件缺失**:确认`include`目录包含所有FFmpeg头文件 - **方法未定义**:确保CMake链接了所有必需的库(`avcodec`, `avformat`等) > 提示:预编译库更新较慢,如需最新特性需自行编译FFmpeg[^1] --- ### 相关问题 1. 如何解决Android集成FFmpeg时的`java.lang.UnsatisfiedLinkError`错误? 2. 使用FFmpegAndroid上进行视频转码需要哪些核心API? 3. 如何通过CMake同时集成多个原生库(如OpenCV+FFmpeg)? 4. FFmpeg的LGPL和GPL许可证在商业应用中有什么区别? 5. 如何优化FFmpegAndroid上的性能以减少CPU占用?
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值