From f8150c78d5113c1dd93fccd72350cd038965cd2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sun, 7 Jun 2026 22:01:55 +0200 Subject: [PATCH] demux_mkv: don't apply AVI b-frame delay compensation to VfW tracks crazy_video_pts_stuff() shifts video PTS back by the codec delay to undo libavcodec returning frames paired with a later packet's DTS. This is only correct for genuine AVI, where DTS are decode-order frame indices. VfW-muxed Matroska looks similar but its block timestamps are real DTS, already offset by the reorder delay, so the libavcodec shift cancels the offset and no compensation is needed. Applying it anyway pushed video one frame ahead of audio (e.g. VC-1, whose Advanced Profile always reports has_b_frames=1). Split the `avi_dts` flag. Deep DTS routing for VfW mkv via a new `block_dts`, and reserve avi_dts for genuine AVI only. Note that demux_lavf for Matroska was already not affected, because `avi_dts` wouldn't be set for those. Fixes #18089 --- demux/demux_lavf.c | 2 +- demux/demux_mkv.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index c8f134c47c..bfb230855c 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -775,7 +775,7 @@ static void handle_new_stream(demuxer_t *demuxer, int i) sh->codec->dv_level = cfg->dv_level; } - // This also applies to vfw-muxed mkv, but we can't detect these easily. + // AVI uses decode-order indices as DTS and needs the compensation. sh->codec->avi_dts = matches_avinputformat_name(priv, "avi"); break; diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index acbd75f6d9..91c2a08176 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -145,6 +145,9 @@ typedef struct mkv_track { bool require_keyframes; + // VfW mode: block timestamps are real DTS, route them to the packet DTS. + bool block_dts; + /* stuff for realaudio braincancer */ double ra_pts; /* previous audio timestamp */ uint32_t sub_packet_size; ///< sub packet size, per stream @@ -1647,7 +1650,7 @@ static int demux_mkv_open_video(demuxer_t *demuxer, mkv_track_t *track) extradata = track->private_data + 40; extradata_size = track->private_size - 40; mp_set_codec_from_tag(sh_v); - sh_v->avi_dts = true; + track->block_dts = true; } else if (track->private_size >= RVPROPERTIES_SIZE && (!strcmp(track->codec_id, "V_REAL/RV10") || !strcmp(track->codec_id, "V_REAL/RV20") @@ -3108,7 +3111,7 @@ static int handle_block(demuxer_t *demuxer, struct block_info *block_info) dp->pts = current_pts + i * track->default_duration; dp->keyframe = keyframe; } - if (stream->codec->avi_dts) + if (track->block_dts) MPSWAP(double, dp->pts, dp->dts); if (i == 0 && block_info->duration_known) dp->duration = block_duration / 1e9;