在Ubuntu上使用OpenCV的ffmpeg解码H264(高级)流

7

我正在使用 Ubuntu 14.04 处理来自 IP 摄像机的视频流。一切都很顺利,摄像头的参数如下(来自 FFMPEG):

    Stream #0:0: Video: h264 (Main), yuv420p(progressive), 352x192, 29.97 tbr, 90k tbn, 180k tbc

然后我换了一台新相机,其参数如下:

    Stream #0:0: Video: h264 (High), yuvj420p(pc, bt709, progressive), 1280x720, 25 fps, 25 tbr, 90k tbn, 50 tbc

我的C++程序使用OpenCV3来处理流数据。默认情况下,OpenCV使用ffmpeg来解码和显示流数据,使用VideoCapture函数。

VideoCapture vc;
vc.open(input_stream);
while ((vc >> frame), !frame.empty()) {
   *do work*
}

使用新的相机流时,我会遇到像这样的错误(来自ffmpeg):

[h264 @ 0x7c6980] cabac decode of qscale diff failed at 41 38
[h264 @ 0x7c6980] error while decoding MB 41 38, bytestream (3572)
[h264 @ 0x7c6980] left block unavailable for requested intra mode at 0 44
[h264 @ 0x7bc2c0] SEI type 25 truncated at 208

图像有时会出现故障,有时完全冻结。然而,在VLC上播放完美。我使用最新版本(3.2.2)的FFmpeg播放器安装了它。

./configure --enable-gpl --enable-libx264

现在直接使用ffplay进行播放(而不是通过OpenCV函数VideoCapture从源代码中启动),流媒体播放效果更好,但有时仍会显示警告:

[NULL @ 0x7f834c008c00] SEI type 25 size 896 truncated at 320=1/1   
[h264 @ 0x7f834c0d5d20] SEI type 25 size 896 truncated at 319=1/1   
[rtsp @ 0x7f834c0008c0] max delay reached. need to consume packet   
[rtsp @ 0x7f834c0008c0] RTP: missed 1 packets
[h264 @ 0x7f834c094740] concealing 675 DC, 675 AC, 675 MV errors in P frame

更换摄像机硬件不是一个选项。 摄像机可以设置为编码为h265或mjpeg格式。 当编码为mjpeg格式时,它可以输出5帧每秒的速度,这是不够的。另外,解码为静态视频也不是一个选项,因为我需要实时显示有关流的结果。在这里有一个可以在函数VideoCapture中使用的API后端列表。也许我应该切换到其他解码器和播放器?
从我的研究中,我得出以下选项:
  • 以某种方式使OpenCV使用libVlc而不是ffmpeg

切换到vlc的一个例子可以在这里找到,但我不理解它是否符合我的需求。或者也许我应该在代码中对流进行解析

  • 使用vlc预处理流,如此处所建议。

这可能会很慢,这对于实时结果来说又是不好的。
任何建议和评论都将不胜感激。

3个回答

3

我已经基本解决了这个问题。

  • 首先,我手动重新编译了OpenCV,并使用必要的设置在我的设备上安装了最新版本的ffmpeg。
  • 我使用VLC的工具 > 编解码器信息检查流是否有损坏的帧,结果没有。
  • 我降低了流的分辨率。这是最大的改进。
  • 但我仍然遗留了最后一个错误:

    [NULL @ 0x7f834c008c00] SEI类型25大小896截断于320=1/1
    [h264 @ 0x7f834c0d5d20] SEI类型25大小896截断于319=1/1

但它并不会明显破坏帧。我还没有解决流冻结的问题,但这与我的代码有关,而不是软件。如果我能帮助到有类似问题的任何人,请随时询问其他信息。


3

默认情况下,它使用RTP导致错误是由于数据包丢失造成的。现在您看到更多的错误是因为您切换到了更高比特率的输入。

在OpenCV的open函数中添加?tcp以强制使用TCP,例如rtsp://*private*/media/video2?tcp,前提是您的硬件和/或使用场景支持它。


附加后,但流仍在大约10秒后冻结,这在旧相机流中不会发生,也不会在从ffplay直接播放时发生。 - arvids
当直接从编译有h264库的ffplay播放时。 - arvids
1
如果您需要使用ffplay进行测试,请使用-rtsp_transport tcp - aergistal

0

经过4天的研究,我也遇到了同样的问题。最终,我通过这段代码轻松地解决了它:

for(;;) {
        if(!vcap.read(image)) {
            std::cout << "No frame" << std::endl;
            cv::waitKey();
        }
        cv::imshow("Output Window", image);
        if(cv::waitKey(1) >= 0) break;
    }   

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接