1. 前言

问题:解决opencv无法播放rtsp问题
原因分析:opencv播放网络流使用ffmpeg解码,所以问题出在ffmpeg这里,我们需要手动编译ffmpeg,再从新编译opencv即可

笔者环境是centos 7.6版本,gcc 7.3版本

2. 编译依赖项

在编译之前需要设置一些环境变量,不然后面可能会遇到编译错误的问题, 其中/home/swls/work_dir/lib/ffmpeg_build是我自己的路径,需要手动更改以下,一般设置在家目录下的ffmpeg_build就行

# 安装依赖 用于使用ffplay直接播放视频流
sudo yum install libXext-devel

# 安装必要依赖 否则后面编译会出现找不到命令的错误
yum -y install patch
yum groupinstall "Development Tools"
yum install autoconf automake libtool

# 添加环境变量
vim ~/.bashrc
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/home/swls/work_dir/lib/ffmpeg_build/lib"
export PATH="$PATH:/home/swls/work_dir/lib/ffmpeg_build/bin"
source ~/.bashrc

执行完毕后,当前命令行不要关闭,后面编译所有依赖项都需要在这一个命令行上操作,因为关系到环境临时环境变量的问题。下面设置环境变量,此处目的是添加-fPIC防止在opencv编译时报错

#在命令行执行, 添加环境变量 
export CFLAGS="$CFLAGS -fPIC"
export CPPFLAGS="$CPPFLAGS -fPIC"
# 此处路径要和前面的保持一致
export prefix="/home/swls/work_dir/lib/ffmpeg_build"

2.1 SDL

编译SDL, 接着在同一个命令行上操作

# 在家目录下创建一个文件夹,用于存放源代码
mkdir ffmpeg_sources
cd ~/ffmpeg_sources
git clone https://github.com/libsdl-org/SDL.git
cd SDL/ && git checkout release-2.0.18
mkdir build && cd build
../configure --prefix="$prefix" --enable-shared --with-pic --enable-static
make -j4 
make install

2.2 Nasm

编译Nasm, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
curl -O -L https://www.nasm.us/pub/nasm/releasebuilds/2.15.05rc1/nasm-2.15.05rc1.tar.bz2
tar xjvf nasm-2.15.05rc1.tar.bz2
cd nasm-2.15.05rc1/
./autogen.sh
./configure --prefix="$prefix"
make -j4
make install

2.3 Yasm

编译Nasm, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
curl -O -L http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
tar xzvf yasm-1.3.0.tar.gz
cd yasm-1.3.0
./configure --prefix="$prefix" --enable-shared --with-pic --enable-static
make -j4
make install

2.4 libfdk_aac

编译libfdk_aac, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
git clone --depth 1 https://github.com/mstorsjo/fdk-aac.git
cd fdk-aac
autoreconf -fiv
./configure --prefix="$prefix" --enable-shared --with-pic --enable-static
make -j4
make install

2.5 libmp3lame

编译libmp3lame, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
curl -O -L http://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz
tar xzvf lame-3.100.tar.gz
cd lame-3.100
./configure --prefix="$prefix" --enable-shared --with-pic --enable-static --enable-nasm
make -j4
make install

2.6 libopus

编译libopus, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
curl -O -L https://archive.mozilla.org/pub/opus/opus-1.3.tar.gz
tar xzvf opus-1.3.tar.gz
cd opus-1.3
./configure --prefix="$prefix" --enable-shared --with-pic --enable-static
make -j4
make install

2.7 libogg

编译libogg, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
curl -O -L http://downloads.xiph.org/releases/ogg/libogg-1.3.3.tar.gz
tar xzvf libogg-1.3.3.tar.gz
cd libogg-1.3.3
./configure --prefix="$prefix" --enable-shared --with-pic --enable-static
make -j4
make install

2.8 libvorbis

编译libvorbis, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
curl -O -L http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.6.tar.gz
tar xzvf libvorbis-1.3.6.tar.gz
cd libvorbis-1.3.6
./configure --prefix="$prefix" --with-ogg="$prefix" --enable-shared --with-pic --enable-static
make -j4
make install

2.9 libvpx

编译libvpx, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
git clone --depth 1 https://chromium.googlesource.com/webm/libvpx.git
cd libvpx
./configure --prefix="$prefix" --enable-shared --enable-static --disable-examples --disable-unit-tests --enable-vp9-highbitdepth
make -j4
make install

2.10 freetype2

