Android 集成 FFmpeg (一) 基礎知識及簡單調用

前言

網上關于 Android 集成 FFmpeg 的文章很多,但大多數都只介紹了步驟,沒有說明背后的原理,若之前沒有集成底層庫的經驗,那就會“神知無知”的走一步看一步,出錯幾率很大,出錯了也不知道原因,然后會亂猜“這篇教程有問題“,“換個版本估計可以”,甚至“電腦有問題,重裝下系統試試”。

為什么會出現這種情況,答案很簡單:欲速則不達,要實現 Android 端集成 FFmpeg 功能,那就要掌握必需的基礎知識,如果連 JNI、NDK都不了解,一上來就參考幾秒鐘搜出來的集成步驟開始集成,那只會被各種莫名其妙的異常完虐,如果運氣好很快就實現了功能呢? 在我看來這是更大的損失,這些你沒有掌握的知識如此接近卻又悄悄溜走。

那么在 Android 端集成 FFmpeg 需要掌握哪些基礎知識呢?個人認為以下內容是需要了解的:

  1. JNI
  2. CPU架構
  3. 交叉編譯
  4. NDK
  5. FFmpeg 簡介

以下知識點闡述是經過反復推敲的,不是隨意復制而來,其中融入自己的理解,以個人易于理解的方式記錄下來,希望能給你帶來幫助。

1.JNI

JNI,即 Java Native Interface ,是 Java 提供用來與其他語言通信的 api ,“其他語言”意味不止局限于 C 或 C++ ,也可以調用除 C 和 C++ 之外的語言,只是大多數情況下調用 C 或 C++ ; “通信”意味著 Java 和 其他語言之間可以相互調用,不止局限于 Java 調用其他語言,其他語言也可以主動調用 Java .

Java 虛擬機實現了跨平臺特性, 無法很好的實現與操作系統相關的本地操作,而 C 或 C++ 可以,同時代表著 C 或 C++ 不具備 Java 的跨平臺能力,那么當我們在程序中使用 JNI 功能時,就必須關注程序的平臺可移植性, JNI 標準要求本地代碼至少能工作在任何Java 虛擬機環境。

簡而言之,跨平臺的 Java 調用了不跨平臺的 C/C++,使程序喪失了跨平臺性,這就是 JNI 的副作用,所以可以不使用 JNI 時就盡量避免。而大多數不可避免的情況是:已存在用 C/C++ 寫的程序/庫或者 Java 語言不支持程序所要實現的特性,比如 ffmpeg 是由 C 編寫的,則必須要通過 JNI 實現調用。

JNI 的實現步驟很簡單,如下:

  1. 編寫帶有 native 方法的 Java 類
  2. 生成該類擴展名為 .h 的頭文件
  3. 創建該頭文件的 C/C++ 文件,實現 native 方法
  4. 將該 C/C++ 文件編譯成動態鏈接庫
  5. 在Java 程序中加載該動態鏈接庫

動態鏈接庫是一組源代碼的模塊,其中包含可供應用程序調用的函數。比如 Windows 下的 .dll 文件就是一種動態鏈接庫,也就是說 Java 程序在 Windows 中運行,所需的動態鏈接庫就是 .dll 文件; 如果 Java 程序在 Linux 中運行,所需的動態鏈接庫就是 .so 文件 ,這里 JNI 的副作用已初見端倪,本來無視操作系統的 Java ,因為 JNI ,就要考慮運行環境是 Windows 還是 Linux 。除此之外,還要考慮 CPU 架構,這也是 Android 中使用 JNI 主要需考慮的 so 庫兼容型問題。

對于 Java 程序來說,需要的僅僅是編譯后的動態鏈接庫,不需要 C/C++ 文件和 .h 頭文件。Android 亦如此,網上很多 Android NDK 教程會把需要編譯的 C/C++ 源碼放入 Android 工程中,形成類似這樣的工程結構:

