FFMPEG-Android编译、环境搭建、测试

一、FFMPEG-Android编译

(一)、下载FFmpeg

这里使用的是ffmpeg-3.4.6
也可以使用脚本下载指定的版本:

#库名称
source="ffmpeg-3.4.6"
#下载这个库
if [ ! -r $source ]
then
#没有下载,那么我需要执行下载操作
    echo "没有FFmpeg库,我们需要下载….."
#下载:怎么下载?
#"curl"命令表示:它可以通过Http\ftp等等这样的网络方式下载和上传文件(它是一个强大网络工具)
#基本格式:curl 地址
#指定下载版本
#下载完成之后,那么我们需要解压(通过自动解压)
#"tar"命令:表示解压和压缩(打包)
#基本语法:tar options
#例如:tar xj
#options选项分为很多中类型
#-x 表示:解压文件选项
#-j 表示:是否需要解压bz2压缩包(压缩包格式类型有很多:zip、bz2等等…)
    curl http://ffmpeg.org/releases/${source}.tar.bz2 | tar xj || exit 1
fi
(二)、注意事项

默认目标编译出来的.so格式:libavcodec.so.57.2.100
存在问题:在Android程序中无法加载动态库,编译器报错(报错信息:找不到动态库),即使手动修改了后缀名为libavcodec.so,依然还是无法运行.
解决方案:
1.进入FFmpeg-3.4.6开发包
2.打开configure文件
3.修改配置

#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)'
(三)、执行脚本./build-ffmpeg-armeabi.sh

脚本内容:

#!/bin/bash

#第一步:进入到指定目录
cd ffmpeg-3.4.6
#第二步:指定NDK路径(编译什么样的平台->采用什么样的平台编译器)
#Android平台NDK技术->做C/C++开发->编译Andrroid平台下.so动态库
#注意:放在英文目录(中文目录报错)
#修改一:修改为你自己NDK存放目录
NDK_DIR=/Users/ws/Desktop/ffmpeg/android/NDK/android-ndk-r10e

#第三步:配置Android系统版本(支持最小的版本)
#指定使用NDK Platform版本(对应系统版本)
SYSROOT=$NDK_DIR/platforms/android-18/arch-arm
#/Users/ws/Desktop/Android/android-sdk-macosx/platforms/android-18/arch-arm


第四步:指定编译工具链->(通俗:指定编译器)->CPU架构(Android手机通用的CPU架构类型):armeabi
TOOLCHAIN=$NDK_DIR/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64

#第五步:指定CPU平台架构类型
#指定编译后的安装目录
ARCH=arm
ADDI_CFLAGS="-marm"

#第六步:指定编译成功之后,.so动态库存放位置
#修改二:这个目录你需要修改为你自己目录
PREFIX=/Users/ws/Desktop/ffmpeg/android/android-ffmpeg

#第七步:编写执行编译脚本->调用FFmpeg进行配置
#定义了Shell脚本函数(方法)
function build_armeabi
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--enable-gpl \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-doc \
--disable-symver \
--enable-small \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=android \
--arch=$ARCH \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--enable-pic \
$ADDITIONAL_CONFIGURE_FLAG

make clean
make -j4
make install
}

#第八步:执行函数->开始编译
build_armeabi
echo "Android armeabi builds finished"

脚本上已经都有标注明确的步骤,如果要使用上述脚本仅需要修改上述NDK的路径NDK_DIR以及动态库.so的存放位置PREFIX

结果:

二、环境搭建

(一).使用Android Studio创建项目:

要引入C/C++库,需要选中如下选项:Include C++ support

1.png

需要捕获C/C++异常,需要选中如下选项:

2.png

(二).引入.so

首先在app->src->main下创建文件夹jniLibs
.so和头文件引入:

企业微信截图_35e20bd6-7666-4301-8b57-58e6ffeeae55.png

(三).添加、链接动态库

打开CMakeLists.txt文件:

# FFMpeg配置
# FFmpeg配置目录
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../src/main/jniLibs)

# 编解码(最重要的库)
add_library(
            avcodec
            SHARED
            IMPORTED)
set_target_properties(
            avcodec
            PROPERTIES IMPORTED_LOCATION
            ../../../../src/main/jniLibs/armeabi/libavcodec.so)


# 设备
add_library(
            avdevice
            SHARED
            IMPORTED)
set_target_properties(
            avdevice
            PROPERTIES IMPORTED_LOCATION
            ../../../../src/main/jniLibs/armeabi/libavdevice.so)


# 滤镜特效处理库
add_library(
            avfilter
            SHARED
            IMPORTED)
set_target_properties(
            avfilter
            PROPERTIES IMPORTED_LOCATION
            ../../../../src/main/jniLibs/armeabi/libavfilter.so)

# 封装格式处理库
add_library(
            avformat
            SHARED
            IMPORTED)
set_target_properties(
            avformat
            PROPERTIES IMPORTED_LOCATION
            ../../../../src/main/jniLibs/armeabi/libavformat.so)

