1. 程式人生 > >Android ffmpeg編譯

Android ffmpeg編譯

首先,被這部分煩的不行的可以去github裡clone一些別人的成品輕鬆拿到適合Android的編譯結果

    說下自己的環境
    win10 x64
    VMware® Workstation 12 Pro
    ubuntu 14.04 LTS
    android-ndk-r10b
    ffmpeg3.0.2

Step1

android-ndk-r10b的安裝,超級簡單,去官網按照自己的配置下載一個,然後放到你習慣的目錄下(我直接放/目錄下了)。最後export配置下就好了

export NDK_HOME=/android-ndk-r10b
export PATH=$NDK_HOME:$PATH


Step2

到ffmpeg的官網下載最新的原始碼包http://www.ffmpeg.org/。並解壓到你習慣的位置(我這裡依然解壓在/根目錄下)然後對他的配置檔案稍作修改,原因是為了讓編譯出來的so庫適合Android。

su gedit /ffmpeg-3.0.2/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)'





這裡無腦改即可,不需要做其它修改。
Step3

這步卡死了梟雄無數,關鍵在於網上很多說明不是很詳細;其實就是一個configure的引數(至於引數的意思自己–help檢視哈),ffmpeg的引數比較多根據個人的不同要求可以有不同的配置,網上很多寫成*.sh的檔案都是可以用的,只不過不清楚裡面幾個變數的意思含義的話很容易報錯卡這裡。我也是在這裡卡了好一會,感謝github上大神的詳解,這裡抄襲下:

1.指定臨時目錄
export TMPDIR=/home/djia/tmpdir
指定一個臨時目錄,可以是任何路徑,但必須保證存在,ffmpeg編譯要用;

2.指定NDK路徑
NDK=/home/djia/android/android-ndk-r10

3.指定使用NDK Platform版本
SYSROOT=$NDK/platforms/android-16/arch-arm/
這裡指定的ndk platform的路徑,一定要選擇比你的目標機器使用的版本低的,比如你的手機是android-15版本,那麼就選擇低於15的

4.指定編譯工具鏈
TOOLCHAIN=/home/djia/android/android-ndk-r10/toolchains/arm-Linux-androideabi-4.9/prebuilt/linux-x86_64

5.指定編譯後的安裝目錄
PREFIX=/root/workspace/ffmpeg_shared_compile/dxjia_ffmpeg_install
這個目錄是ffmpeg編譯後的so的輸出目錄,會有一個include和lib資料夾生成在這裡,這也是我們之後要在android apk中使用的.

    網上很多種.sh我這裡也貼一個,順便把它的github專案地址貼出來
    https://github.com/dxjia/ffmpeg-compile-shared-library-for-android

#!/bin/bash
export TMPDIR=/home/djia/tmpdir
NDK=/home/djia/android/android-ndk-r10
SYSROOT=$NDK/platforms/android-16/arch-arm/
TOOLCHAIN=/home/djia/android/android-ndk-r10/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CPU=arm
PREFIX=/root/workspace/ffmpeg_shared_compile/dxjia_ffmpeg_install/arm/
ADDI_CFLAGS="-marm"
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-doc \
--disable-symver \
--enable-small \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
build_one



   
Step4

給sh檔案設定可執行許可權並執行下sh檔案,然後休息幾分鐘。。。幸運的話 就可以看到結果了。。。順便提下上面有需要的目錄都是需要你事先手動建好順便把許可權設定下。。。
ok,假設你一步步走到這裡了。開啟你sh檔案裡指定的放編譯結果的目錄, $PREFIX 目錄下生成 include和lib兩個資料夾,將lib資料夾中的 pkgconfig 目錄和so的連結檔案刪除,只保留so檔案,然後include 和lib兩個目錄拷貝出來這就是我們想要的了

華麗的分割下

最後把拿到的庫檔案測試下效果,寫一個jni的程式呼叫下。
過程我就不寫了,按照jni的流程走下。有幾點說明下,一個Android.mk

ifeq ($(APP_ABI), x86)
LIB_NAME_PLUS := x86
else
LIB_NAME_PLUS := armeabi
endif

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= avcodec-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= avdevice-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavdevice-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= avfilter-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavfilter-6.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= avformat-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavformat-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE :=  avutil-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libavutil-55.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libswresample-2.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libffmpegjni

ifeq ($(APP_ABI), x86)
TARGET_ARCH:=x86
TARGET_ARCH_ABI:=x86
else
LOCAL_ARM_MODE := arm
endif

LOCAL_SRC_FILES := com_hsb_ffmpeg_FFmpegNative.c
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
LOCAL_SHARED_LIBRARIES:= avcodec-prebuilt-$(LIB_NAME_PLUS) \
                         avdevice-prebuilt-$(LIB_NAME_PLUS) \
                         avfilter-prebuilt-$(LIB_NAME_PLUS) \
                         avformat-prebuilt-$(LIB_NAME_PLUS) \
                         avutil-prebuilt-$(LIB_NAME_PLUS) \
                         swresample-prebuilt-$(LIB_NAME_PLUS) \
                         swscale-prebuilt-$(LIB_NAME_PLUS)
LOCAL_C_INCLUDES += -L$(SYSROOT)/usr/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include

ifeq ($(APP_ABI), x86)
LOCAL_CFLAGS := -DUSE_X86_CONFIG
else
LOCAL_CFLAGS := -DUSE_ARM_CONFIG
endif

include $(BUILD_SHARED_LIBRARY)



 
   
另外一個是c裡的幾行程式碼

JNIEXPORT jint JNICALL Java_com_hsb_ffmpeg_FFmpegNative_test_1h264
  (JNIEnv* env, jobject thiz,jint codecID)
 {
     AVCodec* codec = NULL;
    av_register_all();//該函式在所有基於ffmpeg的應用程式中幾乎都是第一個被呼叫的。只有呼叫了該函式,才能使用複用器,編碼器等
    codec = avcodec_find_decoder(codecID);//通過code ID查詢一個已經註冊的音視訊編碼器。H264的codecID是28,所以我們java那邊傳28下來如果檢測到H264註冊過了這邊codec就不為空,返回0
    if(codec != NULL)
    {
      return 0;
    }else{
      return -1;
    }
 }

 
    最後一點,其實jni的過程也是浪費了些時間,大部分的錯在於細節。。。大部分錯誤都是你漏了啥。。。如果你也報錯了又沒有思路那就把jni的呼叫過程在複習下。。。maybe 你會拍大腿的。。。。

    last but not least,把走到這裡我用到的打包發資源下(一個result是ubuntu那邊編譯的結果,一個FFmpeg是android的專案)
    http://download.csdn.net/detail/xiaoru5127/9533849