這對新手來說可能會產生誤導,誤以為 Android 工程需要 C/C++ 文件或 .h 頭文件或者其他的文件,要清楚的是, Android 工程需要的僅僅是編譯后的 .so 庫,所以我們可以在工程之外編譯完后,只將 .so 庫移植到工程中。那為什么大多數教程會把源碼先移植到 Android 工程中再去編譯呢?目的只有一個:節省目錄的切換以及 .so 庫的復制時間,實際上這些時間微乎其微,我推薦新手將編譯操作于工程外進行,更易理解。

2.CPU 架構

我們都知道 CPU 是什么,那 CPU 架構到底是什么呢?回歸到“架構”這個詞本身含義,CPU 架構就是 CPU 的框架結構、設計方案,處理器廠商以某種架構為基礎,生產自己的 CPU,就好比“總-分-總”是文章的一種架構,多篇文章可以都基于“總-分-總”架構。

常見的 CPU 架構有 x86、x86-64 以及 arm 等, x86-64 其實也是基于 x86 架構,只是在 x86 的基礎上做了一些擴展,以支持 64 位程序的應用,常見的 Intel 、AMD 處理器都是基于 x86 架構的。

而 x86 架構主打的是 pc 端,對于移動端,arm 架構處于霸主地位 ,由于其體積小、低功耗、低成本、高性能的優點,被廣泛應用在嵌入式系統中,目前大多數安卓、蘋果手機的 CPU 都基于 arm 架構,此處所說的 arm 架構指 arm 系列架構,其中包括 ARMv5 、ARMv7 等等。

最后再看 Android 端 , Android 系統目前支持 ARMv5、ARMv7、ARMv8、 x86 、x86_64、MIPS 以及 MIPS64 共七種 CPU 架構,也就是說除此之外其他 CPU 架構的硬件并不能運行 Android 系統。

3.交叉編譯

在某個平臺上,編譯該平臺的可執行程序,叫做本地編譯,比如在 Windows 平臺上編譯 Windows 自身的可執行程序;在 x86 平臺上,編譯 x86 平臺自身的可執行程序。

在某個平臺上,編譯另一種平臺的可執行程序,就是交叉編譯,比如在 x86 平臺上,編譯 arm 平臺的可執行程序,這也是 Android 端使用最多的交叉編譯類型。

在交叉編譯時,由于主機與目標的體系架構、環境不同,所以交叉編譯比本地編譯復雜很多,需要一些工具來解決主機與目標不同特性的問題,這些工具構成的工具集就叫做交叉編譯鏈。

既然交叉編譯比本地復雜很多,那為什么不使用本地編譯,比如在 arm 平臺編譯 arm 平臺的可執行程序呢?這是因為目標平臺存儲空間和計算能力通常是有限的,而編譯過程需要較大的存儲空間和較快的計算能力,但目標平臺無法提供。

4.NDK

我們需要的是 arm 平臺的動態庫,而這一編譯過程往往是在 x86 平臺上進行,所以屬于交叉編譯,需要交叉編譯鏈來實現,所以 NDK(Native Development Kit )中提供了交叉編譯鏈,方便開發。

Android 中包括七種 CPU 架構,NDK 中自然就有與之對應的交叉編譯鏈,以下是 Android 官網對此的表格描述:

除此之外,NDK 還提供了一些原生標頭和共享庫文件,包括 C/C++ 支持庫、從 C/C++ 代碼中可以向 Android 系統輸出日志的 < android/log.h > 等等,可以點擊這里了解更多,總之,NDK 是用來幫助我們實現交叉編譯的工具。

在實際使用時,比較重要的是 Android.mk 語法,內容并不多,但你必須了解,不然只復制別人的配置很容易出錯,關鍵是你無法真正的掌握這部分知識,而最好的學習方法就是仔細閱讀幾遍 Android.mk 官網教程

