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:
@@ -169,7 +169,6 @@ fn title_with_video(
|
||||
display_aspect: None,
|
||||
secondary: false,
|
||||
label: String::new(),
|
||||
top_field_first: None,
|
||||
measured_cicp: None,
|
||||
})],
|
||||
chapters: Vec::new(),
|
||||
|
||||
+12
-5
@@ -23,7 +23,6 @@ fn sample_disc_title() -> DiscTitle {
|
||||
display_aspect: None,
|
||||
secondary: false,
|
||||
label: "Main".into(),
|
||||
top_field_first: None,
|
||||
measured_cicp: None,
|
||||
}),
|
||||
Stream::Audio(AudioStream {
|
||||
@@ -300,6 +299,8 @@ fn m2ts_stream_write_read() {
|
||||
// Write some PES frames
|
||||
for i in 0..5u8 {
|
||||
let frame = libfreemkv::pes::PesFrame {
|
||||
coding: None,
|
||||
source: None,
|
||||
track: 0,
|
||||
pts: i as i64 * 1_000_000,
|
||||
keyframe: i == 0,
|
||||
@@ -322,6 +323,8 @@ fn m2ts_stream_write_read() {
|
||||
fn m2ts_pes_frame_roundtrip() {
|
||||
// PesFrame serialize/deserialize roundtrip
|
||||
let frame = libfreemkv::pes::PesFrame {
|
||||
coding: None,
|
||||
source: None,
|
||||
track: 2,
|
||||
pts: 1_234_567_890,
|
||||
keyframe: true,
|
||||
@@ -403,7 +406,6 @@ fn meta_codec_roundtrip() {
|
||||
display_aspect: None,
|
||||
secondary: false,
|
||||
label: String::new(),
|
||||
top_field_first: None,
|
||||
measured_cicp: None,
|
||||
}));
|
||||
}
|
||||
@@ -507,7 +509,6 @@ fn meta_all_stream_types() {
|
||||
display_aspect: None,
|
||||
secondary: false,
|
||||
label: "Primary".into(),
|
||||
top_field_first: None,
|
||||
measured_cicp: None,
|
||||
}),
|
||||
Stream::Audio(AudioStream {
|
||||
@@ -596,6 +597,8 @@ fn mkvstream_write_finish() {
|
||||
// since there is no real codec data, but it should not panic)
|
||||
for i in 0..20u8 {
|
||||
let frame = libfreemkv::pes::PesFrame {
|
||||
coding: None,
|
||||
source: None,
|
||||
track: 0,
|
||||
pts: i as i64 * 1_000_000,
|
||||
keyframe: i == 0,
|
||||
@@ -658,6 +661,8 @@ fn mkvstream_roundtrip_bdts() {
|
||||
// Write PES frames targeting the audio track
|
||||
for i in 0..10u8 {
|
||||
let frame = libfreemkv::pes::PesFrame {
|
||||
coding: None,
|
||||
source: None,
|
||||
track: 0,
|
||||
pts: i as i64 * 1_000_000,
|
||||
keyframe: true,
|
||||
@@ -694,7 +699,6 @@ fn mkvstream_meta_preserves_all_streams() {
|
||||
display_aspect: None,
|
||||
secondary: false,
|
||||
label: "Main Video".into(),
|
||||
top_field_first: None,
|
||||
measured_cicp: None,
|
||||
}),
|
||||
Stream::Audio(AudioStream {
|
||||
@@ -795,7 +799,6 @@ fn mkvstream_e2e_h264_produces_valid_mkv() {
|
||||
display_aspect: None,
|
||||
secondary: false,
|
||||
label: "Main".into(),
|
||||
top_field_first: None,
|
||||
measured_cicp: None,
|
||||
})],
|
||||
chapters: Vec::new(),
|
||||
@@ -857,6 +860,8 @@ fn mkvstream_e2e_h264_produces_valid_mkv() {
|
||||
|
||||
// Write the ES data (SPS+PPS+IDR) as a keyframe PES frame.
|
||||
let frame1 = libfreemkv::pes::PesFrame {
|
||||
coding: None,
|
||||
source: None,
|
||||
track: 0,
|
||||
pts: 1_000_000_000, // 1 second in ns
|
||||
keyframe: true,
|
||||
@@ -867,6 +872,8 @@ fn mkvstream_e2e_h264_produces_valid_mkv() {
|
||||
|
||||
// Write a second non-IDR frame
|
||||
let frame2 = libfreemkv::pes::PesFrame {
|
||||
coding: None,
|
||||
source: None,
|
||||
track: 0,
|
||||
pts: 1_041_700_000, // ~1 frame later in ns
|
||||
keyframe: false,
|
||||
|
||||
Reference in New Issue
Block a user