Android/NDK環境下FFmpeg及AAC,MP3,X264的編譯

來源:互聯網
上載者:User

標籤:

本篇介紹在Android/Ndk環境下FFmpeg的編譯及使用, FFmpeg內建了H264、AAC、MP3的解碼器,但卻沒有(或沒有好的)相應的編碼器。相應的編碼器需要使用第三方庫。推薦使用的第三方庫為x264(H264編碼) 、FDK_AAC(AAC編碼),lame(MP3編碼)。

在順序上,應該先編譯好第三方庫,最後再編譯FFmpeg庫。

【本書說明:本文邵發,本文選自《FFmpeg視音頻編程指南》。有關本書的詳細資料請訪問官網:http://www.afanihao.cn 】

【權利聲明:作者保留本文的全部權利。作者授權任何人都可以自由轉載本文,但轉載時必須遵守以下限制:①轉載時必須全文轉載,不得有任何修改,包括“權利聲明”和“本書說明”部分 ② 僅限於網路轉載,即最終結果公佈於網路上。凡是不遵守以上兩條的轉載行為視為侵權行為。除非本人允許,任何人不得將本文內容用於任何的其他用途。】

1.1        NDK環境的準備

本篇的示範樣本使用的是android-ndk-r8e版本,但理論上也適用於更新的NDK版本。為了讓你的編譯過程極其順利,應該對NDK作以下改動:

進入目錄 platforms/android-14/arch-arm/usr/lib

應該可以看到一些檔案,例如 crtbegin_dynamic.o ,crtbegin_static.o  crtend_so.o , crtbegin_so.o ,crtend_android.o,等等。

 

把這個目錄下的所有檔案拷貝到

\toolchains\arm-linux-androideabi-4.6\prebuilt\linux-x86\lib\gcc\arm-linux-androideabi\4.6

 

否則在連結的時候ld會提示“找不到crtbegin_so.o和crtend_so.o”的錯誤。

 

應該把NDK的相關工具都把加PATH環境變數中,例如,

#!/bin/sh

export PATH=$PATH:/opt/ndk/android-ndk-r8e/

export PATH=$PATH: /opt/ndk/android-ndk-r8e/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/

 

1.2        FDK_AAC庫的編譯

如果你不打算使用AAC編碼的功能,則可以略過本節。目前(2015年3月),fdk_aac的官方發布地址是在source_forge上,也許以後會變,作者可以自行搜尋。目前地址為:

http://sourceforge.net/projects/opencore-amr/files/fdk-aac/

本文使用的版本是fdk-aac-0.1.3,為減少不必要的麻煩,讀者也請下載這個包。

 

1.2.1         修改configure指令碼

修改指令碼的目的是去除目標庫的版本號碼,以適應Android/NDK的對庫的載入要求。簡單地講,這是因為在Android/NDK項目的java代碼中,使用System.loadLibrary()函數來載入so檔案時,動態庫是不能加版本號碼的。

在fdk_aac的configure指令碼裡找到如下的行:

# This must be glibc/ELF.

linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)

  version_type=linux # correct to gnu/linux during the next big refactor

  need_lib_prefix=no

  need_version=no

  library_names_spec=‘${libname}${shared_ext}   ${libname}${shared_ext}   $libname${shared_ext}‘

  soname_spec=‘${libname}${shared_ext}‘

  finish_cmds=‘PATH="\$PATH:/sbin" ldconfig -n $libdir‘

  shlibpath_var=LD_LIBRARY_PATH

  shlibpath_overrides_runpath=no

 

把粗體字部分替換為:

library_names_spec=‘$libname${shared_ext} $libname.a‘

 

1.2.2         建立配置指令碼

在源碼的根目錄下建議一個myconfig.sh指令碼。這是一個SHELL指令碼,要求讀者自己稍微瞭解一些SHELL指令碼的寫法。在這裡只強調一點:SHELL指令碼是以\n結尾的,如果你是在windows下面編輯的,那麼應該用dos2unix來把文本的分行符號轉成unix格式。

為了避免不必要的麻煩,把NDK解壓縮在/opt/ndk/android-ndk-r8e目錄,並將FDK的輸出目錄--prefix設定在/opt/ndk/openlib目錄下。讀者第一遍操作時,不要擅自修改目錄,必須在熟練掌握之後再自行修改目錄。

myconfig.sh裡面內容為:

#!/bin/sh

 

export CC=arm-linux-androideabi-gcc

export CXX=arm-linux-androideabi-g++

export AR=arm-linux-androideabi-ar

export LD=arm-linux-androideabi-ld

export AS=arm-linux-androideabi-gcc

 

export CFLAGS=" --sysroot=/opt/ndk/android-ndk-r8e/platforms/android-14/arch-arm -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 "

