Skip to content

Commit da3e8ac

Browse files
fix(producer): audio always waits for video gate, even on initial start
The producer's audio gate used to skip the "wait for video" branch on initial-start sessions, on the assumption that the video gate opens at the file's first packet and audio + video naturally land at the same source-time. That assumption broke after 0842e07 made the video gate always require AV_PKT_FLAG_KEY: on MKV remuxes whose first decode-order packet isn't a sync sample (e.g. Bluey BD remuxes), the video gate now skips leading non-key packets and opens at the first IDR. Audio still anchored itself at its own first packet (much earlier in source-time), so after the per-stream PTS shift, audio's tfdt=0 represents the file's start while video's tfdt=0 represents the IDR location. AVPlayer plays them as simultaneous at time 0, but the source-content is offset by `firstKey - firstAudio` seconds — Vincent saw "audio kommt später" (audio playing the silent pre-action intro while video shows the post-intro action, then ongoing desync once audio "catches up" to a section it doesn't match). Fix: `audioWaitForVideo` is now always true at producer init. The video gate-open block sets `restartTargetAudioDts` from the actual video DTS and clears the wait. Audio packets land at the first DTS at-or-after the video keyframe, so both streams' first kept sample comes from the same source-time and the shift-to-tfdt-0 alignment holds. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 64a4f72 commit da3e8ac

1 file changed

Lines changed: 9 additions & 1 deletion

File tree

Sources/AetherEngine/Video/HLSSegmentProducer.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,15 @@ final class HLSSegmentProducer: @unchecked Sendable {
308308
// first kept audio sample is from the same source-time as
309309
// the first video keyframe we land on.
310310
self.restartTargetAudioDts = Int64.min
311-
self.audioWaitForVideo = (restartTargetVideoDts != Int64.min)
311+
// Audio always waits for video, even on initial-start. The video
312+
// gate may skip leading non-key packets while scanning for the
313+
// first AV_PKT_FLAG_KEY (some MKV remuxes have a non-IDR first
314+
// packet, e.g. Bluey BD remuxes); if audio anchored itself at
315+
// its own first packet in the meantime, the two streams' first
316+
// kept sample would come from different source-times and play
317+
// back desynced by `firstVideoKeyDts - firstAudioDts` even
318+
// though their tfdts after shift both equal 0.
319+
self.audioWaitForVideo = true
312320
self.desiredFirstVideoTfdtPts = desiredFirstVideoTfdtPts
313321
self.desiredFirstAudioTfdtPts = desiredFirstAudioTfdtPts
314322

0 commit comments

Comments
 (0)