編輯:關於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工程
(1) 將上面編譯成功的7個so文件放入到該目錄下;
(2) 將/home/dennis/ffmpeg-2.2/android/arm/include下的所有頭文件夾拷貝到該目錄下.
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); }
進入bin/classes目錄,執行:javah-jni cn.dennishucd.FFmpegNative
會在當前目錄產生cn_dennishucd_FFmpegNative.h的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;
}
}
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)
打開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");
}
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)。
參考資料:
本文實例講述了Android編程之陰影(Shadow)制作方法。分享給大家供大家參考,具體如下:先看運行效果圖如下:陰影制作:包括各種形狀(矩形,圓形等等),以及文字等等
你看到微信上有朋友分享好友的未讀信息嗎!其實這個可以自己生成的哦!那麼微信好友未讀消息怎麼生成?微信好友未讀信息生成器給你帶來一種新的裝逼模式,你的微信聊天
我們公司做了一款使用百度錢包的移動網頁支付進行支付的產品,用戶通過百度錢包、百度糯米掃描我們產品的二維碼,選擇商品,點擊支付將會自動調用百度錢包進行支付,支付成功後返回成
最近比較忙,而且又要維護自己的博客,視頻和公眾號,也就沒仔細的梳理源碼的入門邏輯,今天也就來講一個源碼的玩法,各位看官,一起學習學習! 參考資料 官方教程:http:/