FFmpeg挂起缓冲区填充c ++

时间:2017-08-29 15:54:23

标签: c++ ffmpeg buffer

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

}

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

3 个答案:

答案 0 :(得分:0)

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

如果您需要顺序完成订单,则必须使用某种结构(队列?)来在无序线程中完成订单。

答案 1 :(得分:0)

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

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

看起来你正在尝试实时编写原始帧,所以要警告:显然,fps和帧大小在所有内容的速度中起作用,但我怀疑你会看到很多丢帧。

答案 2 :(得分:0)

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

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

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