zoukankan      html  css  js  c++  java
  • [工程记录] 编译Opencv Android With FFMPEG For RTSP

    OpenCV默认并不支持安卓端FFMPEG,也就是说,在给了编译选项WITH_FFMPEG的情况下也无法成功调用VideoCapture获取流,因此我们需要修改OpenCV的CMAKE文件,手动设置一下FFMPEG库的路径,然后重新编译即可。

    编译环境

    NDK:android-ndk-r16

    Android-ABI:arm64-v8

    Android-API:android-21

    OpenCV:3.4.5

    FFMPEG:4.1

    编译工具:clang

    编译步骤

    1. 交叉编译OpenCV并保证无FFMPEG support情况下编译链接正常
    2. 交叉编译FFMPEG并保证拉流正常
    3. 修改OpenCV配置文件联合编译With FFMPEG support情况下编译链接正常。

    FFMPEG交叉编译

    配置好NDK之后,先生成以下独立的编译链工具,讲道理我这个版本的NDK是不需要单独生成的,但为了保险期间还是单独生成一下:

    ffmpeg的编译需要生成独立的编译链工具

    ./make-standalone-toolchain.sh 
    	--arch=arm64 
    	--platform=android-21 
    	--install-dir=TARGET_DIR/stand-alone-toolchain 
    	--use-llvm 
    	--stl=libc++ 
    	--force
    

    生成编译链工具之后,需要编译FFMPEG,这个编译脚本是我尝试了各种ndk版本,独立遍历链工具和配置项后确定的,因为我们这边需要、rtsp视频流的解析支持,所以加了一些network、protocol的编译选项。编译成静态库也是为了后面编译集成。

    #!/bin/bash
    export MY_TOOLCHAIN=DIR_TO_REPLACE/stand-alone-toolchain
    mkdir ffmjpeg-lib
    export PREFIX=ffmjpeg-lib
    BUILD_FFMJPEG(){
    ./configure  --target-os=android  --prefix=$PREFIX 
    --enable-cross-compile 
    --enable-runtime-cpudetect 
    --disable-asm 
    --disable-x86asm 
    --enable-protocol=tcp 
    --enable-network 
    --enable-protocol=udp 
    --enable-demuxer=rtsp 
    --enable-demuxer=rtp 
    --disable-doc  
    --arch=aarch64 
    --cc=$MY_TOOLCHAIN/bin/aarch64-linux-android-clang 
    --cxx=$MY_TOOLCHAIN/bin/aarch64-linux-android-clang++ 
    --disable-stripping 
    --nm=$MY_TOOLCHAIN/aarch64-linux-android/bin/nm 
    --sysroot=$MY_TOOLCHAIN/sysroot 
    --enable-jni 
    --enable-mediacodec 
    --enable-avresample 
    --enable-gpl --disable-shared  --enable-small 
    --disable-ffprobe --disable-ffplay   --disable-debug 
    --extra-cflags="-DBIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD -fPIC -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm -D__ANDROID_API__=21     -march=armv8-a"
    }
     
    BUILD_FFMJPEG
    
    make -j8
    make install
    

    编译可能出现的错误:

    1. member reference base type '__be32' (aka 'unsigned int') is not a structure or union,这个似乎是我用ndk16编译的时候出现的,改为21修正了。
    2. libavdevice/v4l2.c:135:9: fatal error: assigning to,这个错误似乎有时候会出现,有时候不会,我出现这个错误之后,添加编译选项-DBIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD。

    具体其他错误忘记了,大概都是通过编译选项和NDK版本控制修正的。

    FFMPEG测试

    ./ffmpeg -i rtsp://USER:PASS@IP/h264/ch1/main/av_stream 
    	-r 1/60 
    	-f image2 
    	/data/test/tmp/images%05d.png 
    	-c copy 
    	-map 0 
    	-f segment 
    	-segment_time 60 
    	"/data/test/tmp/out%03d.mkv"
    

    把二进制文件push到板子上测试,出现过这些错误:

    1. 完全无法解析给定的RTSP地址,这个原因是编译的时候没有开rtsp支持
    2. 出现Network不可达之类的,是因为没连wifi。。。
    3. Could not find tag for codec pcm_mulaw in stream,存储格式mp4写的有问题,要改为mkv。

    OpenCV编译

    编译脚本:

    cmake ..
     -DCMAKE_TOOLCHAIN_FILE=TOOLCHAIN_ROOT/android.toolchain.cmake 
     -DCMAKE_ANDROID_NDK=NDK_ROOT
     -DANDROID_NATIVE_API_LEVEL=21
     -DBUILD_ANDROID_PROJECTS=OFF
     -DBUILD_ANDROID_EXAMPLES=OFF
     -DCMAKE_BUILD_TYPE=Release
     -DBUILD_JAVA=OFF
     -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a
     -DCMAKE_INSTALL_PREFIX=INSTALL_ROOT/opencv_install 
     -DANDROID_ABI="arm64-v8a" 
     -DBUILD_JASPER=ON 
     -DBUILD_JPEG=ON 
     -DBUILD_PERF_TESTS=OFF 
     -DBUILD_SHARED_LIBS=NO 
     -DBUILD_TESTS=OFF 
     -DBUILD_TIFF=ON 
     -DBUILD_ZLIB=ON 
     -DBUILD_WEBP=ON 
     -DBUILD_opencv_apps=OFF 
     -DBUILD_opencv_core=ON 
     -DBUILD_opencv_calib3d=ON 
     -DBUILD_opencv_dnn=ON 
     -DBUILD_opencv_features2d=ON 
     -DBUILD_opencv_flann=ON 
     -DBUILD_opencv_gapi=OFF 
     -DBUILD_opencv_highgui=ON 
     -DBUILD_opencv_imgcodecs=ON 
     -DBUILD_opencv_imgproc=ON 
     -DBUILD_opencv_java_bindings_generator=OFF 
     -DBUILD_opencv_js=OFF 
     -DBUILD_opencv_ml=ON 
     -DBUILD_opencv_objdetect=OFF 
     -DBUILD_opencv_photo=OFF 
     -DBUILD_opencv_python2=OFF 
     -DBUILD_opencv_python3=OFF 
     -DBUILD_opencv_python_bindings_generator=OFF 
     -DBUILD_opencv_stitching=OFF 
     -DBUILD_opencv_ts=OFF 
     -DBUILD_opencv_video=ON 
     -DBUILD_opencv_videoio=ON 
     -DWITH_GTK=OFF 
     -DWITH_GTK_2_X=OFF 
     -DWITH_LAPACK=OFF 
     -DANDROID_STL=c++_static 
     -DANDROID_TOOLCHAIN=clang 
     -DANDROID_ARM_NEON=ON 
     -DWITH_FFMPEG=ON
    

    这个脚本也是尝试了一些,最终都是我们需要用到的,最后编译选项DWITH_FFMPEG=ON打不打开没影响,因为最终也不会编进去。。

    这一块遇到的报错就不说了,基本OpenCV的编译。

    联合编译OpenCV和FFMPEG

    主要修改两个文件:

    1. OpenCV根目录CMakeLists.txt
    OCV_OPTION(WITH_FFMPEG "Include FFMPEG support" ON
      VISIBLE_IF NOT ANDROID AND NOT IOS AND NOT WINRT
      VERIFY HAVE_FFMPEG)
    

    改为:

    OCV_OPTION(WITH_FFMPEG         "Include FFMPEG support"                      ON   IF (NOT IOS AND NOT WINRT) )
    
    if(WITH_FFMPEG OR HAVE_FFMPEG)
      if(OPENCV_FFMPEG_USE_FIND_PACKAGE)
        status("    FFMPEG:"       HAVE_FFMPEG         THEN "YES (find_package)"                       ELSE "NO (find_package)")
      elseif(WIN32)
        status("    FFMPEG:"       HAVE_FFMPEG         THEN "YES (prebuilt binaries)"                  ELSE NO)
      else()
        status("    FFMPEG:"       HAVE_FFMPEG         THEN YES ELSE NO)
      endif()
      status("      avcodec:"      FFMPEG_libavcodec_FOUND    THEN "YES (ver ${FFMPEG_libavcodec_VERSION})"    ELSE NO)
      status("      avformat:"     FFMPEG_libavformat_FOUND   THEN "YES (ver ${FFMPEG_libavformat_VERSION})"   ELSE NO)
      status("      avutil:"       FFMPEG_libavutil_FOUND     THEN "YES (ver ${FFMPEG_libavutil_VERSION})"     ELSE NO)
      status("      swscale:"      FFMPEG_libswscale_FOUND    THEN "YES (ver ${FFMPEG_libswscale_VERSION})"    ELSE NO)
      status("      avresample:"   FFMPEG_libavresample_FOUND THEN "YES (ver ${FFMPEG_libavresample_VERSION})" ELSE NO)
    endif()
    

    改为:

    if(WITH_FFMPEG OR HAVE_FFMPEG)
      if(OPENCV_FFMPEG_USE_FIND_PACKAGE)
        status("    FFMPEG:"       HAVE_FFMPEG         THEN "YES (find_package)"                       ELSE "NO (find_package)")
      #elseif(WIN32)
      elseif(WIN32 OR ANDROID)
        status("    FFMPEG:"       HAVE_FFMPEG         THEN "YES (prebuilt binaries)"                  ELSE NO)
      else()
        status("    FFMPEG:"       HAVE_FFMPEG         THEN YES ELSE NO)
      endif()
      status("      avcodec:"      FFMPEG_libavcodec_FOUND    THEN "YES (ver ${FFMPEG_libavcodec_VERSION})"    ELSE NO)
      status("      avformat:"     FFMPEG_libavformat_FOUND   THEN "YES (ver ${FFMPEG_libavformat_VERSION})"   ELSE NO)
      status("      avutil:"       FFMPEG_libavutil_FOUND     THEN "YES (ver ${FFMPEG_libavutil_VERSION})"     ELSE NO)
      status("      swscale:"      FFMPEG_libswscale_FOUND    THEN "YES (ver ${FFMPEG_libswscale_VERSION})"    ELSE NO)
      status("      avresample:"   FFMPEG_libavresample_FOUND THEN "YES (ver ${FFMPEG_libavresample_VERSION})" ELSE NO)
    endif()
    
    1. cmake/OpenCVFindLibsVideo.cmake

    找到# --- FFMPEG ---的段落

    整个替换:

    # --- FFMPEG ---
    ocv_clear_vars(HAVE_FFMPEG)
    if(WITH_FFMPEG)  # try FFmpeg autodetection
      if(ANDROID)
        set(HAVE_FFMPEG TRUE)
        set(FFMPEG_DIR FFMJPEG_INSTALL_DIR/ffmjpeg-lib)
        set(FFMPEG_INCLUDE_DIRS ${FFMPEG_DIR}/include)
        set(FFMPEG_LIBRARY_DIRS ${FFMPEG_DIR}/lib)
        set(FFMPEG_LIBRARIES avcodec avformat avutil swscale z)
        message(STATUS "FFMPEG_INCLUDE_DIR: ${FFMPEG_INCLUDE_DIRS}")
        message(STATUS "FFMPEG_LIBRARY_DIRS: ${FFMPEG_LIBRARY_DIRS}")
        message(STATUS "FFMPEG_LIBRARIES: ${FFMPEG_LIBRARIES}")
      else()
        message(STATUS "Can't find ffmpeg - 'pkg-config' utility is missing")
      endif()
    endif()
    if(HAVE_FFMPEG
        AND NOT HAVE_FFMPEG_WRAPPER
    )
      try_compile(__VALID_FFMPEG
          "${OpenCV_BINARY_DIR}"
          "${OpenCV_SOURCE_DIR}/cmake/checks/ffmpeg_test.cpp"
          CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${FFMPEG_INCLUDE_DIRS}"
                      "-DLINK_DIRECTORIES:STRING=${FFMPEG_LIBRARY_DIRS}"
                      "-DLINK_LIBRARIES:STRING=${FFMPEG_LIBRARIES}"
          OUTPUT_VARIABLE TRY_OUT
      )
      if(False)
        #message(FATAL_ERROR "FFMPEG: test check build log:
    ${TRY_OUT}")
        message(STATUS "WARNING: Can't build ffmpeg test code")
        set(HAVE_FFMPEG FALSE)
      else()
        ocv_append_build_options(VIDEOIO FFMPEG)
      endif()
    endif()
    

    这一块,一来将FFMPEG相关的变量都手动设置了,二来去掉了编译测试,这一块编译测试老失败导致最后编不进去FFMPEG。

    然后重新编译一下OpenCV。

    过程中可能遇到的问题:

    1. error: function-like macro '__GNUC_PREREQ' is not defined,这个可能是NDK版本不对吧
    2. 主要出现的问题是编不上去,经过几次修改CMAKE文件才编上去。。

    最后去写个文件上板测试一下:

    #include <iostream>
    #include "opencv2/opencv.hpp"
    using namespace std;
    int main(int argc, char *argv[])
    {
    
        cv::VideoCapture cap;
        cap.open("RTSP_ADDRESS");
        cv::Mat frame;
        cout << "open: " << cap.isOpened() << endl;
        for (int i = 0; i < 10; i++)
        {
            cap >> frame;
            cout << frame.cols << endl;
        }
    
        return 0;
    }
    

    没问题:

  • 相关阅读:
    开源ITIL管理软件iTop 2.5-2.6安装
    并发服务器
    套接字通信
    libevent
    gdb调试
    值得收藏的技术社区
    关于博客园随笔编辑页面内容不刷新(空白)的问题解决
    嵌入式Web框架
    内存地址的传递问题
    linux文件缓冲区
  • 原文地址:https://www.cnblogs.com/aoru45/p/15484583.html
Copyright © 2011-2022 走看看