jdizzle
jdizzle

Reputation: 4154

ffmpeg - preserve time base and pts of all frames during transcode

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

Answers (1)

Gyan
Gyan

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

Related Questions