Fix DTS-HD MA muxing as lossy core only (#10)
DTS-HD MA/HRA access units on Blu-ray are a DTS core frame (sync 0x7FFE8001) followed by one or more DTS extension substreams (sync 0x64582025) carrying the lossless audio. Ground-truthing the Dunkirk ISO showed the m2ts demuxer hands these out as SEPARATE PES packets on the same PID: one core PES (exactly core-sized, nothing trailing), then the extension substreams in following PES packets with their own later PTS. The old DtsParser emitted one frame per PES the moment a core frame was complete, and dropped any PES with no core sync. So every core became a core-only (lossy) frame and the extension PES packets were discarded as junk -- silently downgrading the track to lossy DTS core (1557 kb/s CBR, 16-bit) instead of DTS-HD MA (VBR, 24-bit lossless). Rewrite the parser to assemble across PES boundaries: an access unit runs from its core sync up to (but not including) the NEXT core sync, so the core plus every following extension substream stays together. Add a CodecParser::flush() (default empty) called at end-of-stream by both the pipelined and inline DiscStream mux paths to drain the final buffered unit. A 64 KiB cap guarantees forward progress and never stalls if a boundary can't be found. Validated on the rip1 testbed: Dunkirk eng+ger and Fight Club eng main audio now ffprobe as profile=DTS-HD MA (Fight Club eng at 24-bit), with VBR packet sizes (~2716-2788 B) well above the old fixed 2012 B lossy core. Genuinely-lossy DTS dub tracks are left untouched.
This commit is contained in:
@@ -52,6 +52,18 @@ pub trait CodecParser: Send {
|
||||
/// Some (TrueHD): multiple access units per PES.
|
||||
fn parse(&mut self, pes: &PesPacket) -> Vec<Frame>;
|
||||
|
||||
/// Drain any access unit still buffered after the last PES.
|
||||
///
|
||||
/// Parsers that buffer across PES boundaries to assemble a complete
|
||||
/// access unit (e.g. DTS-HD, whose extension substreams arrive in
|
||||
/// separate PES packets) hold the final unit until they can prove it's
|
||||
/// complete. At end-of-stream there is no following packet to prove it,
|
||||
/// so the demuxer calls `flush()` once after the last PES to emit it.
|
||||
/// Default: nothing buffered, no tail.
|
||||
fn flush(&mut self) -> Vec<Frame> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Get codec initialization data (e.g., SPS+PPS for H.264).
|
||||
/// Returns None until enough data has been seen.
|
||||
fn codec_private(&self) -> Option<Vec<u8>>;
|
||||
|
||||
Reference in New Issue
Block a user