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:
@@ -57,6 +57,8 @@ impl PgsParser {
|
||||
let (start_pts, data) = self.pending.take()?;
|
||||
let duration = end_pts_ns.saturating_sub(start_pts).max(0) as u64;
|
||||
Some(Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns: start_pts,
|
||||
keyframe: true,
|
||||
data,
|
||||
@@ -90,6 +92,8 @@ impl CodecParser for PgsParser {
|
||||
.take()
|
||||
.map(|(start_pts, data)| {
|
||||
vec![Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns: start_pts,
|
||||
keyframe: true,
|
||||
data,
|
||||
@@ -115,6 +119,8 @@ impl CodecParser for PgsParser {
|
||||
let frame = match pts {
|
||||
Some(end) => self.emit_pending(end),
|
||||
None => self.pending.take().map(|(start_pts, data)| Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns: start_pts,
|
||||
keyframe: true,
|
||||
data,
|
||||
@@ -136,6 +142,8 @@ impl CodecParser for PgsParser {
|
||||
// Flush any prior pending undurated and skip storing this one.
|
||||
None => {
|
||||
out.extend(self.pending.take().map(|(start_pts, data)| Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns: start_pts,
|
||||
keyframe: true,
|
||||
data,
|
||||
@@ -159,6 +167,8 @@ impl CodecParser for PgsParser {
|
||||
// (A missing PTS falls through to the drop path below: a
|
||||
// bitmap with no timing reference would land at 00:00:00.)
|
||||
out.push(Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns: pts.unwrap_or(0),
|
||||
keyframe: true,
|
||||
data: pes.data.clone(),
|
||||
@@ -185,6 +195,8 @@ impl CodecParser for PgsParser {
|
||||
// the final on-screen subtitle (see the module doc).
|
||||
match self.pending.take() {
|
||||
Some((start_pts, data)) => vec![Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns: start_pts,
|
||||
keyframe: true,
|
||||
data,
|
||||
@@ -206,6 +218,7 @@ mod tests {
|
||||
|
||||
fn make_pes(data: Vec<u8>, pts: Option<i64>) -> PesPacket {
|
||||
PesPacket {
|
||||
source: None,
|
||||
pid: 0x1200,
|
||||
pts,
|
||||
dts: None,
|
||||
|
||||
Reference in New Issue
Block a user