另外還需要了解什么是 ABI ,ABI 即 application binary interface ,應用程序二進制接口,顧名思義,“二進制接口”說明這是程序與系統之間的底層接口,它定義了程序如何與系統交互。我們應該指定每個 CPU 架構所對應的 ABI,所以 Android 中就出現了 armeabi 、armeabi-v7a、arm64-v8a、x86、x86_64、mips 以及 mips64 目錄來區分不同的 ABI ,我們將編譯好的動態庫放入對應 CPU 架構的 ABI 目錄中就可以了。

掌握了以上知識點,才能知道 Android 集成 FFmpeg本質上是在做什么,為什么要這樣做。不只是集成 FFmpeg,這些知識對于任何底層庫的集成都是通用、必要的。

5.FFmpeg 簡介

FFmpeg 是一套可以用來記錄、轉換數字音頻、視頻,并能將其轉化為流的開源計算機程序

FFmpeg 被很多開源項目和軟件使用,比如暴風影音、QQ影音、格式工廠等,另外在我常用的 App 中也發現了它的身影:

其實寫到這里,有點猶豫非操作步驟的內容是否敘述過多了,后來想想,這正是這篇文章的初衷,盡量全面清楚,透過表面操作看本質,另外最重要的一個目標,就是爭取做到授人以漁,我相信這也是大家對所有技術教程文章的一個美好愿景。

下面分為 3 個部分介紹 FFmpeg的編譯及 Android 端的簡單調用:

  1. 準備
  2. 編譯 FFmpeg
  3. 編譯動態庫及調用

1.準備

  • Linux 環境(Ubuntu 16.04):從個人經驗而談,準備 Linux 環境比 Windows 環境編譯的工作量小。
  • 下載NDK(android-ndk-r14b) :網上有些教程美言曰“NDK向后兼容”,其實查閱 NDK 版本更新說明就能解決。
  • 下載 FFmpeg (ffmpeg-3.3.3): 官網下載鏈接:https://ffmpeg.org/download.html

2.編譯 FFmpeg

編譯環境為 x86 的 Linux ,運行環境為 arm 架構的 Android 系統,目標是把 FFmpeg 源碼編譯成 Android 端可調用的動態庫,這屬于交叉編譯,所以需要 NDK 提供的交叉編譯工具,這是這一步驟的本質意義。

Android 工程中只支持導入 .so 結尾的動態庫,形如:libavcodec-57.so 。但是FFmpeg 編譯生成的動態庫默認格式為 xx.so.版本號 ,形如:libavcodec.so.57 , 所以需要修改 FFmpeg 根目錄下的 configure 文件,使其生成以 .so 結尾格式的動態庫:

# 將 configure 文件中的:
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)' 
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"' 
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)' 
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'

#替換為:
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

在編譯 FFmpeg 之前,我們需要修改 FFmpeg 的編譯選項,主要目的如下:

  • 規定編譯方式,使其通過交叉編譯生成我們需要的動態庫。
  • 選擇所需功能,針對需求定制 FFmpeg 功能,精簡動態庫。

比如我們需要對 mp3 文件進行剪切、合并等操作,則應開啟 mp3 格式編碼與解碼功能( FFmpeg 本身不支持 mp3 格式編碼,需要引入 libmp3lame 庫)。

怎么修改 FFmpeg 的編譯選項呢?在 FFmpeg 根目錄下通過 ./configure 命令進行設置,但是為了方便記錄與修改,我們選擇在根目錄下建立一個腳本文件來運行 ./configure 命令。

針對所需功能,腳本文件如下 :

#!/bin/bash  
NDK=/home/yhao/Android/android-ndk-r14b
SYSROOT=$NDK/platforms/android-14/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64

CPU=arm
PREFIX=$(pwd)/Android/$CPU
MP3LAME=/home/yhao/sf/lame-3.99.5/android

