OpenCV FFMPEG RTSP 相机馈送错误

Posted

技术标签:

【中文标题】OpenCV FFMPEG RTSP 相机馈送错误【英文标题】:OpenCV FFMPEG RTSP Camera Feed Errors 【发布时间】:2020-09-24 13:55:02 【问题描述】:

从 rtsp 相机源中保存帧时,我会随机收到这些错误。错误发生在不同的时间,通常在保存 100-200 张图像之后,并且错误本身并不总是完全相同。它们会导致错误发生时保存的图像失真到完全灰色或包含失真像素。

#Frame_142 - [hevc @ 0c3bf800] The cu_qp_delta 29 is outside the valid range [-26, 25].

#Frame_406 - [hevc @ 0b6bdb80] Could not find ref with POC 41

我尝试在 python 和 c++ 中实现代码,结果相同。还尝试另存为 .png 而不是 .jpg。使用 imshow 显示相机时 rtsp 提要工作正常,该问题仅在尝试保存帧时出现。据我所知,这些错误与 ffmpeg 有关,但谷歌对这些类型的错误没有太大帮助。

#include <iostream>
#include <opencv2\opencv.hpp>
#include <chrono>
#include <thread>

using namespace std;
using namespace cv;

int main() 

    VideoCapture cap("rtsp://admin:admin@192.168.88.97/media/video1");
    if (!cap.isOpened())
        return -1;

    for (int i = 0; i < 500; i++)
    
        Mat frame;
        cap >> frame;
        imwrite("C:\\Users\\Documents\\Dev\\c++\\OpenCVExample\\frames\\frame" + std::to_string(i) + ".png", frame);
        cout << i << "\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(10));

    

    return 0;

【问题讨论】:

在写成if(frame.data)之前尝试检查框架是否有效。这可能与问题无关,但也是一个缺失点。检查here 【参考方案1】:

OpenCV 和 RTSP 流有点棘手。这通常发生在无法足够快地读取流的帧时。在这种情况下(某处)接收 RTSP 帧的缓冲区将被填充得比清空快;当缓冲区已满时,它将被刷新并从最近的帧重新开始填充。这将破坏流解码,直到下一个keyframe。

我的建议是删除sleep,即使 10 毫秒非常小。由于这还不够 (:P),唯一的解决方案是实现一个线程不断地从 cv::VideoCapture 读取帧,并在主线程忙于保存前一帧时丢弃抓取的帧。

一个简单的实现可能是:

#include <opencv2/opencv.hpp>
#include <thread>

class VideoSourceHandler

public:
  // Video file or IP camera
  VideoSourceHandler( const std::string & source ) :
    mCapture( source ),
    mRun( false )
  
  

  // USB camera
  VideoSourceHandler( int webcamID ) :
    mCapture( webcamID ),
    mRun( false )
  
  

  // start and stopCapture can be squashed into C'tor and D'tor if you want RTTI
  void startCapture()
  
    mRun = true;
    mLoopThread = std::thread( &VideoSourceHandler::threadLoop, this );
  

  void stopCapture()
  
    mRun = false;
    mLoopThread.join();
  

  cv::Mat getFrame()
  
    std::this_thread::yield(); // Be nice
    const std::lock_guard<std::mutex> lock( mMutex );
    return mCurrentFrame;
  

private:
  void threadLoop()
  
    while( mRun )
    
      // Sleep if you want to "control" FPS
      
        const std::lock_guard<std::mutex> lock( mMutex );
        mCapture >> mCurrentFrame;
      
      std::this_thread::yield(); // Be nice
    
  

  cv::VideoCapture mCapture;
  std::thread      mLoopThread;
  std::mutex       mMutex;
  bool             mRun;
  cv::Mat          mCurrentFrame;
;

int main()

  VideoSourceHandler vsh( 0 );
  vsh.startCapture();
  while( true )
  
    cv::Mat frame = vsh.getFrame();
    if( frame.empty() )
      continue;

    cv::imshow( "Test", frame );
    char key = cv::waitKey( 1 );
    if( key == 'q' || key == 27 )
      break;

  
  vsh.stopCapture();
  return 0;

【讨论】:

这个答案让我改变了来自解决问题的相机的帧速率。将帧速率从 25 fps 降至 10fps 后,错误停止出现。谢谢!【参考方案2】:

将视频压缩更改为 H.264 为我解决了这个问题。

【讨论】:

以上是关于OpenCV FFMPEG RTSP 相机馈送错误的主要内容,如果未能解决你的问题,请参考以下文章

ffmpeg接收rtsp流问题

将 RTSP 信号与 FFMPEG 同步

FFmpeg 播放 RTSP/Webcam 流

ffmpeg解码到opencv Mat中

使用ffmpeg命令推送rtsp流,不包含SPS和PPS帧

来自 RTSP 流的 H.264 解码错误日志