NDK开发FFmpeg之HelloWorld

一、新建Native C++ 工程

首先,不同的工具版本在开发过程中会存在一定的问题,以下为本篇文章的工具版本:

  • AndroidStudio版本:3.3
  • Gradle版本:gradle-4.10.1-all
  • NDK版本:android-ndk-r16b-windows-x86_64
  • FFmpeg库版本:4.0(可参考文章"Linux环境下用NDK编译FFmpeg")

版本确定后,我们在AndroidStudio中,新建Native C++工程,项目名为FFmpegWorld,包名为com.demo.ffmpegworld,新建成功后,直接运行工程,如在首页出现Hello from C++字样,表示NDK开发的准备工作完成。如遇到无法运行等问题,可自行百度解决,这里不再赘述。

题外话:随着AS不断的更新,对NDK的支持越来越友好,并且伴随着CMake的编译方法,旧有的android.mk方法已经显得过于繁琐(可以参考:Android NDK开发之HelloWorld)。

二、导入FFmpeg库

  1. 将项目由Android视图转换为Project视图。

  2. libs目录下新建armeabi文件夹,将FFmpeg的arm\lib路径下带版本号的.so文件拷贝过来。

  3. libs目录下新建include文件夹,将FFmpeg的arm\include路径下的所有文件夹拷贝过来。
    最终的拷贝结果如图:
    NDK开发FFmpeg之HelloWorld_第1张图片

  4. 打开app/build.gradle文件,在android→defaultConfig结点下,新增sourceSets结点,并修改externalNativeBuild结点,具体内容为:

    defaultConfig {
        //新增sourceSets 结点
        sourceSets {
            main {
                jniLibs.srcDirs = ["libs"]
            }
        }
        //修改externalNativeBuild 结点
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters "armeabi"
            }
        }
    }
    
  5. 打开src/main/cpp/CMakeLists.txt文件,在第一个add_library结点后,增加FFmpeg的关联代码(建议直接复制,路径容易出错):

    #------------------------FFmpeg----------------------------------
    include_directories(../../../libs/include)
    set(DIR ../../../../libs)
    MESSAGE("打印")
    MESSAGE("路径 " ${DIR})
    MESSAGE("路径 " ${CMAKE_CURRENT_SOURCE_DIR})
    add_library(avcodec-58
            SHARED
            IMPORTED)
    set_target_properties(avcodec-58
            PROPERTIES IMPORTED_LOCATION
            ${DIR}/armeabi/libavcodec-58.so)
    add_library(avdevice-58
            SHARED
            IMPORTED)
    set_target_properties(avdevice-58
            PROPERTIES IMPORTED_LOCATION
            ${DIR}/armeabi/libavdevice-58.so)
    add_library(avformat-58
            SHARED
            IMPORTED)
    set_target_properties(avformat-58
            PROPERTIES IMPORTED_LOCATION
            ${DIR}/armeabi/libavformat-58.so)
    add_library(avutil-56
            SHARED
            IMPORTED)
    set_target_properties(avutil-56
            PROPERTIES IMPORTED_LOCATION
            ${DIR}/armeabi/libavutil-56.so)
    add_library(swresample-3
            SHARED
            IMPORTED)
    set_target_properties(swresample-3
            PROPERTIES IMPORTED_LOCATION
            ${DIR}/armeabi/libswresample-3.so)
    add_library(swscale-5
            SHARED
            IMPORTED)
    set_target_properties(swscale-5
            PROPERTIES IMPORTED_LOCATION
            ${DIR}/armeabi/libswscale-5.so)
    add_library(avfilter-7
            SHARED
            IMPORTED)
    set_target_properties(avfilter-7
            PROPERTIES IMPORTED_LOCATION
            ${DIR}/armeabi/libavfilter-7.so)
    #------------------------FFmpeg----------------------------------
    

三、编写Native代码

  1. 编写java类FFmpegUtil:

    package com.demo.ffmpegworld;
    
    public class FFmpegUtil {
        static {
            System.loadLibrary("ffmpeg-util");
        }
    
        /**
         * 获取FFmpeg的配置信息
         *
         * @return 配置信息字符串
         */
        public static native String getAvcodecConfiguration();
    }
    
  2. app/src/main/cpp文件夹下,创建ffmpeg-util.h文件:

    #ifndef FFMPEG_NATIVE_LIB_H
    #define FFMPEG_NATIVE_LIB_H
    
    #include 
    #include 
    #include 
    
    extern "C" { //编码
    	#include "libavcodec/avcodec.h" //封装格式处理
    	#include "libavformat/avformat.h" //像素处理
    	#include "libswscale/swscale.h"
    	#include 
    	#include  JNIEXPORT jstring JNICALL Java_com_demo_ffmpegworld_FFmpegUtil_getAvcodecConfiguration(JNIEnv
    	*env, jobject /* this */);
    }
    #define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"jason",FORMAT,##__VA_ARGS__);
    #define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"jason",FORMAT,##__VA_ARGS__);
    
    #endif //FFMPEG_NATIVE_LIB_H
    
    
  3. app/src/main/cpp文件夹下,创建ffmpeg-util.cpp文件:

    #include "ffmpeg-util.h"
    
    extern "C" JNIEXPORT jstring JNICALL
    Java_com_demo_ffmpegworld_FFmpegUtil_getAvcodecConfiguration(JNIEnv
    *env, jobject /* this */) {
        std::string hello = "Hello from C++";
        char info[10000] = {0};
        sprintf(info, "%s\n", avcodec_configuration());
        return env->NewStringUTF(info); 
    }
    
    

四、修改CMakeLists文件,编译运行

  1. 打开src/main/cpp/CMakeLists.txt文件,修改第一个add_library和最后一个target_link_libraries结点,修改内容分别为:

    #add_library结点 
    add_library( # Sets the name of the library.
            ffmpeg-util
            # Sets the library as a shared library.
            SHARED
            # Provides a relative path to your source file(s).
            ffmpeg-util.cpp)   
    #target_link_libraries结点 
    target_link_libraries( # Specifies the target library.
            ffmpeg-util
            # Links the target library to the log library
            # included in the NDK.
            avcodec-58
            avdevice-58
            avformat-58
            avutil-56
            swresample-3
            swscale-5
            -landroid # Add this.
            ${log-lib}) 
    
  2. 修改MainActivity代码,删除其自带的native方法,改为调用我们刚写好的getAvcodecConfiguration方法:

    public class MainActivity extends AppCompatActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Example of a call to a native method
            TextView tv = findViewById(R.id.sample_text);
            tv.setText(FFmpegUtil.getAvcodecConfiguration());
        } 
    }
    
  3. 编译运行,成功后可以看到生成的.so包可在app/build/intermediates/cmake/debug/obj文件夹下找到。安卓界面显示详细的配置信息,至此FFmpeg的HelloWorld程序完成。
    NDK开发FFmpeg之HelloWorld_第2张图片

你可能感兴趣的:(开发笔记)