./configure \
    --prefix=$PREFIX \          #規定編譯文件在哪里生成
    --enable-cross-compile \    #啟用交叉編譯方式
    --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \  #交叉編譯鏈
    --target-os=linux \         #目標系統
    --arch=arm \                #目標平臺架構
    --sysroot=$SYSROOT \        #交叉編譯環境
    --extra-cflags="-I${MP3LAME}/include" \                 #額外需要的頭文件
    --extra-ldflags="-L${MP3LAME}/lib" \                    #額外需要的庫                 
    --enable-shared \           #生成動態庫(共享庫)
    --disable-static \          #禁止生成靜態庫
    --disable-doc \             #禁用不需要的功能,下同
    --disable-ffserver \
    --disable-parsers \
    --disable-protocols \
    --disable-indevs \
    --disable-bsfs \
    --disable-muxers \
    --disable-demuxers \
    --disable-hwaccels \
    --disable-decoders \
    --disable-encoders \
    --enable-parser=mpegaudio \ #啟用需要的功能,下同
    --enable-protocol=http \
    --enable-protocol=file \
    --enable-libmp3lame \
    --enable-encoder=libmp3lame \
    --enable-encoder=png \
    --enable-demuxer=mp3 \
    --enable-muxer=mp3 \
    --enable-decoder=mjpeg \
    --enable-decoder=mp3

除強迫癥風格的注釋之外,再對個別配置進行說明:

  • --sysroot=$SYSROOT : 前言中提到 NDK 除了提供 交叉編譯鏈 以外,還提供一些原生標頭和共享庫文件,通過此配置指定了交叉編譯環境,使其在編譯過程中能夠引用到 NDK 提供的原生標頭和共享庫文件,其中 android-14 目錄指定了生成動態庫最低支持的 Android 版本,嗯~ ,這里可以說它是向后兼容的。

  • --target-os=linux :Android 內核為 Linux ,故在此指定為 linux ,如果要編譯的目標系統為 ios ,則指定為 darwin 。

  • --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- : 類似于通配符方式指定 bin 目錄下以 arm-linux-androideabi-
    開頭的交叉編譯工具,假如不支持這種配置方式則需分別指定,比如在交叉編譯 libmp3lame 時就是分別指定的:

這里寫圖片描述
  • --extra-cflags 和 --extra-ldflags : 由于開啟 mp3 編碼需要引入 libmp3lame 庫,所以需要指定編譯好的 libmp3lame 頭文件和庫文件的路徑,這樣在編譯時才能正確引用到 libmp3lame 。這里是我編譯好的 libmp3lame 庫,下載后指定對應路徑即可 。

  • FFmpeg 功能的開啟和禁用 : 在 FFmpeg 源碼根目錄下通過 ./configure --help 命令查看所有配置選項,針對需求配置,這里針對 mp3 文件操作的功能進行配置,禁用了很多不需要的功能,大幅精簡動態庫,從而減小 APK 大小。

接下來運行該腳本文件使配置生效,比如我的腳本文件名為 config.sh :

sh config.sh

運行成功后會輸出生效的配置,可以看到此時支持的編解碼:

這里寫圖片描述

ok ,現在已經配置完編譯選項了,接下來就可以開始編譯了啦~

sudo make -j4

編譯完成不要忘記安裝:

sudo make install

然后就可以看到成功生成:

這里寫圖片描述

3.編譯動態庫及調用

你可能會疑問,上一步已經編譯 FFmpeg 源碼生成動態庫了,為什么這一步還是“編譯動態庫”呢?其實這個問題等效于:上一步中生成的動態庫可以直接在 Android 工程中使用嗎?

答案是否定的,回到文章開頭 JNI 的使用步驟,在編寫帶有 native 方法的 Java 類后,緊接著就是用 C/C++ 實現本地接口,這是 Java 與 C/C++ 交互的必要通道。

所以接下來需要編寫本地接口,在本地接口中調用上一步編譯好的 FFmpeg 動態庫,然后將本地接口也編譯成動態庫,供 Android 調用,這一步還需要“編譯動態庫”。

網上有些教程在這一步把 FFmpeg 源碼、動態庫全部復制到 Android 工程中,然后在工程中新建本地接口、mk文件...... 花里胡哨的看的我頭皮發麻~ 這一步我推薦在 Android 工程之外進行,直到生成最終可用的動態庫之后,再拷貝到 Android 工程中直接使用。

