Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> FFmpeg的Android平台移植—編譯篇

FFmpeg的Android平台移植—編譯篇

編輯:關於Android編程

FFmpeg的Android平台移植—編譯篇

Dennis Hu 2014年3月28日

摘要:本文主要介紹將FFmpeg音視頻編解碼庫移植到Android平台上的編譯和基本測試過程。

環境准備:

Ubuntu12.04 TLS

android-ndk-r9d-linux-x86_64.tar.bz2

adt-bundle-windows-x86_64-20131030.zip


第一步:源代碼下載

到FFmpeg官方網站http://www.ffmpeg.org/上去下載源代碼,這裡下載的源代碼是最權威的。進入官網之後,選擇”Download”進入下載頁面,截止2014年3月28日止,最新的發布的穩定版本為FFmpeg2.2,代號”Muybridge”。選擇該下方的”Downloadgzip tarball”進行下載,下載後的文件名為ffmpeg-2.2.tar.gz,大約8.3M。

第二步:在Linux環境下編譯FFmpeg

在Windows平台可以采用VMplayer虛擬機上安裝ubuntu的方式,本人也是采用這種方式。

本文以/home/dennis為根目錄進行操作和說明:

將ffmpeg-2.2.tar.gz拷貝至根目錄,然後執行如下解壓命令將其解壓:

$tar zxf ffmpeg-2.2.tar.gz

解壓後將得到/home/dennis/ffmpeg-2.2目錄。

修改ffmpeg-2.2/configure文件

如果直接按照未修改的配置進行編譯,結果編譯出來的so文件類似libavcodec.so.55.39.101,版本號位於so之後,Android上似乎無法加載。因此需要按如下修改:

將該文件中的如下四行:

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)'

編寫build_android.sh腳本文件

FFmpeg可以說是一個包絡音視頻編解碼及格式的超級霸。因此在編譯前通常都需要進行配置,設置相應的環境變量等。

所有的配置選項都在ffmpeg-2.2/configure這個腳本文件中,可以通過執行如下命令來查看所有的配置選項:

$ ./configure –help

配置選項很多,也較為復雜,這裡先把我需要的搞出來,然後有時間再慢慢看。

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

build_android.sh的內容如下:

#!/bin/bash

NDK=/home/dennis/android-ndk-r9d

SYSROOT=$NDK/platforms/android-9/arch-arm/

TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64

function build_one