# 工具库(大部分库都需要这个库的支持)
add_library(
            avutil
            SHARED
            IMPORTED)
set_target_properties(
            avutil
            PROPERTIES IMPORTED_LOCATION
            ../../../../src/main/jniLibs/armeabi/libavutil.so)

add_library(
            postproc
            SHARED
            IMPORTED)
set_target_properties(
            postproc
            PROPERTIES IMPORTED_LOCATION
            ../../../../src/main/jniLibs/armeabi/libpostproc.so)

# 音频采样数据格式转换库
add_library(
            swresample
            SHARED
            IMPORTED)
set_target_properties(
            swresample
            PROPERTIES IMPORTED_LOCATION
            ../../../../src/main/jniLibs/armeabi/libswresample.so)

# 视频像素数据格式转换
add_library(
            swscale
            SHARED
            IMPORTED)
set_target_properties(
            swscale
            PROPERTIES IMPORTED_LOCATION
            ../../../../src/main/jniLibs/armeabi/libswscale.so)


#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)
    set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
    message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)

#配置编译的头文件
include_directories(src/main/jniLibs/include)
target_link_libraries( # Specifies the target library.
                       native-lib avcodec avdevice avfilter avformat avutil postproc swresample swscale

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )
(四).配置CPU平台架构类型

build.gradle中添加配置
app->src->build.gradle中添加配置:abiFilters 'armeabi'

8D8A506ED558F5D024020A9FFB5F2595.png

三.编写案例&测试

案例(一):测试FFmpeg环境

1.创建类FFmpegTest,定义Java方法

//NDK方法
public class FFmpegTest {

    //加载动态库
    static {
        System.loadLibrary("native-lib");
    }

    //NDK音视频编解码:FFmpeg-测试配置
  public static native void ffmpegTest();
}

注释:(1).native标记这个方法是一个特殊方法,不是普通的java方法,而是用于与NDK进行交互方法(C/C++语言交互)
(2).用native进行修饰方法:方法没有实现,具体的实现在C/C++里面.

2.定义C/C++方法(NDK方法和Java方法必须一一对应)
注意:在CMakeLists.txt配置native-lib.cpp文件,将Java和C/C++进行关联

#include 
#include 

//当前C++兼容C语言
extern "C"{
//avcodec:编解码(最重要的库)
#include 
//avformat:封装格式处理
#include "libavformat/avformat.h"
//avutil:工具库(大部分库都需要这个库的支持)
//#include "libavutil/imgutils.h"

JNIEXPORT void JNICALL Java_com_tz_dream_ffmpeg_libso_test_FFmpegTest_ffmpegTest
        (JNIEnv *, jobject);
}
JNIEXPORT void JNICALL Java_com_tz_dream_ffmpeg_libso_test_FFmpegTest_ffmpegTest(
        JNIEnv *env, jobject jobj) {
    //(char *)表示C语言字符串
    const char *configuration = avcodec_configuration();
    __android_log_print(ANDROID_LOG_INFO,"FFmpeg配置信息:","%s",configuration);
}

3.调用测试

 FFmpegTest.ffmpegTest();
案例(二):测试FFmpeg打开封装格式文件。

1.添加Java方法定义:

   public static native void ffmpegVideoOpen(String filePath);

2.定义C/C++方法

JNIEXPORT void JNICALL Java_com_tz_dream_ffmpeg_libso_test_FFmpegTest_ffmpegVideoOpen(
        JNIEnv *env, jobject jobj, jstring jinFilePath){
    const char* cinputFilePath = env->GetStringUTFChars(jinFilePath,NULL);

    //第一步:注册所有组件
    av_register_all();

    //第二步:打开视频输入文件
    //参数一:封装格式上下文->AVFormatContext->包含了视频信息(视频格式、大小等等...)
    AVFormatContext* avformat_context = avformat_alloc_context();
    //参数二:打开文件(入口文件)->url
    int avformat_open_result = avformat_open_input(&avformat_context,cinputFilePath,NULL,NULL);
    if (avformat_open_result != 0){
        //获取异常信息
        char* error_info;
        av_strerror(avformat_open_result, error_info, 1024);
        __android_log_print(ANDROID_LOG_INFO,"main","异常信息:%s",error_info);
        return;
    }

    __android_log_print(ANDROID_LOG_INFO,"main","文件打开成功");
}

3.打开SD卡访问权限

  
    

4.调用测试

   String rootPath = Environment.getExternalStorageDirectory()
                .getAbsolutePath();
        String inFilePath = rootPath.concat("/DreamFFmpeg/Test.mov");

        //文件不存在我创建一个文件
        File file = new File(inFilePath);
        if (file.exists()){
            Log.i("日志:","存在");
        }else {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
   FFmpegTest.ffmpegVideoOpen(inFilePath);

你可能感兴趣的:(FFMPEG-Android编译、环境搭建、测试)