前言
最近在學習android NDK開發(fā)相關(guān)內(nèi)容,借ffmpeg練練手。ffmpeg是做音視頻方面功能的基礎(chǔ),后面會隨著個人的學習更新一系列ffmpeg博客,防止自己遺忘。
這個系列博客主要目的是基于ffmpeg通過NDK開發(fā)的方式完成一個基本的視頻播放器。
本篇博客主要實現(xiàn)了 ffmpeg編譯 以及 引入 android 項目成功調(diào)用 靜態(tài)庫方法顯示版本號。
必備基礎(chǔ)
- c、c++基礎(chǔ)語法;Cmake基礎(chǔ)(常用配置、常量);
- NDK JNI基礎(chǔ)(熟悉java/kotlin 、c++ 互調(diào));
- kotlin基礎(chǔ)(android 項目全部使用kotlin編寫);
- linux常用命令、shell腳本基礎(chǔ)語法;
準備工作
編譯ffmpeg時使用Linux或者Mac都可以;如果是Mac需要安裝gcc,使用gcc -v輸出版本號即為成功。
ffmpeg(4.0.2)
ffmpeg全版本下載地址:
http://www.ffmpeg.org/releases/
NDK(android-ndk-r17c)
NDK歷史版本下載地址:
https://developer.android.google.cn/ndk/downloads/older_releases
ffmpeg下載完成后解壓縮;進入ffmpeg解壓后到目錄
cd ./ffmpeg-4.0.2
ffmpeg編譯時有很多命令參數(shù),查看命令參數(shù)命令:
./configure --help
編寫ffmpeg編譯腳本
為了方便直接在 ffmpeg-4.0.2 目錄里新建shell腳本
vim ./ffmpeg-4.0.2/build_ffmpeg_4.0.2.sh
輸入以下內(nèi)容;
注意:每一行腳本都有對應的注釋,需要仔細查看,直接復制可能會編譯失敗,NDK工具包的相關(guān)路徑要改成自己的。
NDK_SRC 和 NDK_GCC 的目錄可能不同?。?!
NDK_GCC 的 arm-linux-androideabi-4.9 目錄根據(jù)不同的平臺路徑不同 本次實現(xiàn)僅實現(xiàn)了armeabi-v7a平臺?。。?/mark>
#!/bin/bash
# NDK工具包目錄
NDK_SRC=/Users/tttell/tools/android-ndk-r17c
# 此變量執(zhí)行ndk中的交叉編譯gcc所在目錄
NDK_GCC=$NDK_SRC/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
# 傳遞給gcc的參數(shù) [從Android Project的 externalNativeBuild/xxx/build.ninja 中復制到參數(shù) 可以減少警告信息]
FLAGS="-isystem $NDK_SRC/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=21 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -O0 -fPIC"
# 導入必需的頭文件 [NDK 工具包的目錄]
INCLUDES=" -isystem $NDK_SRC/sources/android/support/include"
# 編譯后輸出的目錄 [根據(jù)自己情況自定義目錄]
PREFIX=./bulid_ffmpeg_lib
./configure \
--prefix=$PREFIX \
--enable-static \
--enable-small \
--enable-cross-compile \
--disable-programs \
--disable-avdevice \
--disable-encoders \
--disable-muxers \
--disable-filters \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--extra-cflags="$FLAGS $INCLUDES" \
--extra-cflags="-isysroot $NDK_SRC/sysroot/" \
--sysroot=$NDK_SRC/platforms/android-21/arch-arm \
--arch=arm \
--target-os=android
make clean
make install
# 參數(shù)注釋
# --enable-static # 編譯靜態(tài)庫
# --enable-small # 體積優(yōu)化
# --enable-cross-compile # 開啟交叉編譯
# --disable-programs # 不編譯ffmpeg命令行工具 [如果需要可以編譯]
# --disable-avdevice # 不編譯avdevice模塊 [--help 提示中表示該模塊不支持Android平臺]
# --disable-encoders # 不編譯編碼器 [本系列僅實現(xiàn)播放功能 所以不需要編碼]
# --disable-muxers # 不編譯封裝器 [本系列僅實現(xiàn)播放功能 所以不需要封裝]
# --disable-filters # 不編譯所有濾鏡
# --cross-prefix # 指定使用NDK工具包中的gcc相關(guān)編譯器
# --extra-cflags # gcc的參數(shù)
# --sysroot # 平臺標準庫 [具體根據(jù)android項目的平臺、最低支持版本而定 本次實現(xiàn)僅編譯了armeabi-v7a 最低支持sdk21 ]
# --arch # 平臺
# --target-os # 平臺
開始執(zhí)行腳本
sh ./ffmpeg-4.0.2/build_ffmpeg_4.0.2.sh
腳本運行時,要關(guān)注日志輸出,如果出現(xiàn)error日志就及時停止吧 肯定會失敗的 不用等到之行結(jié)束;編譯過程可能會出現(xiàn)各種錯誤,具體錯誤可能跟環(huán)境也有關(guān)系,根據(jù)提示信息去搜索對應解決辦法修改即可。
如果編譯失敗,輸出目錄中應該是空的,需要查看下終端的輸出日志排查錯誤;
編譯成功則會在你指定的輸出目錄下出現(xiàn)以下文件:
include 目錄是待會需要導入到Android Project中的頭文件;
lib 目錄中就是成功編譯出的靜態(tài)庫文件;
share 目錄中的examples是一些例子 都是c語言的例子;
Android 項目集成
新建項目
Android Studio 版本 我這應該是最新的
新建一個支持Native的項目
然后一直下一步就可以了。
打開項目后需要在SDKManager中下載NDK和Cmake:
NDK 不用全部下載,我是為了調(diào)試不同版本全部下載了 下載21左右的就可以。
Cmake 下載的是最新版本的。
接著修改 app 目錄的 build.gradle 文件:
android {
...
defaultConfig {
externalNativeBuild {
cmake {
abiFilters "armeabi-v7a"
}
}
ndk {
abiFilters("armeabi-v7a")
}
}
# 為了開發(fā)方便不寫findviewbyId 我開啟了 databinding
dataBinding {
enabled = true
}
...
}
下載完成后同步一下項目,運行下測試下 如果頁面成功顯示了 Hello from C++ 即為成功;
導入ffmpeg
將編譯好的 ffmpeg 頭文件目錄 include 復制到 android project 的 cpp 目錄下:
接著開始導入靜態(tài)庫,在 cpp 目錄下新建 libs 目錄;因為上一步驟中編譯的是 armeabi-v7a 的 ffmpeg 所以在libs下新建 armeabi-v7a 目錄(實際開發(fā)中會打多個平臺的庫文件,如:x86_64需要新建x86_64的目錄)。將靜態(tài)庫文件復制到 armeabi-v7a 目錄中:
導入工作完成后 開始編寫 CMakeLists.txt :
cmake_minimum_required(VERSION 3.18.1)
project("studyffmepg")
# 導入 include目錄的 庫文件
# CMAKE_SOURCE_DIR 是常量 代表CMake文件所在目錄
include_directories(${CMAKE_SOURCE_DIR}/include)
# 批量導入源文件 定義一個 SOURCE 變量
# 這樣寫在cpp目錄下新建c++文件時不用再一個個寫導入了
file(GLOB SOURCE *.cpp *.c)
# 添加動態(tài)庫
add_library(
studyffmepg # 生成庫的名字
SHARED # SHARED 動態(tài)庫 STATIC 靜態(tài)庫
${SOURCE} # 源文件 上面定義的變量 表示全部打包進去
)
# 在NDK工具包中尋找 log 庫
find_library(
log-lib
log
)
# 導入FFmpeg的庫文件
# CMAKE_CXX_FLAGS 類似于 windows 環(huán)境變量中的 path;設(shè)置目錄后會去目錄下自動尋找?guī)煳募?/span>
# -L 代表追加目錄
# CMAKE_ANDROID_ARCH_ABI 表示運行的平臺(如:armeabi-v7a) 因為在 app:build.gradle中指定了平臺所以這里可以讀取到運行的平臺
# 注意我這里的 -L 后的路徑 /libs 對應上一步驟新建的目錄 如果你的目錄不同切記修改 否則會找不到依賴庫
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}")
target_link_libraries(
studyffmepg
${log-lib}
# ffmpeg的靜態(tài)庫有依賴關(guān)系 使用 -Wl,--start-group -Wl,--end-group 方式寫 可以忽略順序 否則容易出錯
-Wl,--start-group
libavcodec.a libavfilter.a libavformat.a libavutil.a libswresample.a libswscale.a
-Wl,--end-group
)
完成之后同步一下。
集成測試
修改 native-lib.cpp 文件,輸出一下 ffmpeg 的版本號文章來源:http://www.zghlxwxcb.cn/news/detail-402317.html
#include <jni.h>
#include <string>
using namespace std;
extern "C" {
#include <libavutil/avutil.h>
}
extern "C" JNIEXPORT jstring JNICALL
Java_top_sunhy_studyffmepg_MainActivity_stringFromJNI(
JNIEnv *env,
jobject jobj
) {
//std::string hello = "Hello from C++";
string s = "集成成功!FFmpeg Version:";
s.append(av_version_info());
return env->NewStringUTF(s.c_str());
}
完成后運行一下,出現(xiàn)版本號即為成功:文章來源地址http://www.zghlxwxcb.cn/news/detail-402317.html
到了這里,關(guān)于Android ffmpeg入門(1)—— 使用NDK交叉編譯ffmpeg集成到Android項目的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!