I have a sample.mpg
mpegts file with a video keyframe starting at 65738.512389
$ ffprobe -hide_banner -loglevel fatal sample.mpg -select_streams v -print_format json -show_packets -read_intervals "%+#1"
{
"packets": [
{
"codec_type": "video",
"stream_index": 0,
"pts": 5916466115,
"pts_time": "65738.512389",
"dts": 5916454103,
"dts_time": "65738.378922",
"duration": 3003,
"duration_time": "0.033367",
"size": "185920",
"pos": "65048",
"flags": "K_",
"side_data_list": [
{
"side_data_type": "MPEGTS Stream ID"
}
]
}
]
}
If I remux with -copyts
, I can get the exact same timestamp 65738.512389
in the new copy:
$ ffmpeg -hide_banner -loglevel fatal -copyts -i sample.mpg -map v -c copy -mpegts_copyts 1 -f mpegts -y /dev/stdout |
ffprobe -hide_banner -loglevel fatal /dev/stdin -select_streams v -print_format json -show_packets -read_intervals "%+#1"
{
"packets": [
{
"codec_type": "video",
"stream_index": 0,
"pts": 5916466115,
"pts_time": "65738.512389",
"dts": 5916454103,
"dts_time": "65738.378922",
"duration": 3003,
"duration_time": "0.033367",
"size": "185920",
"pos": "564",
"flags": "K_",
"side_data_list": [
{
"side_data_type": "MPEGTS Stream ID"
}
]
}
]
}
Now, if I transcode instead of the remux, the first timestamp decreases by 6ms for some reason to 65738.506167
:
$ ffmpeg -hide_banner -loglevel fatal -copyts -i sample.mpg -map v -c mpeg2video -mpegts_copyts 1 -f mpegts -y /dev/stdout |
ffprobe -hide_banner -loglevel fatal /dev/stdin -select_streams v -print_format json -show_packets -read_intervals "%+#1"
{
"packets": [
{
"codec_type": "video",
"stream_index": 0,
"pts": 5916465555,
"pts_time": "65738.506167",
"dts": 5916462552,
"dts_time": "65738.472800",
"duration": 3003,
"duration_time": "0.033367",
"size": "82063",
"pos": "564",
"flags": "K_",
"side_data_list": [
{
"side_data_type": "MPEGTS Stream ID"
}
]
}
]
}
Using -debug_ts
we can see the PTS wired through the demuxer and decoder is correct (5916466115
):
demuxer -> ist_index:0 type:video next_dts:NOPTS next_dts_time:NOPTS next_pts:NOPTS next_pts_time:NOPTS pkt_pts:5916466115 pkt_pts_time:65738.5 pkt_dts:5916454103 pkt_dts_time:65738.4 off:0 off_time:0
demuxer+ffmpeg -> ist_index:0 type:video pkt_pts:5916466115 pkt_pts_time:65738.5 pkt_dts:5916454103 pkt_dts_time:65738.4 off:0 off_time:0
decoder -> ist_index:0 type:video frame_pts:5916466115 frame_pts_time:65738.5 best_effort_ts:5916466115 best_effort_ts_time:65738.5 keyframe:1 frame_type:1 time_base:1/90000
Then that's fed into the filter and encoder, but by the time it comes out of the encoder the timestamp has changed (to 5916465555
):
filter -> pts:1970185 pts_time:65738.5 exact:1970185.186501 time_base:1001/30000
encoder <- type:video frame_pts:1970185 frame_pts_time:65738.5 time_base:1001/30000
encoder -> type:video pkt_pts:1970185 pkt_pts_time:65738.5 pkt_dts:1970184 pkt_dts_time:65738.5
encoder -> type:video pkt_pts:5916465555 pkt_pts_time:65738.5 pkt_dts:5916462552 pkt_dts_time:65738.5
muxer <- type:video pkt_pts:5916465555 pkt_pts_time:65738.5 pkt_dts:5916462552 pkt_dts_time:65738.5 size:82063
It appears the 6ms discrepency is caused by the loss of precision when converting to the encoder timebase and back:
> pts = 5916466115
=> 5916466115
> pts_time = pts / 90000.0
=> 65738.51238888889
> enc_pts = pts / 90000.0 / (1001.0 / 30000)
=> 1970185.1864801864
> enc_pts_time = enc_pts * 1001.0 / 30000
=> 65738.51238888888
> enc_pts_trunc = enc_pts.round
=> 1970185
> enc_pts_trunc_time = enc_pts_trunc * 1001.0 / 30000
=> 65738.50616666667
> enc_pts_trunc_time - enc_pts_time
=> -0.006222222204087302
Sure enough, if you use -enc_time_base -1
to ensure the input timebase is used, there is no loss of precision. Unfortunately the mpeg2video
encoder doesn't accept 1/90k
as a timebase, but most other encoders do:
$ ffmpeg -hide_banner -loglevel fatal -copyts -i sample.mpg -map v -c libx264 -enc_time_base -1 -mpegts_copyts 1 -f mpegts -y /dev/stdout |
ffprobe -hide_banner -loglevel fatal /dev/stdin -select_streams v -print_format json -show_packets -read_intervals "%+#1"
{
"packets": [
{
"codec_type": "video",
"stream_index": 0,
"pts": 5916466115,
"pts_time": "65738.512389",
"dts": 5916458608,
"dts_time": "65738.428978",
"size": "68467",
"pos": "564",
"flags": "K_",
"side_data_list": [
{
"side_data_type": "MPEGTS Stream ID"
}
]
}
]
}