美文网首页
FFmpeg库移植并优化YUV、BGR24 转化

FFmpeg库移植并优化YUV、BGR24 转化

作者: CHSmile | 来源:发表于2018-03-26 11:21 被阅读246次

    最近项目使用OpenCV实现视频帧透视变换,当切换视频流720p、1280p,出现部分手机和小米ipad2平板等出现视频流卡顿、应用程序退出问题。原因分析:OpenCV API 方法:cvtColor() 实现yuv 与 bgr24转化消耗时间较长,因此视频流的优化,就是减少各种转换消耗的时间。

    FFmpeg so包编译和jni开发
    • 下载FFmpeg 3.1.3
      网址:https://ffmpeg.org/download.html#build-mac

      image.png
    • 下载NDK
      NDK下载地址

    • 配置ndk环境

      1. 启动终端Terminal
      2. 进入当前用户的home目录
      3. 输入cd ~ 或 /Users/YourUserName
      4. 创建.bash_profile
      5. 输入touch .bash_profile
      6. 编辑.bash_profile文件
      7. 输入open -e .bash_profile

      因为是为了配置NDK开发环境,输入Android NDK下目录,前面是android sdk的,可以不用动它,最终.bash_profile文件如下:

      export NDK_ROOT=/Users/YourUserName/Downloads/android-ndk-r13      
      export PATH=$PATH:$NDK_ROOT
      
    1. 保存文件,关闭.bash_profile
    2. 更新刚配置的环境变量
      输入source .bash_profile
    • 编译FFmpeg
      在编译前,在源码中,修改FFmpeg的configure
      下载FFmpeg源代码之后,首先需要对源代码中的configure文件进行修改。由于编译出来的动态库文件名的版本号在.so之后(例如“libavcodec.so.5.100.1”),而android平台不能识别这样文件名,所以需要修改这种文件名。在configure文件中找到下面几行代码(在3209-3212行):
    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)'  
    

    接下来开始写shell脚本
    重命名为build_android.sh。脚本如下:

    #!/bin/bash  
    #export TMPDIR="/Users/YourUserName/program/ffmpeg-3.4.2"  
    NDK=/Users/YourUserName/Downloads/android-ndk-r13
    NDK_VERSION=android-18
    function build_one {
    ./configure \
    --target-os=linux \
    --arch=$ARCH \
    --prefix=$PREFIX \
    --enable-shared \
    --disable-static \
    --disable-doc \
    --disable-ffmpeg \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-ffserver \
    --disable-doc \
    --disable-symver \
    --enable-cross-compile \
    --cross-prefix=$CROSS_COMPILE \
    --sysroot=$SYSROOT \
    --extra-cflags="-fpic"
    make clean
    make
    make install
    }
    ARCH=arm 
    CPU=arm
    PREFIX=$(pwd)/android/$CPU
    TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64
    CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-
    SYSROOT=$NDK/platforms/$NDK_VERSION/arch-$ARCH
    build_one
    

    如果大家要编译,记得改下前三行,对应自己机器上的环境
    接着开始执行这个shell脚本,在终端输入./ build_android.sh
    开始进行自动编译:

    中间过程:



    结果如下:


    这时会发现 FFmpeg下多了一个文件夹android:


    打开如下:



    这样我们要的so就有了,当然,这只是基本的。

    • 移植到Android平台
    1. 在src/main下建一个jni目录



      把前面编译好的android目录移植过来

    image.png
    1. 编写 Android.mk Application.mk文件
      Android.mk
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE := avcodec
    LOCAL_SRC_FILES := ffmpeg/lib/$(TARGET_ARCH_ABI)/libavcodec.so
    include $(PREBUILT_SHARED_LIBRARY)
     
    include $(CLEAR_VARS)
    LOCAL_MODULE := avdevice
    LOCAL_SRC_FILES := ffmpeg/lib/$(TARGET_ARCH_ABI)/libavdevice.so
    include $(PREBUILT_SHARED_LIBRARY)
     
    include $(CLEAR_VARS)
    LOCAL_MODULE := avfilter
    LOCAL_SRC_FILES := ffmpeg/lib/$(TARGET_ARCH_ABI)/libavfilter.so
    include $(PREBUILT_SHARED_LIBRARY)
     
    include $(CLEAR_VARS)
    LOCAL_MODULE := avformat
    LOCAL_SRC_FILES := ffmpeg/lib/$(TARGET_ARCH_ABI)/libavformat.so
    include $(PREBUILT_SHARED_LIBRARY)
     
    include $(CLEAR_VARS)
    LOCAL_MODULE := avutil
    LOCAL_SRC_FILES := ffmpeg/lib/$(TARGET_ARCH_ABI)/libavutil.so
    include $(PREBUILT_SHARED_LIBRARY)
     
    include $(CLEAR_VARS)
    LOCAL_MODULE := swscale
    LOCAL_SRC_FILES := ffmpeg/lib/$(TARGET_ARCH_ABI)/libswscale.so
    include $(PREBUILT_SHARED_LIBRARY)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE := swresample
    LOCAL_SRC_FILES := ffmpeg/lib/$(TARGET_ARCH_ABI)/libswresample.so
    include $(PREBUILT_SHARED_LIBRARY)
    
    LOCAL_MODULE := apm-plugin-video-preprocessing
    LOCAL_SRC_FILES := \
        video_preprocessing_plugin_jni.cpp \
    
    LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/include
    
    LOCAL_LDLIBS += -latomic
    LOCAL_LDLIBS +=  -lm -llog
    
    LOCAL_SHARED_LIBRARIES := \
            libyuv  \
            avcodec \
            avdevice\
            avfilter\
            avformat\
            avutil  \
            swscale \
            swresample
    
    include $(BUILD_SHARED_LIBRARY)
    APP_ALLOW_MISSING_DEPS :=true
    

    Application.mk

    APP_STL := gnustl_static
    APP_CPPFLAGS := -frtti -fexceptions
    APP_ABI :=  armeabi armeabi-v7a
    #arm64-v8a x86 x86_64
    APP_PLATFORM := android-18
    APP_CFLAGS += -Wno-error=format-security
    APP_ALLOW_MISSING_DEPS :=true
    
    1. 编写.cpp文件,完成jni开发
      注意:在C++文件中引入C头文件需添加
    extern "C"
    {
    #include <libavcodec/avcodec.h>
    #include <libavutil/pixfmt.h>
    #include <libswscale/swscale.h>
    }
    

    1、新建一个类,声明native方法。这个类是java与C/C++交互的中介,方法由java声明,由C/C++实现。

    public class VideoPreProcessing {
        static {
            System.loadLibrary("apm-plugin-video-preprocessing");
        }
        ...
        public native void resetVideo();
    }
    

    确认自己类的包名!使用javah生成.h头文件
    javah命令应该这么写:

    /Users/Documents/workspace/app/src/main/java >javah -jni com.example.VideoPreProcessing
    

    然后就能看到生成了一个h文件。
    2、 新建一个jni文件夹,新建main.c,把.h里面的内容复制进去,并实现里面的函数。

    JNIEXPORT void JNICALL Java_com_example_VideoPreProcessing_resetVideo
            (JNIEnv *env, jobject obj)
    {
    }
    

    3、至此,VideoPreProcessing.cpp 中可以实现 C++中调用ffmpeg so包实现方法,完成YUV与RGB转换.

    相关文章

      网友评论

          本文标题:FFmpeg库移植并优化YUV、BGR24 转化

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