mux: fix keyframe signalling for BlockGroup frames
Inside a Matroska BlockGroup the SimpleBlock 0x80 keyframe bit is
reserved and is always written as 0; keyframe-ness is carried only by
the presence or absence of a ReferenceBlock child. Both halves of the
round-trip got this wrong:
- the reader skipped past ReferenceBlock and read the reserved bit,
so every BlockGroup frame came back as a non-keyframe;
- write_block_group discarded its `keyframe` argument and never
emitted a ReferenceBlock, on the assumption that only intra frames
(PGS subtitles) reached that path.
The MPEG-2 parser stamps a per-frame duration on I, P and B pictures
alike, so all MPEG-2 video is written as a BlockGroup. That makes the
assumption false and left no video frame looking like a keyframe on
read-back. Downstream, mkv:// -> m2ts:// dropped every video frame (the
TS muxer discards non-key video until the first keyframe) while still
reporting success, and mkv:// -> mkv:// and the stdio round-trip failed
E6008, because the MKV muxer opens a cluster only on a track-0 video
keyframe and so wrote nothing at all. HEVC was unaffected: it carries no
per-frame duration, so it takes the SimpleBlock path where the flag bit
is authoritative.
Verified on a real CSS DVD: 841 keyframes out of 11440 video packets
survive a re-mux, matching the I-picture count in the source bitstream.
Also stop running non-NAL video through the Annex-B converter. MPEG-2
and VC-1 elementary streams are already start-code framed, so
length-prefix conversion corrupts them. TsMuxer takes a per-track
nal_video flag, defaulting to the previous behaviour, which M2tsStream
sets from each video stream's codec.
This commit is contained in:
+11
-1
@@ -8,7 +8,7 @@
|
||||
//! write-only.
|
||||
|
||||
use super::meta;
|
||||
use crate::disc::{DiscTitle, Stream as DiscStream};
|
||||
use crate::disc::{Codec, DiscTitle, Stream as DiscStream};
|
||||
use std::io::{self, Write};
|
||||
|
||||
/// BD transport stream write sink with embedded FMKV metadata
|
||||
@@ -40,6 +40,16 @@ impl M2tsStream {
|
||||
.collect();
|
||||
let boxed: Box<dyn Write + Send> = Box::new(writer);
|
||||
let mut muxer = super::tsmux::TsMuxer::new(boxed, &pids);
|
||||
// Only HEVC/H.264 arrive length-prefixed (MKV/PES NALU convention);
|
||||
// MPEG-2 and VC-1 are already start-code ES and must NOT go through
|
||||
// Annex-B conversion (see `TsMuxer::set_nal_video`) or the frame is
|
||||
// silently mangled while the mux still reports success.
|
||||
for (i, s) in title.streams.iter().enumerate() {
|
||||
if let DiscStream::Video(v) = s {
|
||||
let is_nal = matches!(v.codec, Codec::Hevc | Codec::H264);
|
||||
muxer.set_nal_video(i, is_nal)?;
|
||||
}
|
||||
}
|
||||
for (i, cp) in title.codec_privates.iter().enumerate() {
|
||||
// codec_privates is parallel to streams/pids; ignore any
|
||||
// trailing entries that exceed the track count rather than
|
||||
|
||||
Reference in New Issue
Block a user