PTS是否必须从0开始?

时间:2018-06-28 14:14:01

标签: video ffmpeg video-streaming rtmp pts

我已经看到许多有关视频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

请注意,“时间”,比特率(0.0kbits)和速度( 135000000000x !!!!!)

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

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

这使所有内容都以毫秒为单位(1 PTS = 1 ms),但是我遇到了同样的问题(大量时间,零比特率和巨大速度)

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

更新

查看@Gyan的答案后,我将命令的格式设置为:

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

通过这种方式,PTS值将匹配“流开始后的毫秒数”,并且将被流的开始时间所抵消(理论上使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

这仅返回单个视频帧,该视频帧的PTS不像我期望的那样大:

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

这是一个非常困难的任务

1 个答案:

答案 0 :(得分:2)

这使所有内容都以毫秒为单位(1 PTS = 1 ms),但是我遇到了同样的问题(大量时间,零比特率和巨大速度)

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


如果容器允许,则可以从非零PTS开始。建议这样做是使用选项-output_ts_offset N,其中N以秒为单位。

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