Ffmpeg 如何将包含B帧且没有DTS的视频流写入MP4容器?
我想将从RTSP源接收的h264视频流保存到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
- 该流包含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
试一下你的代码,看看会发生什么。我做了几个实验,有些东西要和你分享
- 单调增加的
- 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);