最近萌生了學(xué)習(xí)視頻的想法判沟,遂在網(wǎng)上找了文章來看在孝,才知道曾經(jīng)有過雷神的存在。雷神的博客激勵著一波又一波走向音視頻編碼的程序員,看著他寫的博客浸须,心中對ffmpeg開源項目,不免升起一種難以割舍的情愫香璃。
網(wǎng)上關(guān)于FFMPEG的編譯so庫教程很多,最開始走了很多彎路舟误,導(dǎo)致編譯不成功葡秒,最后盡管編譯成功了,應(yīng)用到android studio上嵌溢,還是無法實現(xiàn)雷神的那個簡單的hello ffmpeg的項目眯牧。最后在這兩篇博客的啟發(fā)下,終于還是寫出來了赖草。最純粹的直播技術(shù)實戰(zhàn)01-FFmpeg的編譯與運行学少,以及最簡單的android studio 2.3 引用FFmpeg例子程序。前者是將ffmpeg編譯成了靜態(tài)庫秧骑,后者是通過將ffmpeng編譯成了動態(tài)庫版确,雖然在android studio的jni中引用的庫的方式不一樣,但是殊途同歸乎折。
一:mac環(huán)境下的ffmpeg的編譯
ffmpeng的編譯绒疗,一般是通過腳本來實現(xiàn)。當(dāng)我們從ffmpeg的官網(wǎng)上下載了最新的源碼之后骂澄,可以在源碼的根目錄下創(chuàng)建一個.sh的文件吓蘑。由于我將ffmpeg的源碼放在了這個位置/Users/xiaguangcheng/ffmpeg/ffmpeg/,因此我的腳本文件就是ffmpegbuild.sh:
#!/bin/bash
export TMPDIR=/Users/xiaguangcheng/ffmpeg/ffmpeg/ffmpegtemp
NDK=/Users/xiaguangcheng/android/android-sdk-macosx/ndk-bundle
SYSROOT=$NDK/platforms/android-18/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
CPU=arm
PREFIX=/Users/xiaguangcheng/ffmpeg/ffmpeg/android
ADDI_CFLAGS="-marm"
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--enable-gpl \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-doc \
--disable-symver \
--enable-small \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
make clean
make
make install
}
build_one
這里需要注意的幾點:
- TMPDIR 對應(yīng)的ffmpegtemp是一個文件夾坟冲,需要自己手動創(chuàng)建士修,不然會有異常等你。
- NDK的位置需要配置你自己的樱衷。
- SYSROOT 和TOOLCHAIN同樣的道理。
- PREFIX 是打包生成的so文件和.h頭文件的位置酒唉。
- 在編譯之前需要將ffmpeg文件夾下的configure文件中的部分字段進(jìn)行修改矩桂,引用的那兩篇文章中都有詳細(xì)說明。
有時候編譯還需要yasm,因此可以先通過homebrew 安裝yasm
brew install yasm
配置完成之后侄榴,我們就可以cd到當(dāng)前ffmpeg的根目錄雹锣,通過運行
./ffmpegbuild.sh
的方式啟動這個編譯過程。
之后就可以生成這樣的一個文件夾:
二:通過android studio2.3 完成對ffmpeg so庫的調(diào)用
- (一)獲取Cmake
由于在android studio2.2之后癞蚕,官方就推薦我們使用Cmake來編譯原生庫蕊爵,因此我們首先應(yīng)該下載并安裝Cmake。這一點android stuido在SDK Tools中桦山,已經(jīng)為我們提供了方便獲得的渠道攒射,只要我們打勾下載就可以了。
- (二)創(chuàng)建一個包含c++的項目
在我們創(chuàng)建新項目的時候恒水,記得勾選include c++ support会放,不然里面的一些文件以及文件夾就需要我們手動創(chuàng)建,雖然這樣也可以钉凌。然后就是一路綠燈加速前進(jìn)了咧最。
-
(三)依賴ffmpeg 的so庫和頭文件
我們把前面生成的ffmpeg的so和頭文件拷貝到項目中來,記得添加到對應(yīng)的文件夾中御雕。so放在自己手動創(chuàng)建的jniLibs/armeabi中矢沿。頭文件放在自己手動創(chuàng)建的ffmpeg3/include中。
image.png - (四)配置CMakeLists.txt 文件酸纲。
由于項目采用了CMake來管理C++原生代碼捣鲸,因此我們還需要來配置該文件。具體的CMake使用方法福青,可以參看 CMake的官方文檔摄狱。下面貼出本項目的配置。
cmake_minimum_required(VERSION 3.4.1)
set(lib_src_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI})
add_library(native-lib SHARED src/main/cpp/native-lib.cpp)
add_library(avcodec-57 SHARED IMPORTED)
add_library(avformat-57 SHARED IMPORTED)
add_library(avutil-55 SHARED IMPORTED)
add_library(swresample-2 SHARED IMPORTED)
add_library(swscale-4 SHARED IMPORTED)
set_target_properties(avcodec-57 PROPERTIES IMPORTED_LOCATION
${lib_src_DIR}/libavcodec-57.so)
set_target_properties(avformat-57 PROPERTIES IMPORTED_LOCATION
${lib_src_DIR}/libavformat-57.so)
set_target_properties(avutil-55 PROPERTIES IMPORTED_LOCATION
${lib_src_DIR}/libavutil-55.so)
set_target_properties(swresample-2 PROPERTIES IMPORTED_LOCATION
${lib_src_DIR}/libswresample-2.so)
set_target_properties(swscale-4 PROPERTIES IMPORTED_LOCATION
${lib_src_DIR}/libswscale-4.so)
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/ffmpeg3/include)
find_library(log-lib log )
target_link_libraries( native-lib ${log-lib} avcodec-57
avformat-57
avutil-55
swresample-2
swscale-4)
- (五)app的gradle文件配置
如果是通過studio生成的c++原生庫无午,那么會在module的build.gradle中自動配置好Cmake的路徑媒役。
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
我們需要做的就是再添加一些參數(shù)
defaultConfig {
externalNativeBuild {
cmake {
cppFlags ""
arguments '-DANDROID_TOOLCHAIN=clang','-DANDROID_STL=gnustl_static'
}
}
ndk{
abiFilters 'armeabi'
}
}
- (六)編寫 C++代碼
項目創(chuàng)建的時候自動為我們配置了一個簡單的stringFromJNI的方法,我們就在native-lib.cpp文件中宪迟,手動改寫這個方法來獲取ffmpeg中的一些配置信息酣衷。
#include <jni.h>
#include <string>
extern "C"{
#include "libavcodec/avcodec.h"
};
extern "C"
JNIEXPORT jstring JNICALL
Java_com_fengfutong_cmakedemo_MainActivity_stringFromJNI(JNIEnv *env,
jobject /* this */)
{
char info[10000] = {0};
sprintf(info, "%s\n", avcodec_configuration());
return env->NewStringUTF(info);
}
三:運行app
當(dāng)你的手機出現(xiàn)這個頁面,也就到了我們第一篇說再見的時候了次泽。祝君好運穿仪,下期再會。