Ffmpeg 如何将包含B帧且没有DTS的视频流写入MP4容器?

Ffmpeg 如何将包含B帧且没有DTS的视频流写入MP4容器?,ffmpeg,mp4,rtsp,rtp,muxer,Ffmpeg,Mp4,Rtsp,Rtp,Muxer,我想将从RTSP源接收的h264视频流保存到MP4容器中。 与其他问题不同,我面临的挑战如下: 该流包含B帧 流只有RTP/RTCP给出的PTS 这是我做的代码 // ffmpeg pkt->data = ..; pkt->size = ..; pkt->flags = bKeyFrame? AV_PKT_FLAG_KEY : 0; pkt->dts = AV_NOPTS_VALUE; pkt->pts = PT

我想将从RTSP源接收的h264视频流保存到MP4容器中。 与其他问题不同,我面临的挑战如下:

  • 该流包含B帧

  • 流只有RTP/RTCP给出的PTS

这是我做的代码

//  ffmpeg
    pkt->data = ..;
    pkt->size = ..;
    pkt->flags = bKeyFrame? AV_PKT_FLAG_KEY : 0;    
    pkt->dts = AV_NOPTS_VALUE;
    pkt->pts = PTS;

    // PTS is based on epoch microseconds so I ignored re-scaling.
    //av_packet_rescale_ts(pkt, { 1, AV_TIME_BASE }, muxTimebase);

    auto ret = av_interleaved_write_frame(m_pAVFormatCtx, pkt);
我收到了很多这样的错误消息: “应用程序向muxer提供了无效的、非单调递增的dts…”

结果:mp4文件可通过VLC播放,但FPS仅为原始FPS的一半,视频持续时间不正确(VLC显示一个奇怪的数字)

那么,在发送到容器之前,如何设置正确的DTS和PTS呢

更新: 我尝试了一些更改,虽然还没有成功,但我发现帧速率下降的原因是由于muxer丢弃了具有错误DTS的帧。 此外,如果我将PTS和DTS的起始值设置得太大,像VLC这样的一些播放器在显示视频之前必须延迟一段时间。

这是不正常的,“流只有RTP/RTCP给出的PTS。”。这里有点不对劲。
如果没有dts,这意味着您应该只使用pts。如果真的有B帧,那么dts值将不同于pts


试一下你的代码,看看会发生什么。

我做了几个实验,有些东西要和你分享

  • 无论是否有B帧,mp4 muxer要求DTS必须(至少):

    • 单调增加的

    • DTS@kamilz这里没有问题。正如我前面提到的,流来自RTSP源,自然没有可以从RTSP流检索的DTS。当dts不存在时,“try pts=dts”是什么意思?即使您真正的意思是“dts=pts”,它也不会起作用,因为dts必须线性增加。我试着根据pts和帧速率计算dts。是的,我的意思是“dts=pts”。不管怎样,你确定吗?“当然,您无法从RTSP流媒体检索DTS。”是的,我是。RTP/RTCP通道中不携带DTS,除非您将其发送到带外。您可以在RTSP RFC中进行检查。我明白了。。因此,在这种情况下,您可以告诉源代码为dts发送oob数据,也可以不使用b帧。我看不到另一个解决办法。但是如果你发现了什么,请分享。我真的很好奇你是否能制作出正确的dts。当然,我会在有了解决方案后分享。谢谢你的关注。
      // Initialize container
      
          pAVStream->time_base = { 1, AV_TIME_BASE }; // PTS/DTS in microseconds.
          pAVFormatCtx->oformat->flags |= AVFMT_SEEK_TO_PTS;
          ret = avformat_write_header(m_pAVFormatCtx, &priv_opts);
      
          Assume that you have pre-calculated average duration: 
          nAvgDuration = 33'333LL;
      
          //  Per each frame
      
          if (waitingForTheFirstKeyFrame) {
              if (!bsKeyFrame) {
                  return false;
              }
      
              waitingForTheFirstKeyFrame = false;
              nPTSOffset = nPTS; // pts will start from 0
              nStartDTS = nPTS - nAvgDuration; // dts will start from -nAvgDuration
          }
      
          nDTS = nStartDTS;
          nStartDTS += nAvgDuration; // dts is monotonically increasing
      
          pkt->pts = nPTS - nPTSOffset;
          pkt->dts = nDTS - nPTSOffset;
      
          //  Since PTS/DTS are in microseconds, no need to rescalling more.
          //  Of course, you can use a different time_base.
      
          auto ret = av_interleaved_write_frame(m_pAVFormatCtx, pkt);