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.
注: 我用的是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