ffmpeg移植android
① 如何用Android NDK編譯FFmpeg
android的NDK開發需要在linux下進行:
因為需要把C/C++編寫的代碼生成能在arm上運行的.so文件,這就需要用到交叉編譯環境,而交叉編譯需要在linux系統下才能完成。
安裝android-ndk開發包,這個開發包可以在google android 官網下載: 通過這個開發包的工具才能將android jni 的C/C++的代碼編譯成庫
android應用程序開發環境: 包括eclipse、java、 android sdk、 adt等。
NDK編譯步驟:
a.選擇ndk自帶的例子hello-jni,我的位於E:android-ndk-r5sampleshello-jni(根據具體的安裝位置而定) 。
b.運行cygwin,輸入命令cd /cygdrive/e/android-ndk-r5/samples/hello-jni,進入到E:android-ndk-r5sampleshello-jni目錄。
c.輸入$NDK/ndk-build,執行成功後,它會自動生成一個libs目錄,把編譯生成的.so文件放在裡面。($NDK是調用我們之前配置好的環境變數,ndk-build是調用ndk的編譯程序)
d.此時去hello-jni的libs目錄下看有沒有生成的.so文件,如果有,ndk就運行正常啦。
② 如何在Android用FFmpeg+SDL2.0解碼聲音
一、創建一個VideoPicture結構體用來保存解碼出來的圖像;
二、添加數據隊列的初始化、添加以及讀取的函數;
三、audio_decode_frame():解碼音頻;
四、audio_callback(): 回調函數,向SDL緩沖區填充數據;
五、創建視頻刷新相關的函數;
六、添加視頻顯示函數;
七、分配顯示輸出內存空間;
八、解碼線程,將解碼器,建立音頻線,保存重要信息到數據結構中;
九、編寫Main函數用來調用解碼線程。
知識點延伸:
FFmpeg是一個開源免費跨平台的視頻和音頻流方案,屬於自由軟體,採用LGPL或GPL許可證(依據你選擇的組件)。它提供了錄制、轉換以及流化音視頻的完整解決方案。它包含了非常先進的音頻/視頻編解碼庫libavcodec,為了保證高可移植性和編解碼質量,libavcodec里很多codec都是從頭開發的。FFmpeg在Linux平台下開發,但它同樣也可以在其它操作系統環境中編譯運行。
SDL2.0(Simple DirectMedia Layer)是一套開放源代碼的跨平台多媒體開發庫,使用C語言寫成。SDL多用於開發游戲、模擬器、媒體播放器等多媒體應用領域。SDL內置了調用OpenGL的函數。SDL提供了數種控制圖像、聲音、輸出入的函數,讓開發者只要用相同或是相似的代碼就可以開發出跨多個平台(Linux、Windows、Mac OS X等)的應用軟體。
③ 如何用Android NDK編譯FFmpeg
一、安裝cygwin、配置ndk和下載ffmpeg源碼
這步就不說了,網上很多教程,再次聲明本教程只針對ndk R4這個版本。需要說明的是,本人在cygwin安裝路徑下的.bash_profile文件中指定的NDK路徑如下所示。因為本人裝了好幾個NDK,因此後面的R4隻是個標示。
NDK_R4=/cygdrive/d/android-ndk-r4
export NDK_R4
二、編譯前准備和編譯
1、因為R4這個NDK比較舊,交叉編譯的時候需要在一個Android環境中,那簡單,創建一個Android空項目,把整個項目拷出來,在項目下建立一個文件夾jni,把ffmpeg0.6.6的源碼拷進去。左圖,HelloJni就是我新建的一個項目,Android.mk這時候你還沒有,先不用管。右圖ffmpeg-0.6.6文件夾的內容要跟我一樣,直接就是代碼。我這里的ffmpeg_cywin這個文件夾是隨便建的,放哪裡無所謂的。
2、在ffmpeg-0.6.6下建立一個文件config.sh,內容如下所示。需要注意的是,unix下的換行符和windows下是不一樣,如果直接拷貝到windows下的記事本,後面執行這個config.sh的時候會出問題,這里我用的是notepad++編輯的,在編輯->檔案格式轉換->轉換為UNIX格式。(注意,後面的所有的Android.mk的編輯都有此要求)。
簡單說一下這個config.sh,PREBUILT和PLATFORM根據你安裝ndk的位置而不同,config.sh其實是一個腳本,執行這個腳本的時候又調用了另外一個腳本configure,configure主要是根據編譯選項(下面enable disable那些),生成相應的編譯配置,就是說你想要編譯ffmpeg什麼模塊就自己定製編譯選項的內容。基本上這個文件只要修改一下PREBUILT和PLATFORM就行,其他都不用改。
#!/bin/bash
export PREBUILT=D://android-ndk-r4/build/prebuilt/windows/arm-eabi-4.4.0
export PLATFORM=D://android-ndk-r4/build/platforms/android-8/arch-arm
./configure --target-os=linux \
--arch=arm \
--enable-version3 \
--enable-gpl \
--enable-nonfree \
--disable-stripping \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffserver \
--disable-ffprobe \
--disable-encoders \
--disable-muxers \
--disable-devices \
--disable-protocols \
--enable-protocol=file \
--enable-avfilter \
--disable-network \
--disable-mpegaudio-hp \
--disable-avdevice \
--enable-cross-compile \
--cc=$PREBUILT/bin/arm-eabi-gcc \
--cross-prefix=$PREBUILT/bin/arm-eabi- \
--nm=$PREBUILT/bin/arm-eabi-nm \
--extra-cflags="-fPIC -DANDROID" \
--disable-asm \
--enable-neon \
--enable-armv5te \
--extra-ldflags="-Wl,-T,$PREBUILT/arm-eabi/lib/ldscripts/armelf.x -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtbegin.o $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtend.o -lc -lm -ldl"
3、修改configure文件,找到下圖的內容,修改成我這樣,這個是用來存放執行腳本過程的臨時文件的,我這里用的是D://NDK,你可以設置其他地方,但是要先創建好這個文件夾,放哪裡無所謂的。
4、然後在cywin中進入ffmpeg0.6.6文件夾,執行chmod -x config.sh,然後執行./config,此過程需要一定的時間。如果這一步出現問題,很有可能是你config.sh中的PREBUILT和PLATFORM的路徑設置不對,或者是你拷貝內容到config.sh的時候沒有在UNIX格式下。執行完如下圖所示。
5、在ffmpeg-0.6.6下會生成一個config.h文件,編輯它,找到#define restrict restrict這一行,把它改成#define restrict
6、在libavutil/libm.h下,把所有static的方法注釋掉或者直接刪掉。
7、修改libavcodec,libavfilter,libavformat,libavutil,libpostproc和libswscale目錄的MakeFile文件,每個文件中,刪除語句
include $( SUBDIR ) ../config.mak 和 include $ (SUBDIR) .. / subdir.mak。
libavcodec下的makefile中搜索inverse.o,把它所在的那一行刪掉,要不編譯的時候會沖突。
8、在ffmpeg-0.6.6文件夾下,創建av.mk文件(UNIX格式),內容如下:
#LOCAL_PATH is one of libavutil, libavcodec, libavformat, or libswscale
#include $(LOCAL_PATH)/../config-$(TARGET_ARCH).mak
include $(LOCAL_PATH)/../config.mak
OBJS :=
OBJS-yes :=
MMX-OBJS-yes :=
include $(LOCAL_PATH)/Makefile
# collect objects
OBJS-$(HAVE_MMX) += $(MMX-OBJS-yes)
OBJS += $(OBJS-yes)
FFNAME := lib$(NAME)
FFLIBS := $(foreach,NAME,$(FFLIBS),lib$(NAME))
FFCFLAGS = -DHAVE_AV_CONFIG_H -Wno-sign-compare -Wno-switch -Wno-pointer-sign
FFCFLAGS += -DTARGET_CONFIG=\"config-$(TARGET_ARCH).h\"
ALL_S_FILES := $(wildcard $(LOCAL_PATH)/$(TARGET_ARCH)/*.S)
ALL_S_FILES := $(addprefix $(TARGET_ARCH)/, $(notdir $(ALL_S_FILES)))
ifneq ($(ALL_S_FILES),)
ALL_S_OBJS := $(patsubst %.S,%.o,$(ALL_S_FILES))
C_OBJS := $(filter-out $(ALL_S_OBJS),$(OBJS))
S_OBJS := $(filter $(ALL_S_OBJS),$(OBJS))
else
C_OBJS := $(OBJS)
S_OBJS :=
endif
C_FILES := $(patsubst %.o,%.c,$(C_OBJS))
S_FILES := $(patsubst %.o,%.S,$(S_OBJS))
FFFILES := $(sort $(S_FILES)) $(sort $(C_FILES))
9、在jni文件夾下,創建Android.mk(UNIX格式),內容如下:
include $(all-subdir-makefiles)
10、在ffmpeg-0.6.6文件夾下,創建Android.mk,內容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale
LOCAL_MODULE := ffmpeg
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
11、在ffmpeg-0.6.6\libavformat下,創建Android.mk,內容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_CFLAGS += -include "string.h" -Dipv6mr_interface=ipv6mr_ifindex
LOCAL_LDLIBS := -lz
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)
12、在ffmpeg-0.6.6\libavcodec下,創建Android.mk,內容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_LDLIBS := -lz
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)
13、在ffmpeg-0.6.6\libavfilter、libavutil、libpostproc和libswscale下,創建Android.mk,內容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)
14、然後在jni目錄下,運行$NDK_R4/ndk-build -B,這里的命令需要根據你自己的情況修改,然後就開始編譯了。過程需要10來分鍾,成功之後,會在libs下生產libffmpeg.so。如果編譯出來的libffmpeg.so只有1.5k,得如下修改一下NDK,再重新編譯。
把下面紅色部分加到NDK的build/core/build-binary.mk里:
LOCAL_STATIC_LIBRARIES := $(call strip-lib-prefix,$(LOCAL_STATIC_LIBRARIES))
LOCAL_STATIC_WHOLE_LIBRARIES := $(call strip-lib-prefix,$(LOCAL_STATIC_WHOLE_LIBRARIES))
...
static_libraries := $(call map,static-library-path,$(LOCAL_STATIC_LIBRARIES))
static_whole_libraries := $(call map,static-library-path,$(LOCAL_STATIC_WHOLE_LIBRARIES))
...
$(call mole-add-static-depends,$(LOCAL_MODULE),$(LOCAL_STATIC_LIBRARIES))
$(call mole-add-static-depends,$(LOCAL_MODULE),$(LOCAL_STATIC_WHOLE_LIBRARIES))
...
$(LOCAL_BUILT_MODULE): $(static_libraries) $(static_whole_libraries) $(shared_libraries)
...
$(LOCAL_BUILT_MODULE): PRIVATE_STATIC_LIBRARIES := $(static_libraries)
$(LOCAL_BUILT_MODULE): PRIVATE_WHOLE_STATIC_LIBRARIES := $(static_whole_libraries)
接著再將最外層ffmpeg/Android.mk裡面的LOCAL_STATIC_LIBRARIES改成LOCAL_STATIC_WHOLE_LIBRARIES
④ Ubuntu 環境 編譯 ffmpeg移植android 的問題!
到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目錄。