编译freetype2, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
# freetype版本采用较新版,避免编译opencv时出现`undefined reference to 'FT_Get_Var_Design_Coordinates'`错误
curl -O -L  https://github.com/aseprite/freetype2/archive/VER-2-8.zip
unzip VER-2-8.zip
cd freetype2-VER-2-8
./autogen.sh
./configure --prefix="$prefix" --enable-shared --with-pic
make -j4
make install

2.11 libx264

编译libx264, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
git clone --depth 1 https://code.videolan.org/videolan/x264.git
cd x264
./configure --prefix="$prefix"  --enable-shared --enable-pic
make -j4
make install

2.12 libx265

编译libx265, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
git clone https://bitbucket.org/multicoreware/x265_git.git
cd ~/ffmpeg_sources/x265_git/build/linux
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$prefix" -DENABLE_SHARED:bool=ON ../../source
make -j4
make install

编译ffmpeg-4.1

编译ffmpeg-4.1, 接着在同一个命令行上操作

cd ~/ffmpeg_sources
curl -O -L https://ffmpeg.org/releases/ffmpeg-4.1.tar.bz2
tar xjvf ffmpeg-4.1.tar.bz2
cd ffmpeg-4.1
# 设置环境变量,不然编译ffmpeg的时候会无法找到依赖项
PATH="$prefix/bin:$PATH" 
PKG_CONFIG_PATH="$prefix/lib/pkgconfig" 
./configure \
  --prefix="$prefix" \
  --extra-cflags="-I$prefix/include" \
  --extra-ldflags="-L$prefix/lib" \
  --extra-libs=-lm \
  --bindir="$prefix/bin" \
  --enable-gpl \
  --enable-pthreads \
  --enable-libfdk_aac \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libvorbis \
  --enable-libvpx \
  --enable-libx264 \
  --enable-libx265 \
  --enable-nonfree \
  --enable-libfreetype \
  --disable-yasm \
  --enable-pic   \
  --disable-debug \
  --enable-version3 \
  --enable-avresample \
  --enable-shared

make -j4
make install

如果在configure的时候出现如下红色醒目提示,那么就是没有正确找到opus库,
ERROR: opus not found using pkg-config 可是我们已经在前面的步骤中编译好了,那么需要手动配置PKG_CONFIG_PATH路径,执行如下命令,最后在重新configure即可

export PKG_CONFIG_PATH=/usr/lib/pkgconfig:$prefix/lib/pkgconfig

最后编译成功后,在当前命令行上直接敲ffmpeg -version 显示如下结果,列出了所有依赖项和版本号,如果没有输出结果,那么应该是操作有问题,无法找到相关依赖库,可参考这篇文章

(base) [swls@192 ~]$ ffmpeg -version
ffmpeg version N-98978-g4cfe812 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 7 (GCC)
configuration: --prefix=/home/swls/work_dir/lib/ffmpeg_build --extra-cflags=-I/home/swls/work_dir/lib/ffmpeg_build/include --extra-ldflags=-L/home/swls/work_dir/lib/ffmpeg_build/lib --extra-libs=-lm --bindir=/home/swls/work_dir/lib/ffmpeg_build/bin --enable-gpl --enable-pthreads --enable-libfdk_aac --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-nonfree --enable-libfreetype --disable-yasm --enable-pic --disable-debug --enable-version3 --enable-shared
libavutil      56. 58.100 / 56. 58.100
libavcodec     58.101.101 / 58.101.101
libavformat    58. 51.101 / 58. 51.101
libavdevice    58. 11.101 / 58. 11.101
libavfilter     7. 87.100 /  7. 87.100
libswscale      5.  8.100 /  5.  8.100
libswresample   3.  8.100 /  3.  8.100
libpostproc    55.  8.100 / 55.  8.100

编译opencv-3.4.6

最后编译opencv,笔者使用3.4.6,下载路径contrib下载路径 接着在同一个命令行上操作,添加cmake 查找路径,不然无法查找到ffmpeg

# /home/swls/work_dir/lib/ffmpeg_build 需要改成上面相同的路径
export PKG_CONFIG_PATH=/home/swls/work_dir/lib/ffmpeg_build/lib/pkgconfig:$PKG_CONFIG_PATH

# 安装opencv依赖项
# ubuntu
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev ffmpeg
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
# centos
# cmake可以去掉,因为系统安装的cmake版本太低,需要自己手动安装  
# gcc 笔者使用7.3 如果已经安装,则可以去掉
yum install -y gcc gcc-c++ gtk+-devel libjpeg-devel libtiff-devel jasper-devel libpng-devel zlib-devel cmake
yum install git gtk2-devel pkgconfig numpy python python-pip python-devel gstreamer-plugins-base-devel libv4l ffmpeg-devel mplayer mencoder flvtool2
yum install -y libdc1394
yum install libwebp-tools

