FFmpeg卡在缓冲填充中(C++)

10
我正在使用ffmpeg处理来自RTSP流的一堆帧。 我对这些帧进行了许多处理,这意味着我并不总是实时地获取数据。如果缓冲区变满,进程将挂起。 我想知道以下哪个解决方案可行/能够解决问题,如果可以,如何使用ffmpeg库实现:

1)如果我遇到挂起的情况,是否有一种清除缓冲区的方法? 我可以确定何时出现挂起,但不知道该怎么解决它。
2)是否有一种使缓冲区覆盖旧数据,只读取最新数据的方法? 如果丢失帧对我来说无关紧要。
3)我已经发现可以使用以下代码将缓冲区任意扩大:av_dict_set(& avd,“buffer_size”,“655360”,0); 。 这可能是一种解决方案,但我不知道需要多大/小的缓冲区,因为我不知道流会发布视频多长时间?
4)这只是我需要与ffmpeg团队提出的错误吗?
5)还有其他没有考虑的方法吗?
while(av_read_frame(context, &(packet)) >= 0 && fcount < fps*SECONDS) {
    clock_t start, end;
    int ret = avcodec_send_packet(codec_context, packet);
    if(!(packet->stream_index == video_stream_index)) {
      continue;
    }

    if (ret == AVERROR(EAGAIN) || ret == AVERROR(EINVAL)) {
      continue;
    } else if (ret < 0) {
      cerr << "Error while decoding frame " << fcount << endl;
      exit(1);
    }

    ret = avcodec_receive_frame(codec_context, frame);
    if (ret == AVERROR(EAGAIN) || ret == AVERROR(EINVAL)) {
      continue;
    } else if (ret < 0) {
      cerr << "Error while decoding frame " << fcount << endl;
      exit(1);
    }

    sws_scale(img_convert_ctx, frame->data, frame->linesize, 0,
              codec_context->height, picture_rgb->data, picture_rgb->linesize);

    if(!frame) {
      cerr << "Could not allocate video frame" << endl;
      exit(1);
    }

    if(codec_context == NULL) {
      cerr << "Cannot initialize the conversion context!" << endl;
      exit(1);
    }

    // Do something with the frame here

    fcount++;
    av_packet_unref(&(packet));

}

我已添加导致程序挂起的代码。


2
这里没有代码,所以任何人都无法猜测出问题出在哪里。这并不足以重现问题。 - tadman
1
@tadman,这些代码足够让你猜出问题了吗? 我试图表明我已经调试了问题,并发现缓冲区是问题所在。这就是为什么我建议了一些具体的解决方案并询问了它们是否可行。但我理解你想要看到代码的原因,所以我已经添加了它。 - Derek Halden
1
上下文很重要。你最初的问题有点太假设了。 - tadman
这个方案对你有帮助吗?https://dev59.com/Hm3Xa4cB1Zd3GeqPiL-c - kvr
@kvr,那似乎没有帮助。 - Derek Halden
显示剩余10条评论
3个回答

0

缓冲区大小是套接字选项,在底层中,如果缓冲区已满,ffmpeg 可能会在其套接字 recv 调用上阻塞。经过查看 ffmpeg 代码,似乎它们对于纯 UDP 流有一个循环缓冲区的 FIFO 大小选项,但对于 RTP 流则禁用了该选项。

为确保缓冲区永远不会被填满,我会在一个线程中运行所有 pkt 接收和帧解码操作,并将其馈送到自己的线程安全循环缓冲区中。树莓派应该能够跟上解码的速度,但如果不能,我会考虑硬件辅助解码。关键是确保您的分离和解码维护实时速度。您可以在其他线程中处理所有调整大小、处理和帧写入,并相应地设置循环缓冲区大小以处理溢出。

看起来您正在尝试实时编写原始帧,因此警告一句话:显然,fps 和帧大小在所有速度中都起着作用,但我怀疑您会看到很多丢帧。


掉帧没关系。当我解码过快时,似乎遇到了不同的问题。即:当我将分离/解码放入单独的线程时,会产生错误。 - Derek Halden
此外,将其他进程运行在单独的线程中可以获得额外的性能提升。因此,对于我来说,在多线程处理该过程并不理想。 - Derek Halden
你有相关的代码吗?我对ffmpeg不是很熟悉。 - Saeed Masoomi

0
你可以尝试使用多线程技术。每一帧都由一个独立的线程处理(使用线程池)。
如果你需要按顺序完成,你需要使用某种结构(队列?)来使无序的线程完成时间有序化。

不幸的是,我认为这并不意味着我能够比从流中添加的速度更快地处理帧。其中一个原因是它在处理能力方面类似于树莓派。此外,我已经在多线程另一个进程。 - Derek Halden

0

这应该是一个提示而不是直接解决您的问题。 使用ffmpeg将流转换为帧时缓冲

您应该尝试的是记录流并将其缓存到存储中,然后再进行转换。您还可以尝试将缓冲区缓存到磁盘并重新提供给ffmpeg进程。

一个hacky的解决方案是将RTSP流转换为UDP,这实际上非常容易,然后使用UDP的ffmpeg内部缓冲选项,这些选项对于RTSP是禁用的。


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