Stamp the last frames that were still leaving without provenance
A real rip caught these. The warning added for a track placed from timestamps under a seam plan fired once, on one subtitle track of a 23-clip title, eighteen minutes in — a display set that arrives as a lone non-PCS segment is emitted straight through rather than accumulated, and that path still built its frame with source: None. Auditing the rest the same way found four more: flac, lpcm, mpegaudio and the passthrough parser. All are one-PES-one-frame, so the packet's own facts are the unit's facts. Every Frame construction in every codec parser now carries a source, checked by walking balanced braces rather than by eye — the earlier count was taken with a regex that cannot see a block containing nested braces, which is how these survived the first pass.
This commit is contained in:
@@ -118,7 +118,7 @@ impl CodecParser for FlacParser {
|
|||||||
vec![Frame {
|
vec![Frame {
|
||||||
discontinuity: pes.discontinuity,
|
discontinuity: pes.discontinuity,
|
||||||
coding: None,
|
coding: None,
|
||||||
source: None,
|
source: super::pesbuf::PesFacts::of(pes).source,
|
||||||
pts_ns,
|
pts_ns,
|
||||||
keyframe: true,
|
keyframe: true,
|
||||||
data: pes.data.clone(),
|
data: pes.data.clone(),
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ impl CodecParser for LpcmParser {
|
|||||||
vec![Frame {
|
vec![Frame {
|
||||||
discontinuity: false,
|
discontinuity: false,
|
||||||
coding: None,
|
coding: None,
|
||||||
source: None,
|
source: super::pesbuf::PesFacts::of(pes).source,
|
||||||
pts_ns,
|
pts_ns,
|
||||||
keyframe: true,
|
keyframe: true,
|
||||||
data: pes.data[offset..].to_vec(),
|
data: pes.data[offset..].to_vec(),
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ impl CodecParser for PassthroughParser {
|
|||||||
// parsers must instead defer the flag to the next emitted frame.)
|
// parsers must instead defer the flag to the next emitted frame.)
|
||||||
vec![Frame {
|
vec![Frame {
|
||||||
coding: None,
|
coding: None,
|
||||||
source: None,
|
source: pesbuf::PesFacts::of(pes).source,
|
||||||
pts_ns,
|
pts_ns,
|
||||||
keyframe: self.keyframe,
|
keyframe: self.keyframe,
|
||||||
discontinuity: pes.discontinuity,
|
discontinuity: pes.discontinuity,
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ impl CodecParser for MpegAudioParser {
|
|||||||
vec![Frame {
|
vec![Frame {
|
||||||
discontinuity: pes.discontinuity,
|
discontinuity: pes.discontinuity,
|
||||||
coding: None,
|
coding: None,
|
||||||
source: None,
|
source: super::pesbuf::PesFacts::of(pes).source,
|
||||||
pts_ns,
|
pts_ns,
|
||||||
keyframe: true,
|
keyframe: true,
|
||||||
data: pes.data.clone(),
|
data: pes.data.clone(),
|
||||||
|
|||||||
+27
-1
@@ -366,7 +366,10 @@ impl CodecParser for PgsParser {
|
|||||||
out.push(Frame {
|
out.push(Frame {
|
||||||
discontinuity: false,
|
discontinuity: false,
|
||||||
coding: None,
|
coding: None,
|
||||||
source: None,
|
// Emitted straight from THIS packet, so its facts are
|
||||||
|
// this packet's -- the same rule as a pending set,
|
||||||
|
// which takes the facts of the packet that opened it.
|
||||||
|
source: super::pesbuf::PesFacts::of(pes).source,
|
||||||
pts_ns: pts.unwrap_or(0),
|
pts_ns: pts.unwrap_or(0),
|
||||||
keyframe: true,
|
keyframe: true,
|
||||||
data: pes.data.clone(),
|
data: pes.data.clone(),
|
||||||
@@ -914,4 +917,27 @@ mod tests {
|
|||||||
assert_eq!(t.facts().displays, u32::MAX);
|
assert_eq!(t.facts().displays, u32::MAX);
|
||||||
assert_eq!(t.facts().forced_displays, u32::MAX);
|
assert_eq!(t.facts().forced_displays, u32::MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A lone non-PCS segment with a PTS is emitted straight through rather
|
||||||
|
/// than accumulated, and it must still carry provenance. This path was
|
||||||
|
/// missed on the first pass and showed up on a real disc as a subtitle
|
||||||
|
/// track with no source offset -- the one track out of forty that could
|
||||||
|
/// not be placed by byte.
|
||||||
|
#[test]
|
||||||
|
fn a_lone_segment_emitted_directly_still_carries_provenance() {
|
||||||
|
let mut parser = PgsParser::new();
|
||||||
|
// A non-PCS segment (type 0x15 = ODS) with a PTS and no pending set.
|
||||||
|
let mut p = make_pes(vec![0x15, 0x00, 0x00, 0x00, 0x04, 1, 2, 3, 4], Some(90_000));
|
||||||
|
p.source = Some(crate::pes::SourcePos::at_byte(7_777));
|
||||||
|
let frames = parser.parse(&p);
|
||||||
|
assert!(
|
||||||
|
!frames.is_empty(),
|
||||||
|
"a lone segment with a PTS is passed through"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
frames[0].source.map(|s| s.byte),
|
||||||
|
Some(7_777),
|
||||||
|
"emitted straight from this packet, so it carries this packet's offset"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user