Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 移植 ffmpeg (二) 測試用例

android 移植 ffmpeg (二) 測試用例

編輯:關於Android編程

這一章將重點討論怎麼在應用中加入ffmpeg組件。

所有測試都將在 Android Studio工具中進行。

測試例子源地址:https://github.com/roman10/android-ffmpeg-tutorial

本例子是在android-ffmpeg-tutorial01基礎上進行了簡單調整。

一. 工程目錄結構

\   目錄中主要有6個地方進行變動,所以逐一說明一下。  

1 assets路徑

測試視頻存放地, 目前測試視頻為1.mp4. 通過命令 ffmpeg -i 1.mp4 得到視頻信息。 視頻信息為:(時長10.04秒, 比特率: 352Kb/s, 分辨率: 640*360) \

2 Java 文件目錄

MainActivity.java 主Java程序, 後面會對程序進行說明

Utils.java 工具類。提供了文件拷貝功能,程序中主要用於把1.mp4導入到指定目錄

3 NDK工作目錄 jni文件夾

tutorial01.c: 測試ffmpeg源文件,主要功能,調用ffmpeg sdk分析視頻,並把指定的圖片上傳給Java代碼。後面會進一步說明。 Applicaton.mk文件: 定義了應用程序編譯的基本信息, 非必要。主要告訴ndk要編譯的指令集,及對應的Android平台。 Android NDK編譯系統支持3種API: armeabi, armeabi-v7a和x86,分別對應 ARMv5TE, ARMv7-A和X86指令集的CPU.默認支持armeabi. Android.mk: NDK 編譯命令文件,用來告訴NDK如何編譯此項目的。 常用的命令在上一篇(android 移植 ffmpeg (一))文章中已經有了說明,這裡僅補充沒有說明的。 LOCAL_LDLIBS:=-llog-ljnigraphics-lz linker flags。 可以用它來添加系統庫 LOCAL_SHARED_LIBRARIES:=libavformatlibavcodeclibswscalelibswresamplelibavutil 要鏈接到本模塊的動態庫。 $(callimport-module,ffmpeg/android) import-module: 允許尋找並inport其它modules到本Android.mk中來。它會從NDK_MODULE_PATH尋找指定的模塊名。 使用方法: $(callimport-module,) 這裡就是把ffmpeg/android的模塊導入進來,即把ffmpeg/android/下的Android.mk導入進本模塊來。 這樣上面LOCAL_SHARED_LIBRARIES指字的庫名才能找到。

4 NDK生成目錄 libs目錄

一般NDK生成目錄位於./libs/armeabi/目錄下 裡面有目錄 armeabi, 即生成支持ARMv5TE指令集的CPU的庫。這些庫可直接在ARMv5TE指令集的CPU上去行。 如果要設置成支持多個指令集的話,可在 Application.mk中進行設置,則可生成多個文件夾,每個文件夾中的文件名一樣。

5 build.gradle文件配置

需要配置相應的NDK配置 \

6 local.properties 文件匹配

需要配置SDK,NDK的路徑名。我的機器的配置是: \ NDK的配置還可以通過如下方法進行設置: File->Project Structure… 快捷建(Command + ;)進行設置。 \

 

 

二. 生成代碼文件

生成庫文件:

需要通過命令行來生成

命令行運行到main目錄下,調用ndk_build.

 

172-15-70-196:main jerome$ pwd
/Users/jerome/dev/ffmpeg/android-ffmpeg-tutorial01/app/src/main
172-15-70-196:main jerome$ /Users/jerome/dev/android-ndk-r12b/ndk-build 
[armeabi] Compile thumb  : tutorial01 <= tutorial01.c
jni/tutorial01.c: In function 'naMain':
jni/tutorial01.c:117:2: warning: 'codec' is deprecated (declared at /Users/jerome/dev/android-ndk-r12b/sources/ffmpeg/android/include/libavformat/avformat.h:881) [-Wdeprecated-declarations]
  pCodecCtx=pFormatCtx->streams[videoStream]->codec;
  ^
[armeabi] SharedLibrary  : libtutorial01.so
[armeabi] Install        : libtutorial01.so => libs/armeabi/libtutorial01.so
[armeabi] Install        : libavformat-57.so => libs/armeabi/libavformat-57.so
[armeabi] Install        : libavcodec-57.so => libs/armeabi/libavcodec-57.so
[armeabi] Install        : libswscale-4.so => libs/armeabi/libswscale-4.so
[armeabi] Install        : libswresample-2.so => libs/armeabi/libswresample-2.so
[armeabi] Install        : libavutil-55.so => libs/armeabi/libavutil-55.so
172-15-70-196:main jerome$ 

 

編譯運行apk

直接運行調試。這過程中會碰到如下問題, 需要修改ffmpeg源碼,再重新編譯ffmpeg: cannot locate symbol "log2f" referenced by "libavcodec-57.so".. cannot locate symbol "log2" referenced by "libavcodec-57.so".. 原因: 這個跟ndk與android版本有關。 解決辦法: 修改 ./libavutil/libm.h裡面的定義,不再判斷是否已經存在函數。使用重新定義
//#if !HAVE_LOG2
//#undef log2
#define log2(x) (log(x) * 1.44269504088896340736)
//#endif /* HAVE_LOG2 */

//#if !HAVE_LOG2F
//#undef log2f
#define log2f(x) ((float)log2(x))
//#endif /* HAVE_LOG2F */
  cannot locate symbol "atof" referenced by "libavformat-57.so"... 原因:android的stdlib.h中atof是內聯的, 外部模塊不能直接使用。跟android版本有關。 解決辦法:將所有的atof改成strtod     修改完之後: 1 重新生成ffmpeg(調用 ./build_andriod_mac.sh), 2 調用ndk_build生成C庫文件。 3. 運行android Java代碼。   4. 點擊界面的start按鈕,生成圖片。   至此,程序運行OK.  

 