export CXXFLAGS=" --sysroot=/opt/ndk/android-ndk-r8e/platforms/android-14/arch-arm -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 "

 

export LDFLAGS=" -L/opt/ndk/android-ndk-r8e/platforms/android-14/arch-arm/usr/lib  -march=armv7-a -Wl,--fix-cortex-a8 "

 

./configure --enable-static --prefix=/opt/ndk/openlib --host=arm-linux

 

1.2.3         編譯

如果你嚴格按照以上的操作進行,那麼編譯過程會非常簡單。Linux下的開源軟體一般都是分為三步編譯 configure , make,make install,而fdk_aac也不例外。

1)   ./myconfig.sh

執行上述配置指令碼,開始配置

2)  make

3)  make  install

一切正常,將在/opt/ndk/openlib下存放輸出庫及標頭檔,注意這個庫是去掉版本號碼的libfdk-aac。顯然,Android/NDK的程式員會更喜歡不帶版本號碼的庫。

 

1.3        LAME-MP3的編譯

如果你不打算在項目中使用mp3編碼,則略過本節。

本節介紹lame的編譯,但遺憾的是,其動態庫沒有辦法去掉版本號碼。所以本方法產生的目標動態庫是帶版本號碼的。

1.3.1         建立配置指令碼

建立設定檔myconfig.sh,內容如下,

#!/bin/sh

 

export CC=arm-linux-androideabi-gcc

export CXX=arm-linux-androideabi-g++

export AR=arm-linux-androideabi-ar

export LD=arm-linux-androideabi-ld

export CFLAGS=" --sysroot=/opt/ndk/android-ndk-r8e/platforms/android-14/arch-arm "

export LDFLAGS=" -L/opt/ndk/android-ndk-r8e/platforms/android-14/arch-arm/usr/lib  "

./configure --enable-static --prefix=/opt/ndk/openlib --host=arm-linux

 

1.3.2         編譯

1)   ./myconfig.sh

執行上述配置指令碼,開始配置

2)  make

3)  make  install

一切正常,將在/opt/ndk/openlib下存放輸出庫及標頭檔。

 

1.4        x264的編譯

x264屬於VLC的一部分,當前的源碼位置為:

ftp://ftp.videolan.org/pub/videolan/x264/snapshots/

本篇使用的源碼版本為x264-snapshot-20140723-2245-stable.tar.bz2

1.4.1         修改configure指令碼

這一步的目的是使輸出的庫檔案不帶版本號碼。如果你堅持認為版本號碼不影響你的開發,則忽略本小節。

找到這一位置:

    else

        echo "SOSUFFIX=so" >> config.mak

        echo "SONAME=libx264.so.$API" >> config.mak

        echo "SOFLAGS=-shared -Wl,-soname,\$(SONAME) $SOFLAGS" >> config.mak

    fi

 

將粗體字修改為:(即去掉$API尾碼)

echo "SONAME=libx264.so" >> config.mak

 

1.4.2         建立配置指令碼

建立myconfig.sh配置指令碼,

#!/bin/sh

export CC=arm-linux-androideabi-gcc

export CXX=arm-linux-androideabi-g++

export AR=arm-linux-androideabi-ar

export LD=arm-linux-androideabi-ld

export AS=arm-linux-androideabi-gcc

export CFLAGS=" --sysroot=/opt/ndk/android-ndk-r8e/platforms/android-14/arch-arm -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"

export LDFLAGS=" -L/opt/ndk/android-ndk-r8e/platforms/android-14/arch-arm/usr/lib -march=armv7-a -Wl,--fix-cortex-a8 "

./configure --enable-static --enable-shared --prefix=/opt/ndk/openlib --host=arm-linux 

 

1.4.3         編譯

1)   ./myconfig.sh

執行上述配置指令碼,開始配置

2)  make

3)  make  install

 

1.5        FFmpeg的編譯

本樣本使用的是FFmpeg2.1.3版本,可以從其官網ffmpeg.org上下載。如果不需要x264/aac/lame,可以直接進行本節的編譯。

1.5.1         修改configure指令碼

本節的目的是讓輸出的庫不含有版本號碼。

先找到configure的如下位置:

SHFLAGS=‘-shared -Wl,-soname,$$(@F)‘

LIBPREF="lib"

LIBSUF=".a"

FULLNAME=‘$(NAME)$(BUILDSUF)‘

LIBNAME=‘$(LIBPREF)$(FULLNAME)$(LIBSUF)‘

SLIBPREF="lib"

SLIBSUF=".so"

SLIBNAME=‘$(SLIBPREF)$(FULLNAME)$(SLIBSUF)‘

SLIBNAME_WITH_VERSION=‘$(SLIBNAME).$(LIBVERSION)‘

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_VERSION=‘$(SLIBNAME)‘

SLIBNAME_WITH_MAJOR=‘$(SLIBNAME)‘

