FFmpeg 學習(三):將 FFmpeg 移植到 Android平台


首先需要去FFmpeg的官網http://www.ffmpeg.org/去下載FFmpeg的源碼,目前的版本號為FFmpeg3.3(Hilbert)。

下載的文件為壓縮包,解壓后得到ffmpeg-3.3目錄。

修改ffmpeg-3.3的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)'

原因:如果不修改配置,直接進行編譯出來的so文件類似libavcodec.so.55.39.101,文件的版本號位於so之后,這樣在Android上無法加載,所以需要修改!

編寫build_android.sh腳本文件:

在編譯FFmpeg之前需要進行配置,設置相應的環境變量等。所有的配置選項都在ffmpeg-3.3/configure這個腳本文件中,執行如下命令可查看所有的配置選項:

$ ./configure –help

下面將配置項和環境變量設置寫成一個sh腳本文件來運行以便編譯出Android平台需要的so文件出來。

build_android.sh的內容如下:

#!/bin/bash NDK=/Users/renhui/framework/android-ndk-r14b SYSROOT=$NDK/platforms/android-9/arch-arm/ TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 function build_one { ./configure \ --prefix=$PREFIX \ --enable-shared \ --disable-static \ --disable-doc \--enable-cross-compile \ --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \ --target-os=linux \ --arch=arm \ --sysroot=$SYSROOT \ --extra-cflags="-Os -fpic $ADDI_CFLAGS" \ --extra-ldflags="$ADDI_LDFLAGS" \ $ADDITIONAL_CONFIGURE_FLAG } CPU=arm PREFIX=$(pwd)/android/$CPU ADDI_CFLAGS="-marm" build_one

需要確定的是NDK,SYSROOT和TOOLCHAIN是否是本地的環境,並確定cross-prefix指向的路徑存在。

保存腳本文件后,將腳本的權限提升:

chmod 777 build_android.sh  

然后執行腳本,該腳本會完成對ffmpeg的配置,並生成config.h等配置文件,后面的編譯會用到。如果未經過配置直接進行編譯會提示無法找到config.h文件等錯誤。

然后執行下面兩個命令:

$make $make install  

至此,會在ffmpeg-3.3目錄下生成一個android目錄,其/android/arm/lib目錄下的so庫文件就是能夠在Android上運行的so庫。

 

創建Demo工程,測試上面生成的so文件能否正常使用:

  1. 創建一個新的Android工程
  2. 在工程根目錄下創建jni文件夾 
  3. 在jni下創建prebuilt目錄,然后:將上面編譯成功的so文件放入到該目錄下
  4. 創建包含native方法的類,先在src下創建cn.renhui包,然后創建FFmpegNative.java類文件。主要包括加載so庫文件和一個native測試方法兩部分,其內容如下: 
    package cn.renhui; public class FFmpegNative { static { System.loadLibrary("avutil-55"); System.loadLibrary("avcodec-57"); System.loadLibrary("swresample-2"); System.loadLibrary("avformat-57"); System.loadLibrary("swscale-4"); System.loadLibrary("avfilter-6"); System.loadLibrary("avdevice-57"); System.loadLibrary("ffmpeg_codec"); } public native int avcodec_find_decoder(int codecID); } 
  1. 用javah創建.頭文件: classes目錄,執行:javah-jni cn.renhui.FFmpegNative,會在當前目錄產生cn_renhui_FFmpegNative.h的C頭文件;
  1. 根據頭文件名,建立相同名字c文件cn_renhui_FFmpegNative.c,在這個源文件中實現頭文件中定義的方法,代碼如下:
    #include "cn_renhui_FFmpegNative.h" #ifdef __cplusplus extern "C" { #endif
     JNIEXPORT jint JNICALL Java_cn_renhui_FFmpegNative_avcodec_1find_1decoder (JNIEnv *env, jobject obj, jint codecID) { AVCodec *codec = NULL; /* register all formats and codecs */ av_register_all(); codec = avcodec_find_decoder(codecID); if (codec != NULL) { return 0; } else { return -1; } } #ifdef __cplusplus } #endif
  1. 編寫Android.mk,內容如下:
    LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := avcodec-57-prebuilt LOCAL_SRC_FILES := prebuilt/libavcodec-57.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avdevice-57-prebuilt LOCAL_SRC_FILES := prebuilt/libavdevice-57.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avfilter-6-prebuilt LOCAL_SRC_FILES := prebuilt/libavfilter-6.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avformat-57-prebuilt LOCAL_SRC_FILES := prebuilt/libavformat-57.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE :=  avutil-55-prebuilt LOCAL_SRC_FILES := prebuilt/libavutil-55.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE :=  avswresample-2-prebuilt LOCAL_SRC_FILES := prebuilt/libswresample-2.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE :=  swscale-4-prebuilt LOCAL_SRC_FILES := prebuilt/libswscale-4.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := ffmpeg_codec LOCAL_SRC_FILES := cn_dennishucd_FFmpegNative.c LOCAL_LDLIBS := -llog -ljnigraphics -lz -landroid LOCAL_SHARED_LIBRARIES := avcodec-57-prebuilt avdevice-57-prebuilt avfilter-6-prebuilt avformat-57-prebuilt avutil-55-prebuilt include $(BUILD_SHARED_LIBRARY)
  1. 編譯so文件,執行ndk-build
  2. 新建一個Activity,進行測試,測試核心代碼:
    FFmpegNative ffmpeg = new FFmpegNative(); int codecID = 28; int res = ffmpeg.avcodec_find_decoder(codecID); if (res == 0) { tv.setText("Success!"); } else { tv.setText("Failed!"); }

        28是H264的編解碼ID,可以在ffmpeg的源代碼中找到,它是枚舉類型定義的。在C語言中,可以換算為整型值。這里測試能否找到H264編解碼,如果能找到,說明調用ffmpeg的庫函數是成功的,這也表明我們編譯的so文件是基本可用。


2018年8月20號補充說明:目前最新版本的FFmpeg版本號為4.0.1 ,上面的方法能繼續正常使用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM