將ffmpeg 移植到android平臺(tái) (android studio環(huán)境)下篇

????????上篇中我們已經(jīng)編譯好了ffmpeg的動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù),接下來(lái)我們要在android上使用,網(wǎng)上也有很多例子,把上篇的多個(gè)動(dòng)態(tài)庫(kù)編譯成一個(gè)so庫(kù),我也嘗試過(guò),但是編譯出來(lái)的libffmpeg.so庫(kù)有十多M,而多個(gè)so庫(kù)總共才4M多,相對(duì)來(lái)說(shuō)太大了,而使用多個(gè)so,需要加載太多了so庫(kù)文件,所以我使用靜態(tài)庫(kù)來(lái)生成一個(gè)動(dòng)態(tài)庫(kù),然后再使用這個(gè)動(dòng)態(tài)庫(kù)。

1、創(chuàng)建一個(gè)android項(xiàng)目,支持Cmake,然后將之前編譯好的靜態(tài)庫(kù)分別拷到j(luò)niLibs下如下圖

2、FFmpeg是C開(kāi)發(fā),api比較多,如果使用api來(lái)開(kāi)發(fā)我們要的功能,成本高,費(fèi)時(shí)久,所以我采用的是命令形式,操作很簡(jiǎn)單,在FFmpeg將cmdutils.c 、cmdutils.h 、cmdutils_common_opts.h、 config.h、 ffmpeg.c、 ffmpeg.h、 ffmpeg_filter.c、 ffmpeg_opt.c拷到cpp目錄下,并且將各個(gè)模塊的.h文件過(guò)濾出來(lái)(寫(xiě)個(gè)腳本去把所有的.h文件提取出來(lái),為了android項(xiàng)目編譯的通過(guò),否則會(huì)找不到頭文件),這個(gè)我是參照www.lxweimin.com/p/ceaa286d8aff,如下圖

3、修改文件

找到ffmpeg.c,把int main(int argc, char argv) 改名為 int jxRun(int argc, char argv)

找到ffmpeg.h, 在文件末尾添加函數(shù)申明: int jxRun(int argc, char **argv);然后在return前加上如下代碼即可

nb_filtergraphs =0;progress_avio = NULL;input_streams = NULL;nb_input_streams =0;input_files = NULL;nb_input_files =0;output_streams = NULL;nb_output_streams =0;output_files = NULL;nb_output_files =0;

找到cmdutils.c中的exit_program函數(shù),修改為

在cmdutils.h文件中將exit_program 返回 改成int 并移除掉av_noreturn

創(chuàng)建jni 與java交互的.c文件ffmpeg-pro-lib.c

4、CMakeLists.txt的配置

# For more information about using CMake with Android Studio, read the

# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

add_library( # Sets the name of the library.

ffmpeg-pro-lib

# Sets the library as a shared library.

SHARED

# Provides a relative path to your source file(s).

src/main/cpp/cmdutils.c

src/main/cpp/ffmpeg.c

src/main/cpp/ffmpeg_filter.c

src/main/cpp/ffmpeg_opt.c

src/main/cpp/ffmpeg-pro-lib.c )

add_library(

avcodec

STATIC

IMPORTED

)

add_library(

avfilter

STATIC

IMPORTED

)

add_library(

avformat

STATIC

IMPORTED

)

add_library(

avutil

STATIC

IMPORTED

)

add_library(

swresample

STATIC

IMPORTED

)

add_library(

swscale

STATIC

IMPORTED

)

add_library(

avdevice

STATIC

IMPORTED

)

add_library(

avresample

STATIC

IMPORTED

)

add_library(

postproc

STATIC

IMPORTED

)

add_library(

x264

STATIC

IMPORTED

)

if(${ANDROID_ABI} STREQUAL "armeabi-v7a")

set_target_properties(

avcodec

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libavcodec.a

)

set_target_properties(

avfilter

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libavfilter.a

)

set_target_properties(

avformat

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libavformat.a

)

set_target_properties(

avutil

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libavutil.a

)

set_target_properties(

swresample

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libswresample.a

)

set_target_properties(

swscale

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libswscale.a

)

set_target_properties(

avdevice

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libavdevice.a

)

set_target_properties(

avresample

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libavresample.a

)

set_target_properties(

postproc

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libpostproc.a

)

set_target_properties(

x264

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libx264.a

)

endif(${ANDROID_ABI} STREQUAL "armeabi-v7a")

if(${ANDROID_ABI} STREQUAL "x86")

set_target_properties(

avcodec

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libavcodec.a

)

set_target_properties(

avfilter

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libavfilter.a

)

set_target_properties(

avformat

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libavformat.a

)

set_target_properties(

avutil

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libavutil.a

)

set_target_properties(

swresample

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libswresample.a

)

set_target_properties(

swscale

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libswscale.a

)

set_target_properties(

avdevice

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libavdevice.a

)

set_target_properties(

avresample

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libavresample.a

)

set_target_properties(

postproc

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libpostproc.a

)

set_target_properties(

x264

PROPERTIES IMPORTED_LOCATION

${CMAKE_SOURCE_DIR}/src/main/jniLibs/x86/libx264.a

)

set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-warn-shared-textrel")

endif(${ANDROID_ABI} STREQUAL "x86")

include_directories(

src/main/cpp

)

find_library( # Sets the name of the path variable.

log-lib

# Specifies the name of the NDK library that

# you want CMake to locate.

log )

target_link_libraries( # Specifies the target library.

ffmpeg-pro-lib

swscale

swresample

postproc

avresample

avdevice

avfilter

avformat

avcodec

avutil

x264

# Links the target library to the log library

# included in the NDK.

${log-lib})


由于使用的是靜態(tài)庫(kù),所有鏈接順序不要亂,否則build不過(guò),可以按照我上面的順序。之后就是編寫(xiě)java代碼了,創(chuàng)建一個(gè)java類(lèi)FFmpegNativeHelper

static{

System.loadLibrary("ffmpeg-pro-lib");

}

public static booleancompressVideo(String videoPath,String resultPath){

int ret = ffmpegCmdRun(new String[]{"ffmpeg",

"-i",videoPath,

"-y",

"-c:v","libx264",

"-c:a","aac",

"-crf","25",

"-vf","scale=-1:640",

"-preset","ultrafast",

"-b:v","900k",

"-bufsize","900k",

"-b:a","96k",

resultPath});

if(ret == 0){

return true;

}

}

return false;

}

private static native intffmpegCmdRun(String[] cmd);


上面只是簡(jiǎn)單的測(cè)試命令,你也可以嘗試其它的命令。

生成apk后,只有一個(gè)so庫(kù)文件,另外四個(gè)是我用了第三方播放器加載進(jìn)來(lái)的忽略掉。

視頻壓縮后的結(jié)果8M多壓成了1M多,感覺(jué)還行。

如下:



由于本人一直是從事android開(kāi)發(fā)的,第一次寫(xiě)關(guān)于ffmpeg文章,可能有很多不足之處,希望大家諒解下,如有疑問(wèn),歡迎提出,代碼的話(huà),改天有空上傳到github。

提示:在x86下,請(qǐng)記得替換掉config.h文件(目前這個(gè)config.h文件需要作ABI的區(qū)分),因?yàn)椴煌脚_(tái)下編譯生成的config.h文件不一樣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容