{

./configure \

--prefix=$PREFIX \

--enable-shared \

--disable-static \

--disable-doc \

--disable-ffserver \

--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


這個腳本文件有幾個地方需要注意:

(1) NDK,SYSROOT和TOOLCHAIN這三個環境變量一定要換成你自己機器裡的。

(2) 確保cross-prefix變量所指向的路徑是存在的。

給build_android.sh增加可執行權限:

$chmod+x build_android.sh

執行build_android.sh

$./build_android.sh

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

$make

$make install

至此,會在/home/dennis/ffmpeg-2.2目錄下生成一個android目錄,其中/home/dennis/ffmpeg-2.2/android/arm/lib目錄下的so庫文件如下:

-rwxr-xr-x 1 dennisdennis 55208 Mar 29 16:26libavdevice-55.so

-rwxr-xr-x 1 dennisdennis 632476 Mar 29 16:26 libavfilter-4.so

-rwxr-xr-x 1 dennisdennis 1442948 Mar 29 16:26 libavformat-55.so

-rwxr-xr-x 1 dennisdennis 7985396 Mar 29 16:26 libavcodec-55.so

-rwxr-xr-x 1 dennisdennis 83356 Mar 29 16:26libswresample-0.so

-rwxr-xr-x 1 dennisdennis 308636 Mar 29 16:26 libswscale-2.so

-rwxr-xr-x 1 dennisdennis 300580 Mar 29 16:26libavutil-52.so

注:以上列表去掉了符號鏈接文件和pkgconfig目錄。

第三步:創建一個普通的Android工程

    創建一個新的Android工程FFmpeg4Android 在工程根目錄下創建jni文件夾 在jni下創建prebuilt目錄,然後:

    (1) 將上面編譯成功的7個so文件放入到該目錄下;

    (2) 將/home/dennis/ffmpeg-2.2/android/arm/include下的所有頭文件夾拷貝到該目錄下.

      創建包含native方法的類,先在src下創建cn.dennishucd包,然後創建FFmpegNative.java類文件。主要包括加載so庫文件和一個native測試方法兩部分,其內容如下:

      package cn.dennishucd;
      public class FFmpegNative {
                      static{
                                      System.loadLibrary("avutil-52");
                                      System.loadLibrary("avcodec-55");
                                      System.loadLibrary("swresample-0");
                                      System.loadLibrary("avformat-55");
                                      System.loadLibrary("swscale-2");
                                      System.loadLibrary("avfilter-3");
                                      System.loadLibrary("ffmpeg_codec");
                      }
                      publicnative int avcodec_find_decoder(int codecID);
      }

        用javah創建.頭文件:

        進入bin/classes目錄,執行:javah-jni cn.dennishucd.FFmpegNative

        會在當前目錄產生cn_dennishucd_FFmpegNative.h的C頭文件;

          根據頭文件名,建立相同名字才C源文件cn_dennishucd_FFmpegNative.c

          在這個源文件中實現頭文件中定義的方法,核心部分代碼如下:

          JNIEXPORT jint JNICALLJava_cn_dennishucd_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)

          {

          return0;

          }

          else

          {

          return-1;

          }

          }

            編寫Android.mk,內容如下:

            LOCAL_PATH := $(callmy-dir)

            include $(CLEAR_VARS)

            LOCAL_MODULE :=avcodec-55-prebuilt

            LOCAL_SRC_FILES :=prebuilt/libavcodec-55.so

            include$(PREBUILT_SHARED_LIBRARY)

            include $(CLEAR_VARS)

            LOCAL_MODULE :=avdevice-55-prebuilt

            LOCAL_SRC_FILES :=prebuilt/libavdevice-55.so

            include$(PREBUILT_SHARED_LIBRARY)

            include $(CLEAR_VARS)

            LOCAL_MODULE :=avfilter-4-prebuilt

            LOCAL_SRC_FILES :=prebuilt/libavfilter-4.so

            include$(PREBUILT_SHARED_LIBRARY)

            include $(CLEAR_VARS)

            LOCAL_MODULE :=avformat-55-prebuilt

            LOCAL_SRC_FILES :=prebuilt/libavformat-55.so

            include$(PREBUILT_SHARED_LIBRARY)

            include $(CLEAR_VARS)

            LOCAL_MODULE := avutil-52-prebuilt

            LOCAL_SRC_FILES :=prebuilt/libavutil-52.so

            include$(PREBUILT_SHARED_LIBRARY)

            include $(CLEAR_VARS)

            LOCAL_MODULE := avswresample-0-prebuilt

            LOCAL_SRC_FILES :=prebuilt/libswresample-0.so

            include $(PREBUILT_SHARED_LIBRARY)

            include $(CLEAR_VARS)

            LOCAL_MODULE := swscale-2-prebuilt

            LOCAL_SRC_FILES :=prebuilt/libswscale-2.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-55-prebuilt avdevice-55-prebuilt avfilter-4-prebuiltavformat-55-prebuilt avutil-52-prebuilt

            include$(BUILD_SHARED_LIBRARY)

              編寫Application.mk[可省略] 編譯so文件

              打開cmd命令行,進入FFmpeg4Android\jni目錄下,執行如下命令:

              ndk-build

              截止本步驟完成,將在FFmpeg4Android根目錄下生成libs\armeabi目錄,該目錄除了包含上面的7個so之外,另外還生成了libffmpeg_codec.so文件。

                添加庫的加載方法

                在FFmpegNative類中增加如下加載so庫的代碼:

                static {

                System.loadLibrary("avutil-52");

                System.loadLibrary("avcodec-55");

                System.loadLibrary("swresample-0");

                System.loadLibrary("avformat-55");

                System.loadLibrary("swscale-2");

                System.loadLibrary("avfilter-3");

                System.loadLibrary("avdevice-55");

                System.loadLibrary("ffmpeg_codec");

                }

                  修改layout/main.xml,給TextView增加id,以便在代碼中操作它。
                  
                  
                    
                  

                  增加一個Activity實現類FFmpeg4AndroidActivity,在OnCreate方法中調用native函數將值傳給TextView控件,打包運行即可。FFmpeg4AndroidActivity代碼如下:

                  package cn.dennishucd;

                  import android.app.Activity;

                  import android.os.Bundle;

                  import android.widget.TextView;

                  public class FFmpeg4AndroidActivity extends Activity {

                  @Override

                  protectedvoid onCreate(Bundle savedInstanceState) {

                  super.onCreate(savedInstanceState);

                  setContentView(R.layout.main);

                  TextViewtv = (TextView)this.findViewById(R.id.textview_hello);

                  FFmpegNativeffmpeg = new FFmpegNative();

                  intcodecID = 28; //28 is the H264 Codec ID

                  intres = ffmpeg.avcodec_find_decoder(codecID);

                  if(res ==0) {

                  tv.setText("Success!");

                  }

                  else{

                  tv.setText("Failed!");

                  }

                  }

                  }

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


                  作者注:

                  [1] 本文編譯的方法主要參考了參考資料 [1] 中的思路,這裡要感謝作者的貢獻;

                  [2] 後面的測試過程是參考了ffmpeg-2.1.4中的decoding_encoding.c例子;

                  [3] 關於如何使用pre-built參考了參考資料 [2] 中的思路;

                  [4] 這只是移植過程第一步,後面還會進一步分析ffmpeg的接口來調用其編解碼庫.

                  [5]Android.mk文件應該還可以優化,這是後面的工作.

                  [6] 整個過程完成還是耗費了我不少精力,如有轉載請注明出處,多謝。本文的完整源代碼可以在我的CSDN資源(http://download.csdn.net/detail/gobitan/7132037)下載,最新版本可跟蹤我的github(https://github.com/dennishucd/FFmpeg4Android)。

                  參考資料:

                    http://www.roman10.net/how-to-build-ffmpeg-with-ndk-r9/http://www.ciaranmccormack.com/creating-a-prebuilt-shared-library-on-android-using-the-ndk/

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved