1. 程式人生 > >Android-mac下ffmpeg從0開始編譯

Android-mac下ffmpeg從0開始編譯

0. 題外話

基於ffmpeg4.1版本.(好吧,最後我改成3.3.8版本了)

這次編譯真的是慘痛的經歷.先是經歷了linux空間不足,然後是編譯報錯

/bin/sh: ranlib/usr/local/lib/libavdevice.a: No such file or directory

這個問題就是

LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'

引號中少了一個空格,網上很多教程都沒有空格,改成這樣就好了

LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'

最後成功編譯出來了 

1. 開始編譯的步驟

首先我們需要ffmpeg,ndk.

ffmpeg下載地址

ndk下載地址

注: 我用的是git地址下載的,最好使用git地址.這樣切版本比較方便.

ndk就無所謂什麼版本了

ndk需要配置環境變數.不然會報

-bash: ndk-build: command not found

ffmpeg下載完成之後.注意tag的切換.因為下載過來是4.1版本的,我們需要切換到3.3.8版本.因為4.1版本會報錯

/bin/sh: ranlib/usr/local/lib/libavdevice.a: No such file or directory

git checkout -b n3.3.8

切換完成之後開始編譯了

在編譯前,在原始碼中,修改FFmpeg的configure

也就是根目錄下的configure

SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'  
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'  
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'  
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'  

替換為

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'  
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'  
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'  
SLIB_INSTALL_LINKS='$(SLIBNAME)'

我這邊是在3305行左右的樣子.我是直接註釋了,你也可以替換

先是寫入指令碼.在ffmpeg下面建立一個build.sh指令碼.隨便叫什麼名字.都可以,反正我是叫build.sh

#!/bin/sh
NDK=你的ndk路徑
SYSROOT=$NDK/platforms/android-21/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
function build_one(){
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-doc \
--disable-symver \
--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
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one

這裡執行命令的時候需要注意.因為涉及到make install.所以,我們需要root許可權,所以執行命令為

sudo sh build.sh

注: 如果這裡爆出No such file or directory

說明你的系統不適應,修改一下build.sh就可以了,也就是buildone方法裡面,每個欄位加回車

#!/bin/sh
NDK=你的ndk路徑
SYSROOT=$NDK/platforms/android-27/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
function build_one(){

./configure \

--prefix=$PREFIX \

--enable-shared \

--disable-static \

--disable-doc \

--disable-ffmpeg \

--disable-ffplay \

--disable-ffprobe \

--disable-ffserver \

--disable-avdevice \

--disable-doc \

--disable-symver \

--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

}
CPU=armeabi-v7a
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one

 

這裡編譯完成之後,就會在根目錄中會出現一個android的資料夾.

然後建立一個可以開始快樂的jni編譯了...

現在才是正式開始

先是在工程的目錄下面src/main建立一個名字叫jni的資料夾.

然後把android中的include和lib兩個資料夾移到jni目錄下.

然後右鍵.File 建立三個檔案

Android.mk

Application.mk

ffmpeg-jni.c

建立這三個檔案,然後目錄結構應該是這樣的..

然後就是開始寫檔案內容了

以下是Android.mk檔案的內容

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= libavcodec
LOCAL_SRC_FILES:= lib/libavcodec-57.so
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= libavformat
LOCAL_SRC_FILES:= lib/libavformat-57.so
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= libswscale
LOCAL_SRC_FILES:= lib/libswscale-4.so
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= libavutil
LOCAL_SRC_FILES:= lib/libavutil-55.so
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= libavfilter
LOCAL_SRC_FILES:= lib/libavfilter-6.so
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= libswresample
LOCAL_SRC_FILES:= lib/libswresample-2.so
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)/include
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE:= FFmpegCodec
LOCAL_SRC_FILES:= ffmpeg-jni.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_LDLIBS := -llog -lz
LOCAL_SHARED_LIBRARIES := avcodec avfilter avformat avutil swresample swscale
include $(BUILD_SHARED_LIBRARY)

然後接著是Applicaiton.mk的內容

APP_ABI是你要編譯的so的cpu支援型別,我就寫了一個arm-v7a.可以有別的,這裡可選armeabi,x86,mips和all等

APP_PLATFORM指的是最低版

APP_ABI :=armeabi-v7a
APP_PLATFORM := android-21
APP_OPTIM := debug
APP_STL := gnustl_static

最後就是ffmpeg-jni.c的內容了

函式申明語法:JNIEXPORT jstring Java_包名activity名函式名,包名中間的點號.全部變成下劃線_

例如:我在包名com.ccx.ffmpeg下面的MainActivity中要使用avcodecInfo這個函式,

JNIEXPORT jstring Java_com_ccx_ffmpeg_MainActivity_avcodecInfo

#include <stdio.h>
#include "libavformat/avformat.h"
#include <libavfilter/avfilter.h>
#include <jni.h>
JNIEXPORT jstring Java_包名_MainActivity_avcodecInfo(JNIEnv* env, jobject obj)
{
char info[4000] = { 0 };
int count = 100; //輸出前100個codec名字
av_register_all();//初始化所有decoder和encoder,註冊所有容器型別和codec
AVCodec *c_temp = av_codec_next(NULL);
while (c_temp != NULL && count > 0){
//輸出解碼器和編碼器
if(c_temp->decode != NULL){
sprintf(info,"%s[Dec]",info);
}
else{
sprintf(info,"%s[Enc]",info);
}
sprintf(info,"%s[%10s]\n",info,c_temp->name);
c_temp = c_temp->next;
count--;
}
return (*env)->NewStringUTF(env, info);
}

然後這些就好了.

cd 到jni目錄下..

輸入

ndk-build

這樣就編譯完成了

你會發現在目錄中多了兩個資料夾,libs和obj資料夾.libs就是已經編譯好的so庫了.

這個時候就可以開始使用le