mux: B1 drop-to-keyframe resync after a concealed gap
Pairs with A2 (read-path NULL-TS concealment). When the demux assembler sees a TS continuity gap it now stamps `discontinuity` on the next completed PES; the codec-parse stage carries that onto a per-track ResyncGate. After a gap on an inter-coded video track the gate drops forward to the next IRAP/IDR keyframe so no frame with a dangling reference reaches the muxer (an ffmpeg deep scan would otherwise report a missing-reference / non-existing-PPS error). Audio and subtitle tracks have no cross-frame references, so the gate is a no-op there. - ts.rs: PesPacket gains `discontinuity`; PesAssembler tracks a sticky pending_discontinuity flag set on CC gap / discontinuity_indicator and carried to the next completed/flushed PES. - resync.rs (new): ResyncGate — per-track arm-on-gap, drop non-keyframes until the next keyframe disarms and resumes. Logs the resync + drop count once at the keyframe. - pipelined_stream.rs: precompute per-track is_video, apply the gate in consume_ts. Out-of-range track index emits as-is (defensive). Tests: ResyncGate unit tests; ts.rs gap-stamps-discontinuity; end-to-end B1 video-drops-to-keyframe and audio-never-drops through PipelinedPesStream.
This commit is contained in:
@@ -450,6 +450,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: None,
|
||||
data: vec![],
|
||||
discontinuity: false,
|
||||
};
|
||||
assert!(parser.parse(&pes).is_empty());
|
||||
}
|
||||
@@ -464,6 +465,7 @@ mod tests {
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
data: frame_data.clone(),
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames = parser.parse(&pes);
|
||||
assert_eq!(frames.len(), 1);
|
||||
@@ -483,6 +485,7 @@ mod tests {
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
data: frame_data[..mid].to_vec(),
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames1 = parser.parse(&pes1);
|
||||
assert!(frames1.is_empty(), "partial frame should not emit");
|
||||
@@ -494,6 +497,7 @@ mod tests {
|
||||
pts: Some(93000),
|
||||
dts: None,
|
||||
data: frame_data[mid..].to_vec(),
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames2 = parser.parse(&pes2);
|
||||
assert_eq!(frames2.len(), 1);
|
||||
@@ -512,6 +516,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames = parser.parse(&pes);
|
||||
assert_eq!(frames.len(), 1);
|
||||
@@ -535,6 +540,7 @@ mod tests {
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
data: pes1_data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames1 = parser.parse(&pes1);
|
||||
assert_eq!(frames1.len(), 1, "first complete frame emitted");
|
||||
@@ -548,6 +554,7 @@ mod tests {
|
||||
pts: Some(93000),
|
||||
dts: None,
|
||||
data: pes2_data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames2 = parser.parse(&pes2);
|
||||
assert_eq!(frames2.len(), 1, "split-sync frame must be recovered");
|
||||
@@ -574,6 +581,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames = parser.parse(&pes);
|
||||
assert!(frames.is_empty());
|
||||
@@ -602,6 +610,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
assert!(parser.parse(&pes).is_empty());
|
||||
assert_eq!(parser.buf, vec![0x0B], "lone trailing 0x0B retained");
|
||||
@@ -639,6 +648,7 @@ mod tests {
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let f = parser.parse(&pes);
|
||||
assert_eq!(f.len(), 1, "frame 1 emitted in parse");
|
||||
@@ -671,6 +681,7 @@ mod tests {
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let f = parser.parse(&pes);
|
||||
assert_eq!(f.len(), 2);
|
||||
@@ -714,6 +725,7 @@ mod tests {
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames = parser.parse(&pes);
|
||||
assert_eq!(frames.len(), 1, "only the real AC-3 frame is emitted");
|
||||
@@ -1179,6 +1191,7 @@ mod tests {
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,6 +482,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -233,6 +233,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -537,6 +537,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,6 +924,7 @@ mod tests {
|
||||
pts: Some(180000), // 2 seconds (presentation)
|
||||
dts: Some(90000), // 1 second (decode)
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames = parser.parse(&pes);
|
||||
assert_eq!(frames.len(), 1);
|
||||
@@ -1232,6 +1234,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: Some(90000),
|
||||
data: vec![0x00, 0x00, 0x01, 0x41, 0x10],
|
||||
discontinuity: false,
|
||||
};
|
||||
let f = parser.parse(&pes);
|
||||
assert_eq!(f.len(), 1);
|
||||
@@ -1247,6 +1250,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: None,
|
||||
data: vec![0x00, 0x00, 0x01, 0x41, 0x10],
|
||||
discontinuity: false,
|
||||
};
|
||||
let f = parser.parse(&pes);
|
||||
assert_eq!(f.len(), 1);
|
||||
|
||||
@@ -973,6 +973,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2243,6 +2244,7 @@ mod tests {
|
||||
pts: Some(180000), // 2 s (presentation)
|
||||
dts: Some(90000), // 1 s (decode)
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames = parser.parse(&pes);
|
||||
assert_eq!(frames.len(), 1);
|
||||
@@ -2850,6 +2852,7 @@ mod tests {
|
||||
d.extend_from_slice(&[0x10, 0x20]);
|
||||
d
|
||||
},
|
||||
discontinuity: false,
|
||||
};
|
||||
let f = parser.parse(&pes);
|
||||
assert_eq!(f.len(), 1);
|
||||
|
||||
@@ -98,6 +98,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -198,6 +198,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -707,6 +707,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let mut p = Mpeg2Parser::new();
|
||||
let mut frames = Vec::new();
|
||||
@@ -822,6 +823,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1415,6 +1417,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: Some(90000),
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let f = parse_then_flush(&mut parser, &pes);
|
||||
assert_eq!(f[0].pts_ns, 1_000_000_000, "DTS fallback");
|
||||
@@ -1428,6 +1431,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: None,
|
||||
data: data2,
|
||||
discontinuity: false,
|
||||
};
|
||||
let f2 = parse_then_flush(&mut parser2, &pes2);
|
||||
assert_eq!(f2[0].pts_ns, 0, "no PTS/DTS → 0");
|
||||
|
||||
@@ -223,6 +223,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -425,6 +425,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -451,6 +451,7 @@ mod tests {
|
||||
pts,
|
||||
dts: None,
|
||||
data,
|
||||
discontinuity: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -757,6 +758,7 @@ mod tests {
|
||||
pts: Some(180000), // presentation
|
||||
dts: Some(90000), // decode
|
||||
data,
|
||||
discontinuity: false,
|
||||
};
|
||||
let frames = parser.parse(&pes);
|
||||
assert_eq!(frames.len(), 1);
|
||||
@@ -1007,6 +1009,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: Some(90000),
|
||||
data: vec![0x00, 0x00, 0x01, SC_FRAME, 0x55],
|
||||
discontinuity: false,
|
||||
};
|
||||
let f = parser.parse(&pes);
|
||||
assert_eq!(f[0].pts_ns, 1_000_000_000, "DTS fallback");
|
||||
@@ -1018,6 +1021,7 @@ mod tests {
|
||||
pts: None,
|
||||
dts: None,
|
||||
data: vec![0x00, 0x00, 0x01, SC_FRAME, 0x55],
|
||||
discontinuity: false,
|
||||
};
|
||||
let f2 = parser2.parse(&pes2);
|
||||
assert_eq!(f2[0].pts_ns, 0, "no PTS/DTS → 0");
|
||||
|
||||
Reference in New Issue
Block a user