ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[工程记录] 编译Opencv Android With FFMPEG For RTSP

2021-10-30 11:36:11  阅读:193  来源: 互联网

标签:OFF FFMPEG 编译 -- RTSP Opencv DBUILD opencv


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="-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,这个错误似乎有时候会出现,有时候不会,我出现这个错误之后,稍微修改了一下编译脚本再编译一次就好了,比如把debug模式修改一下,比较玄学。。

具体其他错误忘记了,大概都是通过编译选项和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:\n${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;
}

没问题:

标签:OFF,FFMPEG,编译,--,RTSP,Opencv,DBUILD,opencv
来源: https://www.cnblogs.com/aoru45/p/15484583.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有