首先新建一個文件夾,取名隨意,比如 “ndkBuild ”,這個目錄就作為我們的工作空間,然后在 ndkBuild 下新建 jni 文件夾, 作為編譯工作目錄。 OK~ 接下來按照前言中的 jni 步驟來劃分操作:

1. 編寫帶有 native 方法的 Java 類

package com.jni;

public class FFmpeg {
    
    public static native void run();

}

2. 生成該類擴展名為 .h 的頭文件

在 Android Studio 的 Terminal 中 切換到 java 目錄下,運行 javah 命令生成頭文件:

javah -classpath .  com.jni.FFmpeg

網上很多教程需要先生成 .class 文件,而我在 java 1.8 環境下親測以上一句命令即可。

3. 創建該頭文件的 C/C++ 文件,實現 native 方法

將生成的 com_jni_FFmpeg.h 文件剪切到 ndkBuild 的 jni 目錄下,創建對應的 C 文件 com_jni_FFmpeg.c :

#include <android/log.h>
#include "com_jni_FFmpeg.h"

#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"

JNIEXPORT void JNICALL Java_com_jni_FFmpeg_run(JNIEnv *env, jclass obj) {
  
    char info[40000] = {0};
    av_register_all();
    AVCodec *c_temp = av_codec_next(NULL);
    while(c_temp != NULL){
       if(c_temp->decode!=NULL){
          sprintf(info,"%s[Dec]",info);
       }else{
          sprintf(info,"%s[Enc]",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[%10s]\n",info,c_temp->name);
       c_temp=c_temp->next;
    }
__android_log_print(ANDROID_LOG_INFO,"myTag","info:\n%s",info);
}

這段程序用于輸出 FFmpeg 支持的編解碼信息,通過 < android/log.h > 的 __android_log_print 方法可以直接將信息輸出到 Android Studio 的 logcat 。

4. 將該 C/C++ 文件編譯成動態鏈接庫

編譯 FFmpeg 源碼時的實際入口是通過 FFmpeg 提供的 makefile ,而在這一步,將直接使用 NDK 提供的編譯方法,需要提供 Application.mk 和 Android.mk 文件。

首先在 jni 目錄下創建 Application.mk 文件 :

APP_ABI := armeabi
APP_PLATFORM=android-14

APP_ABI 表示編譯生成 armeabi 架構的 so 庫,APP_PLATFORM 表示最低支持的 Android 版本。

然后在 jni 目錄下創建 Android.mk 文件:

LOCAL_PATH:= $(call my-dir)

INCLUDE_PATH:=/home/yhao/sf/ffmpeg-3.3.3/Android/arm/include
FFMPEG_LIB_PATH:=/home/yhao/sf/ffmpeg-3.3.3/Android/arm/lib

include $(CLEAR_VARS)
LOCAL_MODULE:= libavcodec
LOCAL_SRC_FILES:= $(FFMPEG_LIB_PATH)/libavcodec-57.so
LOCAL_EXPORT_C_INCLUDES := $(INCLUDE_PATH)
include $(PREBUILT_SHARED_LIBRARY)
 
include $(CLEAR_VARS)
LOCAL_MODULE:= libavformat
LOCAL_SRC_FILES:= $(FFMPEG_LIB_PATH)/libavformat-57.so
LOCAL_EXPORT_C_INCLUDES := $(INCLUDE_PATH)
include $(PREBUILT_SHARED_LIBRARY)
 
include $(CLEAR_VARS)
LOCAL_MODULE:= libswscale
LOCAL_SRC_FILES:= $(FFMPEG_LIB_PATH)/libswscale-4.so
LOCAL_EXPORT_C_INCLUDES := $(INCLUDE_PATH)
include $(PREBUILT_SHARED_LIBRARY)
 
include $(CLEAR_VARS)
LOCAL_MODULE:= libavutil
LOCAL_SRC_FILES:= $(FFMPEG_LIB_PATH)/libavutil-55.so
LOCAL_EXPORT_C_INCLUDES := $(INCLUDE_PATH)
include $(PREBUILT_SHARED_LIBRARY)
 
include $(CLEAR_VARS)
LOCAL_MODULE:= libavfilter
LOCAL_SRC_FILES:= $(FFMPEG_LIB_PATH)/libavfilter-6.so
LOCAL_EXPORT_C_INCLUDES := $(INCLUDE_PATH)
include $(PREBUILT_SHARED_LIBRARY)
 
include $(CLEAR_VARS)
LOCAL_MODULE:= libswresample
LOCAL_SRC_FILES:= $(FFMPEG_LIB_PATH)/libswresample-2.so
LOCAL_EXPORT_C_INCLUDES := $(INCLUDE_PATH)
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libpostproc
LOCAL_SRC_FILES:= $(FFMPEG_LIB_PATH)/libpostproc-54.so
LOCAL_EXPORT_C_INCLUDES := $(INCLUDE_PATH)
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= libavdevice
LOCAL_SRC_FILES:= $(FFMPEG_LIB_PATH)/libavdevice-57.so
LOCAL_EXPORT_C_INCLUDES := $(INCLUDE_PATH)
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := com_jni_FFmpeg.c 
LOCAL_C_INCLUDES := /home/yhao/sf/ffmpeg-3.3.3
LOCAL_LDLIBS := -lm -llog
LOCAL_SHARED_LIBRARIES := libavcodec libavfilter libavformat libavutil libswresample libswscale libavdevice
include $(BUILD_SHARED_LIBRARY)

對于 Android.mk 文件前面提到過,最好的學習方法就是仔細閱讀幾遍 Android.mk 官網教程 。 簡要說明一下,此文件將之前編譯好的 FFmepg 動態庫通過 NDK 提供的預編譯方式編譯,通過 prebuilt 這個單詞也能猜到它的含義,點擊了解 NDK 預編譯, 最后將 com_jni_FFmpeg.c 編譯成名為 ffmpeg 的動態庫。

此時 jni 目錄下應有以下四個文件:

請無視 Android.mk 文件上的小鎖兒~ 。然后在 jni 目錄下運行 (注意要把 ndk 添加到環境變量) :

ndk-build

大功告成 ,此時在 ndkBuild 目錄下生成了 libs 和 obj 目錄,而 Android 需要的最終的動態庫就在 libs 目錄下:

5. 在Java 程序中加載該動態鏈接庫

將 libs 目錄下的 armeabi 文件夾整體拷貝到 Android Studio 工程的 libs 文件夾下,當然如果你的工程已經存在 armeabi 目錄,就把該目錄下的動態庫拷貝到工程的 armeabi 目錄下。

在 FFmpeg 中加載動態庫:

package com.jni;


public class FFmpeg {

    static {
        System.loadLibrary("avutil-55");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avformat-57");
        System.loadLibrary("avdevice-57");
        System.loadLibrary("swresample-2");
        System.loadLibrary("swscale-4");
        System.loadLibrary("postproc-54");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("ffmpeg");
    }

    public static native void run();
}

記得在應用的 build.gradle 文件中 android 節點下添加動態庫加載路徑:

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

然后在程序中調用 FFmpeg.run() 方法 ,可以看到 logcat 輸出了 FFmpeg 的編解碼信息:

總結

這篇文章較多篇幅介紹了 JNI 相關的基礎知識,對 JNI 經驗缺乏的人應該會有較多幫助,尤其是交叉編譯和 CPU 架構部分,如果一個月前的我看到估計都感激涕零了,當初一臉茫然的按照網上的教程集成,殊不知不了解這些知識是真的愣頭青。

此文中僅僅實現了 Android 端獲取 FFmpeg 編解碼信息,而要實際使用的話,就要掌握 FFmpeg 提供的函數或者通過命令方式調用,后者難度較小,另外還有 libmp3lame 庫的編譯,下篇文章一起總結。

關注公眾號,Get 更多知識點
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容