PTS一定要从0开始吗?

Does PTS have to start at 0?

我看到很多关于视频 PTS 值不是从零开始的问题,或者询问如何让它们从零开始。我知道使用 ffmpeg 我可以做类似 ffmpeg -i <video> -vf="setpts=PTS-STARTPTS" <output> 的事情来修复这种事情

不过据我了解,PTS 值不会从零开始。例如,如果你加入直播,那么很可能它已经持续了一个小时,而 PTS 已经在 3600000+ 左右,但你的视频播放器忠实地显示一切都很好。因此,如果我有意创建一个 PTS 值从当前挂钟时间开始的视频,我希望不会有问题。

我想使用 ffmpeg 发送实时流,但将当前时间嵌入到流中。这既可以用于流直播时的延迟计算,也可以用于确定流最初播出的时间。根据我对 PTS 的理解,像这样简单的东西应该可以工作:

ffmpeg -i video.flv -vf="setpts=RTCTIME" rtmp://<output>

然而,当我尝试这个时,ffmpeg 输出如下:

frame=   93 fps= 20 q=-1.0 Lsize=    9434kB time=535020:39:58.70 bitrate=   0.0kbits/s speed=1.35e+11x

请注意 "time"、比特率 (0.0kbits) 和速度 (135000000000x! !!)

起初我认为问题可能是我的时基问题,所以我尝试了以下方法:

ffmpeg -i video.flv -vf="settb=1/1K,setpts=RTCTIME/1K" rtmp://<output>

这一切都以毫秒为单位(1 PTS = 1 毫秒),但我遇到了同样的问题(大量时间、零比特率和大量速度)

我是不是对 PTS 有什么误解?是否不允许从非零值开始?还是我做错了什么?

更新

查看@Gyan 的回答后,我将我的命令格式化为:

ffmpeg -re -i video.flv -vf="settb=1/1K, setpts=(RTCTIME-RTCSTART)/1K" -output_ts_offset $(date +%s.%N) rtmp://<output>

这样 PTS 值将匹配 "milliseconds since the stream started" 并且会被流的开始时间偏移(理论上使 PTS = 服务器上的时间戳)

这看起来编码更好:

frame=  590 fps=7.2 q=22.0 size=   25330kB time=00:01:21.71 bitrate=2539.5kbits/s dup=0 drop=1350 speed=   1x 

比特率现在是正确的,时间是准确的,速度也不是离谱的。不过,每秒帧数仍然有点偏差(源视频是 24 fps,但它报告每秒 7.2 帧)

当我尝试从另一端观看流时,视频与音频不同步并以大约两倍正常速度播放了一会儿,然后视频冻结,音频继续没有它

此外,当我将流转储到文件 (ffmpeg -i rtmp://<output> dump.mp4) 并使用 ffprobe (ffprobe -show_entries packet=codec_type,pts dump.mp4 | grep "video" -B 1 -A 2) 查看 PTS 时间戳时,时间戳似乎根本不显示服务器时间:

...
--
[PACKET]
codec_type=video
pts=131072
[/PACKET]
[PACKET]
codec_type=video
pts=130048
[/PACKET]
--
[PACKET]
codec_type=video
pts=129536
[/PACKET]
[PACKET]
codec_type=video
pts=130560
[/PACKET]
--
[PACKET]
codec_type=video
pts=131584
[/PACKET]

是否只是与 RTMP 不兼容的问题?

更新 2

我已经删除了视频过滤器,现在我正在这样编码:

ffmpeg -re -i video.flv -output_ts_offset $(date +%s.%N) rtmp://<output>

编码正确:

frame=  910 fps= 23 q=25.0 size=   12027kB time=00:00:38.97 bitrate=2528.2kbits/s speed=0.981x 

为了验证 PTS 值是否正确,我将输出转储到一个文件中,如下所示:

ffmpeg -i rtmp://<output> -copyts -write_tmcd 0 dump.mp4

我尝试将其保存为 dump.flv(因为它是 RTMP)但是这引发了错误:

[flv @ 0x5600f24b4620] Audio codec mp3 not compatible with flv

这有点奇怪,因为视频不是 mp3 编码的(它是 speex)- 但无论如何。

转储此文件时,重复弹出以下错误:

frame=    1 fps=0.0 q=0.0 size=       0kB time=00:00:09.21 bitrate=   0.0kbits/s dup=0 dr
43090023 frame duplication too large, skipping
43090027 frame duplication too large, skipping
    Last message repeated 3 times
43090031 frame duplication too large, skipping
    Last message repeated 3 times
43090035 frame duplication too large, skipping

在 VLC 中播放生成的视频会播放音频流但不显示视频。然后我尝试用 ffprobe 探测这个视频以查看视频 PTS 值:

ffprobe -show_entries packet=codec_type,pts dump.mp4 | grep "video" -B 1 -A 2

这returns只有一个视频帧,其 PTS 并不像我预期的那样大:

[PACKET]
codec_type=video
pts=1020
[/PACKET]

这是一项异常艰巨的任务

这一切都以毫秒为单位(1 PTS = 1 毫秒)但我遇到了同样的问题(大量时间、零比特率和大量速度)

这只是统计计算的一个副作用,它不参考观察到的起始 PTS 来衡量时间。比特率 (bits/second) 和速度(输出持续时间/实时)计算只是这种设计的牺牲品。


如果容器允许,可以从非零PTS开始。执行此操作的明智方法是使用选项 -output_ts_offset N,其中 N 以秒为单位。

在编码之前更改时间戳是有风险的,因为 ffmpeg 的帧率转换方法使用时间戳来检查同步漂移并做出有关丢弃或复制帧的决定。对于 CFR 输出尤其重要。编码器的速率控制流程也可能会失控。