mux: codec-agnostic PictureInfo + provenance; measure field order, never guess
Carry per-picture truth and byte-exact source provenance THROUGH the stream so the muxer (and the upcoming video index) read MEASURED facts instead of assuming them. Honest data in, honest data out. - codec/coding.rs: codec-agnostic PictureInfo (CodingType / FieldOrder + the accessors field_order/coding_type/nb_fields/progressive/keyframe). Each codec folds its raw signals in; consumers use only accessors, never branch on codec. - mpeg2: builds PictureInfo from the picture coding extension and carries it + SourcePos (source_marks, parallel to pts_marks) on every emitted frame. - pes / codec::Frame: additive `coding` + `source`, forwarded through the highway; None for audio/subtitle and the network/stdio deserialize hop. - mkvstream: DEFER muxer construction until the first coded picture, set the video track's FieldOrder from the MEASURED value, THEN write the header — right the first time, no guess, no seek-back. An interlaced track that arrives with no measured order is LOGGED loudly and left UNDETERMINED, never faked. - mkv: MkvTrack::video no longer guesses TFF (a bitstream property the scan cannot know is UNDETERMINED at build). Removed VideoStream::top_field_first (the dead scan-time guess) crate-wide. - Tests: parser population (every PictureInfo facet + per-PES source carry) and mux-stream consumption (measured -> correct; missing -> UNDETERMINED, not faked). Two obsolete tests updated only after confirming (their own comments) they existed to enforce the deleted hardcoded-TFF.
This commit is contained in:
@@ -115,6 +115,8 @@ impl CodecParser for Ac3Parser {
|
||||
|
||||
let duration_ns = frame_duration_ns(remaining, bsid);
|
||||
frames.push(Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns: frame_pts_ns,
|
||||
keyframe: true,
|
||||
data: data[start..start + frame_size].to_vec(),
|
||||
@@ -199,6 +201,8 @@ impl CodecParser for Ac3Parser {
|
||||
}
|
||||
let duration_ns = frame_duration_ns(frame, bsid);
|
||||
vec![Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns: self.flush_pts_ns,
|
||||
keyframe: true,
|
||||
data: buf[off..off + frame_size].to_vec(),
|
||||
@@ -441,6 +445,7 @@ mod tests {
|
||||
fn parse_empty_pes() {
|
||||
let mut parser = Ac3Parser::new();
|
||||
let pes = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: None,
|
||||
dts: None,
|
||||
@@ -454,6 +459,7 @@ mod tests {
|
||||
let mut parser = Ac3Parser::new();
|
||||
let frame_data = make_ac3_frame(0, 2); // 48kHz, 80 words = 160 bytes
|
||||
let pes = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
@@ -472,6 +478,7 @@ mod tests {
|
||||
|
||||
// First PES: first half of frame
|
||||
let pes1 = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
@@ -482,6 +489,7 @@ mod tests {
|
||||
|
||||
// Second PES: second half
|
||||
let pes2 = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(93000),
|
||||
dts: None,
|
||||
@@ -499,6 +507,7 @@ mod tests {
|
||||
let mut data = vec![0xDE, 0xAD, 0xBE, 0xEF]; // garbage
|
||||
data.extend_from_slice(&frame_data);
|
||||
let pes = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: None,
|
||||
dts: None,
|
||||
@@ -521,6 +530,7 @@ mod tests {
|
||||
let mut pes1_data = frame_data.clone();
|
||||
pes1_data.push(0x0B);
|
||||
let pes1 = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
@@ -533,6 +543,7 @@ mod tests {
|
||||
let mut pes2_data = vec![0x77];
|
||||
pes2_data.extend_from_slice(&frame_data[2..]);
|
||||
let pes2 = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(93000),
|
||||
dts: None,
|
||||
@@ -558,6 +569,7 @@ mod tests {
|
||||
*data.last_mut().unwrap() = 0x0B;
|
||||
}
|
||||
let pes = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: None,
|
||||
dts: None,
|
||||
@@ -585,6 +597,7 @@ mod tests {
|
||||
let mut parser = Ac3Parser::new();
|
||||
let data = vec![0x00, 0x00, 0x0B];
|
||||
let pes = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: None,
|
||||
dts: None,
|
||||
@@ -621,6 +634,7 @@ mod tests {
|
||||
let mut data = frame_data.clone();
|
||||
data.extend_from_slice(&frame_data[..40]); // partial frame 2 held
|
||||
let pes = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
@@ -652,6 +666,7 @@ mod tests {
|
||||
let mut data = frame_data.clone();
|
||||
data.extend_from_slice(&frame_data);
|
||||
let pes = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
@@ -694,6 +709,7 @@ mod tests {
|
||||
let good = make_ac3_frame(0, 2);
|
||||
data.extend_from_slice(&good);
|
||||
let pes = PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
@@ -1152,6 +1168,7 @@ mod tests {
|
||||
// helper: PES with a generic pts for E-AC-3 tests
|
||||
fn make_eac3_pes(data: Vec<u8>) -> PesPacket {
|
||||
PesPacket {
|
||||
source: None,
|
||||
pid: 0,
|
||||
pts: Some(90000),
|
||||
dts: None,
|
||||
|
||||
Reference in New Issue
Block a user