【问题标题】:FFmpeg hangs on buffer fill c++FFmpeg 挂在缓冲区填充 C++
【发布时间】:2018-02-07 04:03:37
【问题描述】:

我正在使用 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));

}

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

【问题讨论】:

  • 这里没有代码,所以任何人都可以猜猜出了什么问题。这些信息不足以重现问题。
  • @tadman,这些代码足以让您猜出问题所在吗?我试图暗示我已经调试了问题,并发现缓冲区是问题所在。这就是为什么我提出了我所询问的具体解决方案。我真的主要是在寻找这些解决方案是否可行。但是我理解你为什么想看代码,所以我添加了它。
  • 上下文很重要。您最初的问题有点过于假设了。
  • 这里的解决方案有帮助吗? stackoverflow.com/questions/14558172/…
  • @kvr 我可能会在明天进行测试,如果能解决问题,请告诉您。

标签: c++ ffmpeg buffer


【解决方案1】:

您可以尝试使用多线程。每个帧都由一个单独的线程处理(使用线程池)。

如果您需要顺序完成顺序,您将不得不使用一些结构(队列?)来为无序线程完成时间带来顺序。

【讨论】:

  • 不幸的是,我认为这并不意味着我能够比从流中添加帧更快地处理帧。这很慢的原因之一是,就处理能力而言,我在类似于树莓派的东西上运行它。另外,我已经在处理另一部分的多线程。
【解决方案2】:

缓冲区大小是一个套接字选项,如果缓冲区已满,ffmpeg 可能会阻塞其套接字 recv 调用。查看 ffmpeg 代码后,似乎他们有一个 FIFO 大小选项,用于纯 UDP 流上的循环缓冲区,但对于 RTP 流,这是禁用的。

为了确保缓冲区永远不会变满,我将在一个线程中运行所有 pkt recv 和帧解码操作,并将其提供给我自己的线程安全循环缓冲区。 raspi 应该能够跟上解码的速度,但如果不是,我会研究硬件辅助解码。关键是,确保您的解复用和解码保持实时速度。您可以在其他线程中处理所有调整大小、处理和帧写入,并相应地设置循环缓冲区大小以处理溢出。

您似乎正在尝试实时写入原始帧,所以请注意:显然,fps 和帧大小对一切速度都有影响,但我怀疑您会看到很多丢帧。

【讨论】:

  • 丢帧没问题。当我解码太快时,我似乎遇到了另一个问题。 IE。当我将解复用/解码放入单独的线程时,我出错了。
  • 另外,我通过在单独的线程中运行我的其他进程获得了单独的性能提升。出于这个原因,多线程这部分过程对我来说并不理想。
  • 你有任何代码吗?我对ffmpeg不是很熟悉
【解决方案3】:

这应该是一个提示,而不是您的问题的直接解决方案。 Buffering while converting stream to frames with ffmpeg

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

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

【讨论】:

    猜你喜欢
    • 2011-02-20
    • 2012-02-04
    • 2013-02-21
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多