Android 引入 FFMpeg 并打印编解码库

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

在编译完 Android 平台下的 FFMpeg 库之后,我们接下来接入到 AndroidStudio 工程中。我们验证的目的是想在 AndroidStudio 控制台中打印 FFMpeg 所有支持的编解码库信息,下面我们来一步一步的实现这个过程。

要完成这个功能主要有以下 2 步:

  • 创建支持 C++ 的 AndroidStudio 工程。

  • 配置 FFMpeg

1.1 创建支持 C++ 的 AndroidStudio 工程

创建一个支持 C++ 的 AndroidStudio 工程,具体如何创建请点击查看NDK 基本知识点&第一个JNI示例分析,在这里我们只关注与 FFMpeg 相关的东西。这里我们创建的 AndroidStudio 工程名字为 FFmpeg4Android

1.1.1 配置 build.gradle 文件

    1. 指定输出异常信息和输出的 so 库为 arm 的 cpu 架构。
    1. 指定 CMakeList.txt 文件的位置。
android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.liaowj.ffmpeg.helloworld"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
       
        externalNativeBuild { //1
            cmake {
                cppFlags "-frtti -fexceptions"
                //输出 arm 架构
                abiFilters 'armeabi'
            }
        }
        sourceSets {
            main {
                jniLibs.srcDirs = ['src/main/jniLibs']
            }
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    //2.
    externalNativeBuild {
        cmake {
             //配置 CMakeList.txt 文件
            path "CMakeLists.txt"
        }
    }

}

1.2 配置 FFMpeg

1.2.1 引入头文件和so库文件

将编译后的 FFMpeg 的头文件和 so 库拷贝到 ffmpeg4helloworld 工程下的中,具体看以下截图,在这里只拷贝 arm 架构的。

导入头文件和so

1.2.2 CmakeList 中配置 ffmpeg

CMakeList 配置 ffmpeg 主要分为四步:

  • 第一步:导入库的头文件路径

导入头文件。导入头文件的目的是为了在引用时,只需要写 .h 文件的相对地址即可,而不需要写绝对地址。

include_directories(src/main/cpp/includes)
  • 第二步:添加动态库

添加库名称为 avcodec-57SHARED 表示动态库,IMPORTED 表示以导入的方式使用该库。这里只是以 avcodec-57 来演示, FFMepeg 其他 so 的引入是一样的。
avcodec-57 是别名哦

add_library( avcodec-57 SHARED IMPORTED)
  • 第三步:设置动态库路径

第一步已经给头文件设置了路径,下面给 so 库设置路径。这里还是以 avcodec-57 为例。

set_target_properties( avcodec-57 # so 库的名字,就是上面设置的别名
      PROPERTIES IMPORTED_LOCATION # 导入的方式引用
      ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-57.so) # 该库实际的位置,这个位置是相对 `CMakeList.txtx` 文件的位置的。
  • 第四步:链接动态库

链接 FFMpeg 的动态库。目的是将 so 库和当前的工程建立关系。

target_link_libraries( # Specifies the target library.
                       native-lib # 当期工程的库
                       # 链接动态库
                       avcodec-57
                       ...
                       log )

下面是 CMakeList.txt 配置代码:

cmake_minimum_required(VERSION 3.4.1)

include_directories(src/main/cpp/includes)

add_library( # Sets the name of the library.
             native-lib
             SHARED
             src/main/cpp/native-lib.cpp)

add_library( avcodec-57 SHARED IMPORTED)
set_target_properties( avcodec-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-57.so)


add_library( avdevice-57 SHARED IMPORTED)
set_target_properties( avdevice-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavdevice-57.so)


add_library( avfilter-6 SHARED IMPORTED)
set_target_properties( avfilter-6
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavfilter-6.so)


add_library( avformat-57 SHARED IMPORTED)
set_target_properties( avformat-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavformat-57.so)


add_library( avutil-55 SHARED IMPORTED)
set_target_properties( avutil-55
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavutil-55.so)

add_library( postproc-54 SHARED IMPORTED)
set_target_properties( postproc-54
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libpostproc-54.so)

add_library( swresample-2 SHARED IMPORTED)
set_target_properties( swresample-2
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libswresample-2.so)


add_library( swscale-4 SHARED IMPORTED)
set_target_properties( swscale-4
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libswscale-4.so)


target_link_libraries( # Specifies the target library.
                       native-lib
                       avcodec-57
                       avdevice-57
                       avformat-57
                       avfilter-6
                       avutil-55
                       postproc-54
                       swresample-2
                       swscale-4
                      log )

1.3 调用 FFMpeg API

  • 在 Java 层加载动态库

FFmpegDemo.java

package com.liaowj.ffmpeg.helloworld;

/**
 * @author liaowj
 * @time 2018/12/31 11:04 PM
 * @desc
 **/
public class FFmpegDemo {
    //1.加载动态库
    static {
        System.loadLibrary("native-lib");
        System.loadLibrary("swresample-2");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avformat-57");
        System.loadLibrary("swscale-4");
        System.loadLibrary("postproc-54");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avdevice-57");
    }

    //native 方法,执行 jni 的代码
    public n ative void logFFMpegInfo();
}

  • 编写 native 代码打印 FFMpeg 支持的编解码库

native-lib.cpp

#include <jni.h>
#include <string>
#include "android/log.h"

extern "C" {
#include <libavformat/avformat.h>
}
#define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"liaowj",FORMAT,##__VA_ARGS__);
extern "C"
JNIEXPORT void JNICALL
Java_com_liaowj_ffmpeg_helloworld_FFmpegDemo_logFFMpegInfo(JNIEnv *env, jobject instance) {

   av_register_all();
   AVCodec *c_temp = av_codec_next(NULL);
   while (c_temp != NULL) {
       switch (c_temp->type) {
           case AVMEDIA_TYPE_VIDEO:
               LOGI("[Video]:%s", c_temp->name);
               break;
           case AVMEDIA_TYPE_AUDIO:
               LOGI("[Audio]:%s", c_temp->name);
               break;
           default:
               LOGI("[Other]:%s", c_temp->name);
               break;
       }
       c_temp = c_temp->next;
   }
}
  • 执行调用程序

    关注控制台即可看到输出的打印信息了。

/**
* @author liaowj
* @time 2018/12/31 11:36 PM
* @desc
**/
public class MainActivity extends AppCompatActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);
   }

   /**
    * 获取 FFMpeg 相关信息,打印到 TextView 中
    *
    * @param view
    */
   public void logFFMpegInfo(View view) {
       FFmpegDemo fFmpegDemo = new FFmpegDemo();
       fFmpegDemo.logFFMpegInfo();
   }
}

Demo

log日志

以上流程就是第一个 FFMpeg 程序,最后的 c++ 代码输出的就是输出 FFmpeg 的编解码器信息。

项目源码:
https://github.com/liaowjcoder/FFmpeg4Android

记录于 2018年11月8日晚

猜你喜欢

转载自blog.csdn.net/lwj_zeal/article/details/85544232