# 创建编译目录,视自己情况来定
mkdir ~/opencv
cd opencv
wget https://github.com/opencv/opencv/archive/3.4.6.zip
wget https://github.com/opencv/opencv_contrib/archive/3.4.6.zip
unzip opencv-3.4.6.zip
unzip opencv_contrib-3.4.6.zip
cd opencv-3.4.6
# 在opencv源码目录下创建编译目录
mkdir build
# 在opencv源码目录下创建安装目录,
mkdir install
cd build

# 编译指令可根据自己需求更改
cmake -D CMAKE_BUILD_TYPE=RELEASE \
    -D CMAKE_INSTALL_PREFIX=../install \
    -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-3.4.6/modules \
    -D BUILD_ITT=ON \
    -D BUILD_JASPER=ON \
    -D BUILD_JPEG=ON \
    -D BUILD_PACKAGE=ON \
    -D BUILD_PERF_TESTS=OFF \
    -D BUILD_PNG=ON \
    -D BUILD_PROTOBUF=ON \
    -D BUILD_SHARED_LIBS=ON \
    -D BUILD_TESTS=OFF \
    -D BUILD_opencv_apps=ON \
    -D BUILD_opencv_aruco=ON \
    -D BUILD_opencv_bgsegm=ON \
    -D BUILD_opencv_bioinspired=ON \
    -D BUILD_opencv_calib3d=ON \
    -D BUILD_opencv_ccalib=ON \
    -D BUILD_opencv_core=ON \
    -D BUILD_opencv_datasets=ON \
    -D BUILD_opencv_dnn=OFF \
    -D BUILD_opencv_dnn_objdetect=OFF \
    -D BUILD_opencv_dpm=ON \
    -D BUILD_opencv_face=ON \
    -D BUILD_opencv_features2d=ON \
    -D BUILD_opencv_flann=ON \
    -D BUILD_opencv_freetype=ON \
    -D BUILD_opencv_fuzzy=ON \
    -D BUILD_opencv_hfs=ON \
    -D BUILD_opencv_highgui=ON \
    -D BUILD_opencv_img_hash=ON \
    -D BUILD_opencv_imgcodecs=ON \
    -D BUILD_opencv_imgproc=ON \
    -D BUILD_opencv_java_bindings_generator=OFF \
    -D BUILD_opencv_js=OFF \
    -D BUILD_opencv_line_descriptor=ON \
    -D BUILD_opencv_ml=ON \
    -D BUILD_opencv_objdetect=ON \
    -D BUILD_opencv_optflow=ON \
    -D BUILD_opencv_phase_unwrapping=ON \
    -D BUILD_opencv_photo=ON \
    -D BUILD_opencv_plot=ON \
    -D BUILD_opencv_python_bindings_generator=OFF \
    -D BUILD_opencv_reg=ON \
    -D BUILD_opencv_rgbd=ON \
    -D BUILD_opencv_saliency=ON \
    -D BUILD_opencv_shape=ON \
    -D BUILD_opencv_stereo=ON \
    -D BUILD_opencv_stitching=ON \
    -D BUILD_opencv_structured_light=ON \
    -D BUILD_opencv_superres=ON \
    -D BUILD_opencv_surface_matching=ON \
    -D BUILD_opencv_text=ON \
    -D BUILD_opencv_tracking=ON \
    -D BUILD_opencv_ts=OF \
    -D BUILD_opencv_video=ON \
    -D BUILD_opencv_videoio=ON \
    -D BUILD_opencv_videostab=ON \
    -D BUILD_opencv_world=ON \
    -D BUILD_opencv_xfeatures2d=ON \
    -D BUILD_opencv_ximgproc=ON \
    -D BUILD_opencv_xobjdetect=ON \
    -D BUILD_opencv_xphoto=ON \
    -D OPENCV_ENABLE_NONFREE=ON \
    -D CV_ENABLE_INTRINSICS=ON \
    -D CV_TRACE=ON \
    -D CV_ENABLE_CCACHE=ON \
    -D ENABLE_CXX11=ON \
    -D ENABLE_OMIT_FRAME_POINTER=ON \
    -D ENABLE_PIC=ON \
    -D WITH_1394=ON \
    -D WITH_ARITH_DEC=ON \
    -D WITH_ARITH_ENC=ON \
    -D WITH_CLP=OFF \
    -D WITH_CUDA=OFF \
    -D WITH_EIGEN=ON \
    -D WITH_FFMPEG=ON \
    -D WITH_GSTREAMER=ON \
    -D WITH_GTK=ON \
    -D WITH_IPP=ON \
    -D WITH_TBB=OFF \
    -D BUILD_TBB=OFF \
    -D WITH_ITT=ON \
    -D WITH_JASPER=ON \
    -D WITH_JPEG=ON \
    -D WITH_LAPACK=ON \
    -D WITH_OPENCVXR=ON \
    -D WITH_PNG=ON \
    -D WITH_PROTOBUF=ON \
    -D WITH_PTHREADS_PF=ON \
    -D WITH_QT=OFF \
    -D WITH_QUIRC=ON \
    -D WITH_TIFF=ON \
    -D WITH_V4L=ON \
    -D WITH_VTK=ON \
    -D WITH_LIBV4L=ON \
    -D WITH_WEBP=ON  ../

