Reputation: 4154
Context:
I have an application that produces mp4s with HEVC encoding. I want to convert them to AVC for use in browser-based displaying. A very crucial part of how I want to use this is to preserve exact PTS times, as this is how we correlate the frames to other data streams not included in the video.
Question:
How do I make ffmpeg preserve this information across the transcode? All the obvious flags seem to have no effect and ffmpeg just does whatever it wants.
$ ffprobe -show_streams original.mp4 2>/dev/null | grep time_base
codec_time_base=16666667/500000000
time_base=1/1000
Here is my convert command:
$ ffmpeg -i original.mp4 -copyts -copytb 0 test.mp4
And its result:
$ ffprobe -show_streams test.mp4 2>/dev/null | grep time_base
codec_time_base=1/60
time_base=1/15360
I would expect the time_bases to match. The PTS of the frames also don't match when doing ffprobe -show_frames
EDIT: @Gyan suggested using -video_track_timescale, but that didn't get the exact behavior I was looking for:
$ sdiff <(ffprobe -show_frames test.mp4 | grep pkt_pts_time) <(ffprobe -show_frames original.mp4 | grep pkt_pts_time)
pkt_pts_time=0.000000 pkt_pts_time=0.000000
pkt_pts_time=0.033000 pkt_pts_time=0.033000
pkt_pts_time=0.067000 | pkt_pts_time=0.066000
pkt_pts_time=0.100000 pkt_pts_time=0.100000
pkt_pts_time=0.133000 pkt_pts_time=0.133000
pkt_pts_time=0.167000 | pkt_pts_time=0.166000
pkt_pts_time=0.200000 pkt_pts_time=0.200000
pkt_pts_time=0.233000 pkt_pts_time=0.233000
pkt_pts_time=0.267000 | pkt_pts_time=0.266000
pkt_pts_time=0.300000 pkt_pts_time=0.300000
pkt_pts_time=0.333000 pkt_pts_time=0.333000
pkt_pts_time=0.367000 | pkt_pts_time=0.366000
pkt_pts_time=0.400000 pkt_pts_time=0.400000
pkt_pts_time=0.433000 pkt_pts_time=0.433000
pkt_pts_time=0.467000 pkt_pts_time=0.467000
pkt_pts_time=0.500000 pkt_pts_time=0.500000
pkt_pts_time=0.533000 | pkt_pts_time=0.532000
pkt_pts_time=0.567000 | pkt_pts_time=0.565000
pkt_pts_time=0.600000 | pkt_pts_time=0.598000
pkt_pts_time=0.633000 | pkt_pts_time=0.631000
pkt_pts_time=0.667000 | pkt_pts_time=0.665000
pkt_pts_time=0.700000 | pkt_pts_time=0.698000
...
Upvotes: 3
Views: 6765
Reputation: 93261
You'll need to set 3 parameters to obtain identical timestamps: -vsync 0
to avoid frame duplication and timebase adjustment, -enc_time_base -1
to avoid timebase adjustment at the encoder layer, and -video_track_timescale
with the inverse of the source timebase.
ffmpeg -i original.mp4 -vsync 0 -enc_time_base -1 -video_track_timescale 1000 test.mp4
Note that with default encoding parameters, B-frames are turned on for the default encoder (libx264 for MP4) and so the frames will be stored in decoding order which is not the same as presentation order. Add -bf 0
to switch this off.
Upvotes: 8