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:
@@ -176,6 +176,18 @@ impl Stream for PipelinedPesStream {
|
||||
}
|
||||
false => {
|
||||
self.eof = true;
|
||||
// Drain any access unit a parser buffered past the last
|
||||
// PES (e.g. DTS-HD's final core+extension unit).
|
||||
let pid_to_track = &self.pid_to_track;
|
||||
let pending = &mut self.pending_frames;
|
||||
for (pid, parser) in self.parsers.iter_mut() {
|
||||
let Some(&(_, track)) = pid_to_track.iter().find(|(p, _)| p == pid) else {
|
||||
continue;
|
||||
};
|
||||
for frame in parser.flush() {
|
||||
pending.push_back(PesFrame::from_codec_frame(track, frame));
|
||||
}
|
||||
}
|
||||
return Ok(self.pending_frames.pop_front());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user