执行完毕后可以在输出靠后的地方看见如下信息,在FFMPEG对应的位置为YES则为ok,否则就是配置有问题,如果读者严格按照教程编译的,那么肯定没有问题。

--   Video I/O:
--     DC1394:                      NO
--     FFMPEG:                      YES
--       avcodec:                   YES (ver 58.101.101)
--       avformat:                  YES (ver 58.51.101)
--       avutil:                    YES (ver 56.58.100)
--       swscale:                   YES (ver 5.8.100)
--       avresample:                NO
--     GStreamer:                   
--       base:                      YES (ver 0.10.36)
--       video:                     YES (ver 0.10.36)
--       app:                       YES (ver 0.10.36)
--       riff:                      YES (ver 0.10.36)
--       pbutils:                   YES (ver 0.10.36)
--     libv4l/libv4l2:              0.9.0-test1 / 0.9.0-test1
--     v4l/v4l2:                    linux/videodev2.h

最后编译安装

make -j4
make install

将在~/opencv/install下看见所有的opencv头文件和库文件

最后测试RTSP流

可以先用ffmpeg测试流类型,如下

# 替换成自己的流地址
ffprobe -i rtsp://x.x.x.x:8888/DevAor=37030000001320000171

输出如下结果,可以看到是h264编码的yuv420p格式图像

Input #0, rtsp, from 'rtsp://x.x.x.x:8888/DevAor=37030000001320000171':
  Metadata:
    title           : sipproxy server
  Duration: N/A, start: 0.000000, bitrate: N/A
    Stream #0:0: Video: h264 (Baseline), yuv420p(progressive), 1280x720, 25 fps, 25 tbr, 90k tbn, 180k tbc

使用opencv测试
一个CMakeLists.txt文件

# test.cpp
cmake_minimum_required(VERSION 3.5)
project(test)
SET(CMAKE_CXX_FLAGS "-std=c++11")
add_executable(test test.cpp)
# 改成你自己的路径
SET(OPENCV_PATH "~/opencv/install")
set(OPENCV_LIB ${OPENCV_PATH}/lib64/libopencv_world.so
include_directories(${OPENCV_PATH}/include)
target_link_libraries(test ${OPENCV_LIB})

一个test.cpp文件

#include <iostream> // for standard I/O
#include <string>   // for strings
#include <iomanip>  // for controlling float print precision
#include <sstream>  // string to number conversion
#include <opencv2/core.hpp>     // Basic OpenCV structures (cv::Mat, Scalar)
#include <opencv2/imgproc.hpp>  // Gaussian Blur
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>  // OpenCV window I/O
using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    int psnrTriggerValue, delay;
    int frameNum = -1;          // Frame counter
    // 改成自己的流地址
    VideoCapture captRefrnc("rtsp://x.x.x.x:8888/DevAor=37030000001320000171");
    if (!captRefrnc.isOpened())
    {
        cout  << "Could not open reference "  << endl;
        return -1;
    }

    cv::Size refS = cv::Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),
                     (int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT));
    std::cout  << "refS: " << refS  << std::endl;
    cv::namedWindow("video");
    while(true) //Show the image captured in the window and repeat
    {   
    cv::Mat image;
    captRefrnc >> image;
    if (image.empty() )
    {
        cout << " < < <  Game over!  > > > ";
        break;
    }
    cv::imshow("video", image);
    cv::waitKey(1);
    }
    return 0;
}

编译执行

mkdir build
cd build
cmake ../
make
./test

opencv FLV opencv flv直播流_命令行