为什么最后一帧没有显示在 libav 生成的 MP4 中?

Why is the last frame not showing in an MP4 generated by libav?

提问人:Ben 提问时间:11/1/2023 最后编辑:Ben 更新时间:11/1/2023 访问量:31

问:

注意:我这里有一个问题的工作示例。

我正在使用 libav/ffmpeg API 生成带有 h4 编解码器的 MP264。在我的特定情况下,我正在生成最大数量为 2 个“B”帧的文件。我能够生成具有正确帧数的 Mp4,以便单个单独的“B”帧是正在写入的最后一帧。发生这种情况时,编码器会将该帧的数据包设置为丢弃(我已经用ffprobe验证了这一点)。最终结果是,某些播放器(例如,将 MP4 放入 Edge 或 Chrome 时)将仅显示 n-1 帧(忽略丢弃的数据包)。其他播放器,例如 VLC,将播放完整的 n 帧(不忽略丢弃的数据包)。因此,结果是不一致的。

ffmpeg.exe本身似乎没有这个问题。相反,它会将唯一的“B”帧设置为“P”帧。这意味着无论使用什么播放器,文件都将播放相同的内容。

问题是:我不知道如何使用 SDK 模仿 ffmpeg 的行为,因此无论播放器如何,最后一帧都会播放。据我所知,我通过刷新编码器缓冲区来正确关闭文件。我一定在某个地方做错了什么。

我提供了指向上面完整源代码的链接,但在高层次上,我正在初始化编解码器上下文和流,如下所示:

newStream->codecpar->codec_id = AV_CODEC_ID_H264;
newStream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
newStream->codecpar->width = Width;
newStream->codecpar->height = Height;
newStream->codecpar->format = AV_PIX_FMT_YUV420P;
newStream->time_base = { 1, 75 };
avcodec_parameters_to_context(codecContext, newStream->codecpar);


codecContext->time_base = { 1, 75 };
codecContext->gop_size = 30;

然后,我坐在一个循环中,使用 OpenCV 生成帧(每个帧上都绘制了帧号):

auto matrix = cv::Mat(Height, Width, CV_8UC3, cv::Scalar(0, 0, 0));

std::stringstream ss;
ss << f; 

cv::putText(matrix, ss.str().c_str(), textOrg, fontFace, fontScale, cv::Scalar(255, 255, 255), thickness, 8);

然后我像这样写出帧(如果需要更多数据,则循环):

if ((ret = avcodec_send_frame(codecContext, frame)) == 0) {

   ret = avcodec_receive_packet(codecContext, &pkt); 

   if (ret == AVERROR(EAGAIN))
   {
       continue; 
   }
   else
   {
       av_interleaved_write_frame(pFormat, &pkt);
   }
   av_packet_unref(&pkt);
}

最后,我像这样在最后刷新文件:

if ((ret = avcodec_send_frame(codecContext, NULL)) == 0)
{
  for (;;)
  {
     if ((ret = avcodec_receive_packet(codecContext, &pkt)) == AVERROR_EOF)
     {
       break;
     }
     else
     {
       ret = av_interleaved_write_frame(pFormat, &pkt);
       av_packet_unref(&pkt);
     }
  }

  av_write_trailer(pFormat);
  avio_close(pFormat->pb);
}

然而,当我在 Chrome 中玩游戏时,播放器在第 6758 帧结束,

enter image description here

在 VLC 中,播放器在第 6759 帧结束。

enter image description here

我做错了什么?

C++ ffmpeg libav libavcodec libavformat

评论


答: 暂无答案