1. 程式人生 > >Android 引入 FFMpeg 並列印編解碼庫

Android 引入 FFMpeg 並列印編解碼庫

在編譯完 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日晚