三. NDK開發運行流程

ndk-build 編譯流程:   1. 查找環境變量NDK_PROJECT_PATH,如果用戶沒有設置,就根據如下流程查找! /Users/jerome/dev/android-ndk-r12b/build/core/build-local.mk中的代碼部分
ifndef NDK_PROJECT_PATH
    ifneq (,$(strip $(wildcard AndroidManifest.xml)))
        NDK_PROJECT_PATH := .
    else
        ifneq (,$(strip $(wildcard jni/Android.mk)))
            NDK_PROJECT_PATH := .
        endif
    endif
endif
ifndef NDK_PROJECT_PATH
    NDK_PROJECT_PATH := $(call find-project-dir,.,jni/Android.mk)
endif
ifndef NDK_PROJECT_PATH
    NDK_PROJECT_PATH := $(call find-project-dir,.,AndroidManifest.xml)
endif
說明:就是在當前目錄及父目錄中查找文件:AndroidManifest.xml 或jni/Android.mk 文件,如果找到,就把找到的目錄賦給NDK_PROJECT_PATH, 如果沒找到,就直接報錯。Android NDK: Could not find application project directory !     2. 查找環境變量APP_BUILD_SCRIPT: 如果沒設置,就運行如下代碼。 在/Users/jerome/dev/android-ndk-r12b/build/core/add-application.mk 中
 _build_script := $(strip $(wildcard $(APP_PROJECT_PATH)/jni/Android.mk))
    ifndef _build_script
        $(call __ndk_info,There is no Android.mk under $(APP_PROJECT_PATH)/jni)
        $(call __ndk_info,If this is intentional, please define APP_BUILD_SCRIPT to point)
        $(call __ndk_info,to a valid NDK build script.)
        $(call __ndk_error,Aborting...)
    endif
    APP_BUILD_SCRIPT := $(_build_script)
說明: 如果沒找到APP_BUILD_SCRIPT的定義,就查找APP_PROJECT_PATH下的jni/Android.mk, 如果找到就賦值給APP_BUILD_SCRIPT。如果沒有找到,就報錯。Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/Android.mk   這裡查找的是APP_PROJECT_PATH, 與1中的NDK_PROJECT_PATH的關系如下(core/add-application.mk 中)。
APP_PROJECT_PATH := $(strip $(APP_PROJECT_PATH))
ifndef APP_PROJECT_PATH
    APP_PROJECT_PATH := $(NDK_PROJECT_PATH)
endif
如果定義了環境變量APP_PROJECT_PATH, 就使用定義的值,如果沒有就使用NDK_PROJECT_PATH的值。   3. 加載其它模塊Android.mk文件 在APP_BUILD_SCRIPT中查找是否有如下語句,有,則加載對應的庫文件
$(call import-module,ffmpeg/android)
查找邏輯是通過查找環境變量:NDK_MODULE_PATH下的對應模塊的Android.mk文件, 上例中就是查找 ffmpeg/android/Android.mk文件。如果找不到就報錯。Android NDK: jni/Android.mk: Cannot find module with tag 'ffmpeg/android' in import path NDK_MODULE_PATH 是可以有多個值。看腳本(core/setup-imports.mk)
NDK_MODULE_PATH := $(strip $(NDK_MODULE_PATH))
ifdef NDK_MODULE_PATH
  ifneq ($(words $(NDK_MODULE_PATH)),1)
    $(call __ndk_info,ERROR: You NDK_MODULE_PATH variable contains spaces)
    $(call __ndk_info,Please fix the error and start again.)
    $(call __ndk_error,Aborting)
  endif
endif

$(call import-init)
$(foreach __path,$(subst $(HOST_DIRSEP),$(space),$(NDK_MODULE_PATH)),\
  $(call import-add-path,$(__path))\
)
$(call import-add-path-optional,$(NDK_ROOT)/sources)
$(call import-add-path-optional,$(NDK_ROOT)/../development/ndk/sources)
由上腳本可知, 如果設置了NDK_MODULE_PATH,則就在NDK_MODULE_PATH中查找,如果沒有設置,那就是$(NDK_ROOT)/sources目錄中查找(還記得嘛,這也是我們編譯ffmpeg存放的目錄!),還就有是在$(NDK_ROOT)/../development/ndk/sources目錄中查找! $(NDK_ROOT)目錄就是ndk-build運行的目錄, 如果用戶不確定, 可直接設置環境變量: 1. vim ~/.bash_profile 2. 添加 export NDK_ROOT=/Users/jerome/dev/android-ndk-r12b 3. source .bash_profile     4. 編譯合成後的Android.mk文件,生成指定的結果文件。     這樣 ndk-build的運行邏輯就清晰了。通過設置主要環境變量, 就可以實現模塊化編程。 NDK_ROOT: 代碼根目錄, 默認為ndk-build所在的目錄。 NDK_PROJECT_PATH: 默認為ndk-build運行的目錄。 APP_PROJECT_PATH: 保存腳本的路徑 APP_BUILD_SCRIPT: 腳本路徑 NDK_MODULE_PATH: 模塊路徑, 用戶定義的路徑 還有兩個系統模塊路徑:$(NDK_ROOT)/sources,$(NDK_ROOT)/../development/ndk/sources。   Gradle打包流程就不分析了。  

四. 後記

  本篇主要讓程序運行起來,並分析ndk-build的邏輯,下一篇,將重點說明程序結構,及代碼流程。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved