美文网首页
FFMPEG-Android编译、环境搭建、测试

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

作者: king_jensen | 来源:发表于2019-11-13 16:19 被阅读0次

    一、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 <jni.h>
    #include <android/log.h>
    
    //当前C++兼容C语言
    extern "C"{
    //avcodec:编解码(最重要的库)
    #include <libavcodec/avcodec.h>
    //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卡访问权限

      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    

    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编译、环境搭建、测试

          本文链接:https://www.haomeiwen.com/subject/yrrhictx.html