LIB_INSTALL_EXTRA_CMD=‘$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"‘

SLIB_INSTALL_NAME=‘$(SLIBNAME_WITH_VERSION)‘

SLIB_INSTALL_LINKS=

 

1.5.2         修改配置指令碼

建立myconfig.sh

export NDK_ROOT=/opt/ndk

export TMPDIR=/tmp

./configure  --prefix=$NDK_ROOT/ffmpeg --sysroot=$NDK_ROOT/android-ndk-r8e/platforms/android-14/arch-arm  --cross-prefix=arm-linux-androideabi-  --target-os=linux --arch=arm   --extra-cflags="-I$NDK_ROOT/openlib/include -fPIC  " --extra-ldflags=-L$NDK_ROOT/openlib/lib   --disable-programs --disable-doc --enable-shared --enable-cross-compile  --enable-gpl --enable-nonfree --enable-libx264 --enable-libmp3lame --enable-libfdk-aac

 

這個指令碼中是把x264, fdk-aac, lame全部編譯上了,你可以視自己的情況來修改。

1.5.3         編譯

1)   ./myconfig.sh

執行上述配置指令碼,開始配置

2)  make

3)  make  install

 

1.6        在Android.mk中引用FFmpeg庫1.6.1         使用靜態庫

推薦使用靜態庫。需要注意,FFmpeg庫的靜態庫引用順序是不能隨便寫的,為了避免不必要的麻煩,請照抄以下配置。

在你的Android.mk中添加以下幾行(見黑體字部分)

LOCAL_LDLIBS    += -llog -lz

 

# ffmpeg

FFMPEG=/opt/ndk

LOCAL_CFLAGS += -I$(FFMPEG)/include

LOCAL_LDLIBS += -l$(FFMPEG)/lib/libavformat.a

LOCAL_LDLIBS += -l$(FFMPEG)/lib/libavcodec.a

LOCAL_LDLIBS += -l$(FFMPEG)/lib/libavdevice.a

LOCAL_LDLIBS += -l$(FFMPEG)/lib/libswresample.a

LOCAL_LDLIBS += -l$(FFMPEG)/lib/libavdevice.a

LOCAL_LDLIBS += -l$(FFMPEG)/lib/libswscale.a

LOCAL_LDLIBS += -l$(FFMPEG)/lib/libpostproc.a

LOCAL_LDLIBS += -l$(FFMPEG)/lib/libavutil.a

 

# fdk_aac

LOCAL_LDLIBS += -l/opt/ndk/lib/libfdk-aac.a

LOCAL_LDLIBS += -l/opt/ndk/lib/libmp3lame.a

LOCAL_LDLIBS += -l/opt/ndk/lib/ libx264.a

 

include $(BUILD_SHARED_LIBRARY)

 

1.6.2         使用動態庫

不推薦使用動態庫,此過程過於複雜。要注意的有兩點:①編譯的時候,必須去除庫的版本號碼 ② 在Java代碼中載入的時候,要注意載入的順序。

以下可以加在Android.mk中,但是僅供參考,遇到自己問題需要自己調試

# ffmpeg

FFMPEG=f:/Ndk/ffmpeg

LOCAL_CFLAGS += -I$(FFMPEG)/include

LOCAL_LDLIBS += -L$(FFMPEG)/lib

LOCAL_LDLIBS += -lavformat -lavcodec  -lswresample -lswscale  -lavutil -lavfilter

 

include $(BUILD_SHARED_LIBRARY)

 

1.6.3         在C++中使用ffmpeg

ffmpeg的庫是按C編譯的,裡面的符號都是C格式,因此,若在C++中使用,還是要使用extern "C"這種技術。相關文法請參考《C/C++文法指南》(邵發,官網http://www.afanihao.cn)。

為了大家的方便,在/opt/ndk/ffmpeg/include下建立一個ffmpeg.h,內容為:

#ifndef _FFMPEG_H

#define _FFMPEG_H

 

#ifdef __cplusplus

extern "C" {

 

#define INT64_C(val) val##LL

#define UINT64_C(val) val##ULL

 

#endif

 

#include <libavcodec/avcodec.h>

#include <libavformat/avformat.h>

#include <libswscale/swscale.h>

#include <libavutil/avutil.h>

#include <libavutil/opt.h>

#include <libavutil/imgutils.h>

#include <libswresample/swresample.h>

 

#include <libavutil/error.h>

#include <libavfilter/avfiltergraph.h>

#include <libavfilter/avcodec.h>

#include <libavfilter/buffersink.h>

#include <libavfilter/buffersrc.h>

 

#ifdef __cplusplus

}

#endif

 

#endif

 

然後在C++代碼中直接#include "ffmpeg.h"就可以了。

 

Android/NDK環境下FFmpeg及AAC,MP3,X264的編譯

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.