編輯:關於Android編程
這一章將重點討論怎麼在應用中加入ffmpeg組件。
所有測試都將在 Android Studio工具中進行。
測試例子源地址:https://github.com/roman10/android-ffmpeg-tutorial
本例子是在android-ffmpeg-tutorial01基礎上進行了簡單調整。
MainActivity.java 主Java程序, 後面會對程序進行說明
Utils.java 工具類。提供了文件拷貝功能,程序中主要用於把1.mp4導入到指定目錄
./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的邏輯,下一篇,將重點說明程序結構,及代碼流程。
最近在研究android自定義控件屬性,學到了TypedArray以及attrs。大家也可以結合《理解Android中的自定義屬性》這篇文章進行學習,後續一篇還有應用。1
在小米2016夏季新品發布會上,正式發布了小米Max,與小米5一樣,小米Max也支持全網通,並支持雙卡雙待。最大的特點就是,小米Max配有6.44英寸巨屏,
目前本書已上傳到百度閱讀, 在百度中搜索[Anroid Studio實用指南]便可以找到本書.什麼是演示模式?顧名思義,當你想給別人演示你的代碼時就會用到這個演示模式.演
Android應用框架鼓勵開發者在開發應用時重用組件,本文將闡述如何用組件構建應用程序以及如何用intent將組件聯系起來。如需閱讀官方原文,請您點擊這個鏈接:《App