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