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:
@@ -9,6 +9,8 @@
|
||||
|
||||
/// AC-3 / E-AC-3 (Dolby Digital / Digital Plus) elementary-stream parser.
|
||||
pub mod ac3;
|
||||
/// Codec-agnostic per-picture coding carrier (`PictureInfo` + accessors).
|
||||
pub mod coding;
|
||||
/// DTS / DTS-HD elementary-stream parser.
|
||||
pub mod dts;
|
||||
/// DVD bitmap subtitle (VobSub) parser.
|
||||
@@ -30,10 +32,13 @@ pub mod truehd;
|
||||
/// VC-1 (SMPTE 421M) elementary-stream parser.
|
||||
pub mod vc1;
|
||||
|
||||
pub use coding::{FieldOrder, PictureInfo};
|
||||
|
||||
use super::ts::PesPacket;
|
||||
use crate::disc::Codec;
|
||||
|
||||
/// A single frame ready for MKV muxing.
|
||||
#[derive(Default)]
|
||||
pub struct Frame {
|
||||
/// Presentation timestamp in nanoseconds.
|
||||
pub pts_ns: i64,
|
||||
@@ -48,6 +53,18 @@ pub struct Frame {
|
||||
/// `SimpleBlock`; without it players guess the display interval
|
||||
/// (subtitles linger past their end-time).
|
||||
pub duration_ns: Option<u64>,
|
||||
/// Codec-agnostic per-picture coding info, set by the video parsers that
|
||||
/// decode it (MPEG-2 fully; H.264/HEVC/VC-1 coding-type only); `None` for
|
||||
/// audio/subtitle frames. Carried additively through the highway and
|
||||
/// forwarded onto [`crate::pes::PesFrame::coding`] so the muxer can read
|
||||
/// field order / pulldown off the frame instead of assuming it. Default
|
||||
/// `None` keeps non-video frames paying nothing.
|
||||
pub coding: Option<PictureInfo>,
|
||||
/// Source position of this frame's first byte, carried from the demux seam
|
||||
/// (where each PES is stamped) through the parser. `None` for synthetic
|
||||
/// sources / parsers that don't track it. Forwarded onto
|
||||
/// [`crate::pes::PesFrame::source`].
|
||||
pub source: Option<crate::pes::SourcePos>,
|
||||
}
|
||||
|
||||
/// Convert 90kHz PTS to nanoseconds (round to nearest).
|
||||
@@ -107,6 +124,8 @@ impl CodecParser for PassthroughParser {
|
||||
fn parse(&mut self, pes: &PesPacket) -> Vec<Frame> {
|
||||
let pts_ns = pes.pts.or(pes.dts).map(pts_to_ns).unwrap_or(0);
|
||||
vec![Frame {
|
||||
coding: None,
|
||||
source: None,
|
||||
pts_ns,
|
||||
keyframe: self.keyframe,
|
||||
data: pes.data.clone(),
|
||||
@@ -174,6 +193,7 @@ mod tests {
|
||||
|
||||
fn pes(pts: Option<i64>, data: Vec<u8>) -> PesPacket {
|
||||
PesPacket {
|
||||
source: None,
|
||||
pid: 0x1011,
|
||||
pts,
|
||||
dts: None,
|
||||
|
||||
Reference in New Issue
Block a user