Fix ISO → MKV producing empty files (TsDemuxer remainder lost)
When the MKV muxer transitions from Scanning to Streaming phase, it creates a fresh TsDemuxer. The old demuxer's remainder bytes (partial 192-byte BD-TS packets) were lost, causing the new demuxer to lose sync. All subsequent feed() calls found 0 packets. Fix: transfer remainder via take_remainder/set_remainder so the new demuxer maintains packet alignment.
This commit is contained in:
+137
-33
@@ -38,6 +38,11 @@ struct ReadState {
|
|||||||
pos: usize,
|
pos: usize,
|
||||||
len: usize,
|
len: usize,
|
||||||
cluster_ts_ms: i64,
|
cluster_ts_ms: i64,
|
||||||
|
/// Codec private data per track (track_number, hvcC/avcC bytes).
|
||||||
|
/// Emitted as Annex B NALs before first frame of each video track.
|
||||||
|
codec_privates: Vec<(u16, Vec<u8>)>,
|
||||||
|
/// Tracks that have already had their codec_private emitted.
|
||||||
|
initialized_tracks: Vec<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Mode {
|
enum Mode {
|
||||||
@@ -125,7 +130,7 @@ impl MkvStream {
|
|||||||
pub fn open(mut reader: impl Read + Seek + 'static) -> io::Result<Self> {
|
pub fn open(mut reader: impl Read + Seek + 'static) -> io::Result<Self> {
|
||||||
let file_size = reader.seek(SeekFrom::End(0))?;
|
let file_size = reader.seek(SeekFrom::End(0))?;
|
||||||
reader.seek(SeekFrom::Start(0))?;
|
reader.seek(SeekFrom::Start(0))?;
|
||||||
let disc_title = parse_mkv_header(&mut reader)?;
|
let (disc_title, codec_privates) = parse_mkv_header(&mut reader)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
disc_title,
|
disc_title,
|
||||||
mode: Mode::Read(ReadState {
|
mode: Mode::Read(ReadState {
|
||||||
@@ -134,6 +139,8 @@ impl MkvStream {
|
|||||||
pos: 0,
|
pos: 0,
|
||||||
len: 0,
|
len: 0,
|
||||||
cluster_ts_ms: 0,
|
cluster_ts_ms: 0,
|
||||||
|
codec_privates,
|
||||||
|
initialized_tracks: Vec::new(),
|
||||||
}),
|
}),
|
||||||
max_buffer: 0,
|
max_buffer: 0,
|
||||||
finished: false,
|
finished: false,
|
||||||
@@ -280,9 +287,22 @@ impl Read for MkvStream {
|
|||||||
let rel_ts = i16::from_be_bytes([block[vl], block[vl + 1]]);
|
let rel_ts = i16::from_be_bytes([block[vl], block[vl + 1]]);
|
||||||
let frame = &block[vl + 3..];
|
let frame = &block[vl + 3..];
|
||||||
let pts_ms = rs.cluster_ts_ms + rel_ts as i64;
|
let pts_ms = rs.cluster_ts_ms + rel_ts as i64;
|
||||||
|
let tnum = track as u16;
|
||||||
|
|
||||||
rs.buf.clear();
|
rs.buf.clear();
|
||||||
frame_to_ts(&mut rs.buf, track as u16, pts_ms, frame);
|
|
||||||
|
// First frame of a track: emit codec_private as Annex B NALs
|
||||||
|
if !rs.initialized_tracks.contains(&tnum) {
|
||||||
|
rs.initialized_tracks.push(tnum);
|
||||||
|
if let Some((_, cp)) = rs.codec_privates.iter().find(|(t, _)| *t == tnum) {
|
||||||
|
let annex_b = hvcc_to_annex_b(cp);
|
||||||
|
if !annex_b.is_empty() {
|
||||||
|
frame_to_ts(&mut rs.buf, tnum, pts_ms, &annex_b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_to_ts(&mut rs.buf, tnum, pts_ms, frame);
|
||||||
rs.pos = 0;
|
rs.pos = 0;
|
||||||
rs.len = rs.buf.len();
|
rs.len = rs.buf.len();
|
||||||
|
|
||||||
@@ -351,7 +371,11 @@ fn begin_streaming(ws: &mut WriteState, dt: &DiscTitle) -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Transfer remainder bytes from old demuxer to new one.
|
||||||
|
// Preserves 192-byte packet alignment across the reset.
|
||||||
|
let remainder = ws.demuxer.take_remainder();
|
||||||
ws.demuxer = TsDemuxer::new(&pids);
|
ws.demuxer = TsDemuxer::new(&pids);
|
||||||
|
ws.demuxer.set_remainder(remainder);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,11 +401,15 @@ fn write_pes(
|
|||||||
|
|
||||||
// ── MKV header parsing (read side) ────────────────────────────
|
// ── MKV header parsing (read side) ────────────────────────────
|
||||||
|
|
||||||
fn parse_mkv_header(r: &mut (impl Read + Seek)) -> io::Result<DiscTitle> {
|
/// Returns (DiscTitle, codec_privates: Vec<(track_number, codec_private_bytes)>)
|
||||||
|
fn parse_mkv_header(
|
||||||
|
r: &mut (impl Read + Seek),
|
||||||
|
) -> io::Result<(DiscTitle, Vec<(u16, Vec<u8>)>)> {
|
||||||
let mut title = String::new();
|
let mut title = String::new();
|
||||||
let mut duration_ms = 0.0f64;
|
let mut duration_ms = 0.0f64;
|
||||||
let mut ts_scale: u64 = 1_000_000;
|
let mut ts_scale: u64 = 1_000_000;
|
||||||
let mut streams: Vec<crate::disc::Stream> = Vec::new();
|
let mut streams: Vec<crate::disc::Stream> = Vec::new();
|
||||||
|
let mut codec_privates: Vec<(u16, Vec<u8>)> = Vec::new();
|
||||||
|
|
||||||
let (id, size, _) = ebml::read_element_header(r)?;
|
let (id, size, _) = ebml::read_element_header(r)?;
|
||||||
if id != ebml::EBML {
|
if id != ebml::EBML {
|
||||||
@@ -432,9 +460,13 @@ fn parse_mkv_header(r: &mut (impl Read + Seek)) -> io::Result<DiscTitle> {
|
|||||||
while r.stream_position()? < end {
|
while r.stream_position()? < end {
|
||||||
let (cid, cs, _) = ebml::read_element_header(r)?;
|
let (cid, cs, _) = ebml::read_element_header(r)?;
|
||||||
if cid == ebml::TRACK_ENTRY {
|
if cid == ebml::TRACK_ENTRY {
|
||||||
if let Some(s) = parse_track(r, cs)? {
|
let (stream, tnum, cp) = parse_track(r, cs)?;
|
||||||
|
if let Some(s) = stream {
|
||||||
streams.push(s);
|
streams.push(s);
|
||||||
}
|
}
|
||||||
|
if let Some(cp) = cp {
|
||||||
|
codec_privates.push((tnum, cp));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
r.seek(SeekFrom::Current(cs as i64))?;
|
r.seek(SeekFrom::Current(cs as i64))?;
|
||||||
}
|
}
|
||||||
@@ -449,19 +481,25 @@ fn parse_mkv_header(r: &mut (impl Read + Seek)) -> io::Result<DiscTitle> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(DiscTitle {
|
let disc_title = DiscTitle {
|
||||||
playlist: title,
|
playlist: title,
|
||||||
duration_secs: duration_ms * (ts_scale as f64) / 1_000_000_000.0,
|
duration_secs: duration_ms * (ts_scale as f64) / 1_000_000_000.0,
|
||||||
streams,
|
streams,
|
||||||
..DiscTitle::empty()
|
..DiscTitle::empty()
|
||||||
})
|
};
|
||||||
|
Ok((disc_title, codec_privates))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_track(r: &mut (impl Read + Seek), size: u64) -> io::Result<Option<crate::disc::Stream>> {
|
/// Returns (stream, track_number, codec_private_bytes)
|
||||||
|
fn parse_track(
|
||||||
|
r: &mut (impl Read + Seek),
|
||||||
|
size: u64,
|
||||||
|
) -> io::Result<(Option<crate::disc::Stream>, u16, Option<Vec<u8>>)> {
|
||||||
let end = r.stream_position()? + size;
|
let end = r.stream_position()? + size;
|
||||||
let (mut ttype, mut tnum) = (0u64, 0u16);
|
let (mut ttype, mut tnum) = (0u64, 0u16);
|
||||||
let (mut codec_id, mut lang, mut name) = (String::new(), String::from("und"), String::new());
|
let (mut codec_id, mut lang, mut name) = (String::new(), String::from("und"), String::new());
|
||||||
let (mut ph, mut sr, mut ch, mut forced) = (0u32, 0.0f64, 0u8, false);
|
let (mut ph, mut sr, mut ch, mut forced) = (0u32, 0.0f64, 0u8, false);
|
||||||
|
let mut codec_priv: Option<Vec<u8>> = None;
|
||||||
|
|
||||||
while r.stream_position()? < end {
|
while r.stream_position()? < end {
|
||||||
let (cid, cs, _) = ebml::read_element_header(r)?;
|
let (cid, cs, _) = ebml::read_element_header(r)?;
|
||||||
@@ -469,6 +507,7 @@ fn parse_track(r: &mut (impl Read + Seek), size: u64) -> io::Result<Option<crate
|
|||||||
ebml::TRACK_NUMBER => tnum = ebml::read_uint_val(r, cs as usize)? as u16,
|
ebml::TRACK_NUMBER => tnum = ebml::read_uint_val(r, cs as usize)? as u16,
|
||||||
ebml::TRACK_TYPE => ttype = ebml::read_uint_val(r, cs as usize)?,
|
ebml::TRACK_TYPE => ttype = ebml::read_uint_val(r, cs as usize)?,
|
||||||
ebml::CODEC_ID => codec_id = ebml::read_string_val(r, cs as usize)?,
|
ebml::CODEC_ID => codec_id = ebml::read_string_val(r, cs as usize)?,
|
||||||
|
ebml::CODEC_PRIVATE => codec_priv = Some(ebml::read_binary_val(r, cs as usize)?),
|
||||||
ebml::LANGUAGE => lang = ebml::read_string_val(r, cs as usize)?,
|
ebml::LANGUAGE => lang = ebml::read_string_val(r, cs as usize)?,
|
||||||
ebml::TRACK_NAME => name = ebml::read_string_val(r, cs as usize)?,
|
ebml::TRACK_NAME => name = ebml::read_string_val(r, cs as usize)?,
|
||||||
ebml::FLAG_FORCED => forced = ebml::read_uint_val(r, cs as usize)? != 0,
|
ebml::FLAG_FORCED => forced = ebml::read_uint_val(r, cs as usize)? != 0,
|
||||||
@@ -516,30 +555,33 @@ fn parse_track(r: &mut (impl Read + Seek), size: u64) -> io::Result<Option<crate
|
|||||||
"S_VOBSUB" => Codec::DvdSub,
|
"S_VOBSUB" => Codec::DvdSub,
|
||||||
_ => Codec::Unknown(0),
|
_ => Codec::Unknown(0),
|
||||||
};
|
};
|
||||||
let res = format!("{ph}p");
|
let res = Resolution::from_height(ph);
|
||||||
let chs: String = match ch {
|
let chs = AudioChannels::from_count(ch);
|
||||||
8 => "7.1",
|
let srs = if sr >= 96000.0 {
|
||||||
6 => "5.1",
|
SampleRate::S96
|
||||||
2 => "stereo",
|
} else {
|
||||||
1 => "mono",
|
SampleRate::S48
|
||||||
_ => "5.1",
|
};
|
||||||
}
|
|
||||||
.into();
|
|
||||||
let srs: String = if sr >= 96000.0 { "96kHz" } else { "48kHz" }.into();
|
|
||||||
|
|
||||||
Ok(match ttype {
|
// Map MKV track numbers to BD-TS PIDs (same mapping as frame_to_ts)
|
||||||
1 => Some(crate::disc::Stream::Video(VideoStream {
|
let ts_pid = if tnum == 1 { 0x1011 } else { 0x1100 + (tnum - 2) };
|
||||||
pid: tnum,
|
|
||||||
codec,
|
let stream = match ttype {
|
||||||
resolution: res,
|
1 => {
|
||||||
frame_rate: String::new(),
|
let is_secondary = name.contains("Dolby Vision EL") || name.contains("DV EL");
|
||||||
hdr: HdrFormat::Sdr,
|
Some(crate::disc::Stream::Video(VideoStream {
|
||||||
color_space: ColorSpace::Bt709,
|
pid: ts_pid,
|
||||||
secondary: false,
|
codec,
|
||||||
label: name,
|
resolution: res,
|
||||||
})),
|
frame_rate: FrameRate::Unknown,
|
||||||
|
hdr: HdrFormat::Sdr,
|
||||||
|
color_space: ColorSpace::Bt709,
|
||||||
|
secondary: is_secondary,
|
||||||
|
label: name,
|
||||||
|
}))
|
||||||
|
}
|
||||||
2 => Some(crate::disc::Stream::Audio(AudioStream {
|
2 => Some(crate::disc::Stream::Audio(AudioStream {
|
||||||
pid: tnum,
|
pid: ts_pid,
|
||||||
codec,
|
codec,
|
||||||
channels: chs,
|
channels: chs,
|
||||||
language: lang,
|
language: lang,
|
||||||
@@ -548,14 +590,15 @@ fn parse_track(r: &mut (impl Read + Seek), size: u64) -> io::Result<Option<crate
|
|||||||
label: name,
|
label: name,
|
||||||
})),
|
})),
|
||||||
17 => Some(crate::disc::Stream::Subtitle(SubtitleStream {
|
17 => Some(crate::disc::Stream::Subtitle(SubtitleStream {
|
||||||
pid: tnum,
|
pid: ts_pid,
|
||||||
codec,
|
codec,
|
||||||
language: lang,
|
language: lang,
|
||||||
forced,
|
forced,
|
||||||
codec_data: None,
|
codec_data: None,
|
||||||
})),
|
})),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
};
|
||||||
|
Ok((stream, tnum, codec_priv))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── BD-TS frame wrapping (read side) ──────────────────────────
|
// ── BD-TS frame wrapping (read side) ──────────────────────────
|
||||||
@@ -573,20 +616,81 @@ fn block_vint(d: &[u8]) -> (u64, usize) {
|
|||||||
(0, 1)
|
(0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert HEVCDecoderConfigurationRecord (hvcC) to Annex B NAL units.
|
||||||
|
/// Extracts VPS, SPS, PPS arrays and prefixes each with 0x00000001.
|
||||||
|
fn hvcc_to_annex_b(hvcc: &[u8]) -> Vec<u8> {
|
||||||
|
// hvcC format (ISO 14496-15):
|
||||||
|
// byte 0: configurationVersion (1)
|
||||||
|
// bytes 1-21: profile/level info
|
||||||
|
// byte 22: numOfArrays
|
||||||
|
// For each array:
|
||||||
|
// byte 0: array_completeness(1) + reserved(1) + NAL_unit_type(6)
|
||||||
|
// bytes 1-2: numNalus (big-endian u16)
|
||||||
|
// For each NAL:
|
||||||
|
// bytes 0-1: nalUnitLength (big-endian u16)
|
||||||
|
// bytes 2..: NAL data
|
||||||
|
if hvcc.len() < 23 {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
let num_arrays = hvcc[22] as usize;
|
||||||
|
let mut pos = 23;
|
||||||
|
let mut out = Vec::new();
|
||||||
|
|
||||||
|
for _ in 0..num_arrays {
|
||||||
|
if pos + 3 > hvcc.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += 1; // skip array_completeness + NAL type byte
|
||||||
|
let num_nalus = u16::from_be_bytes([hvcc[pos], hvcc[pos + 1]]) as usize;
|
||||||
|
pos += 2;
|
||||||
|
for _ in 0..num_nalus {
|
||||||
|
if pos + 2 > hvcc.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let nal_len = u16::from_be_bytes([hvcc[pos], hvcc[pos + 1]]) as usize;
|
||||||
|
pos += 2;
|
||||||
|
if pos + nal_len > hvcc.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out.extend_from_slice(&[0x00, 0x00, 0x00, 0x01]);
|
||||||
|
out.extend_from_slice(&hvcc[pos..pos + nal_len]);
|
||||||
|
pos += nal_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
|
||||||
fn frame_to_ts(out: &mut Vec<u8>, track: u16, pts_ms: i64, data: &[u8]) {
|
fn frame_to_ts(out: &mut Vec<u8>, track: u16, pts_ms: i64, data: &[u8]) {
|
||||||
let pid = if track == 1 {
|
let pid = if track == 1 {
|
||||||
0x1011
|
0x1011
|
||||||
} else {
|
} else {
|
||||||
0x1100 + (track - 2)
|
0x1100 + (track - 2)
|
||||||
};
|
};
|
||||||
let stream_id: u8 = if track == 1 { 0xE0 } else { 0xBD };
|
let is_video = track <= 1 || pid == 0x1011;
|
||||||
|
let stream_id: u8 = if is_video { 0xE0 } else { 0xBD };
|
||||||
let pts = encode_pts(pts_ms * 90);
|
let pts = encode_pts(pts_ms * 90);
|
||||||
let hdr = [0x00, 0x00, 0x01, stream_id, 0x00, 0x00, 0x80, 0x80, 0x05];
|
let hdr = [0x00, 0x00, 0x01, stream_id, 0x00, 0x00, 0x80, 0x80, 0x05];
|
||||||
|
|
||||||
let mut pes = Vec::with_capacity(hdr.len() + pts.len() + data.len());
|
let mut pes = Vec::with_capacity(hdr.len() + pts.len() + data.len());
|
||||||
pes.extend_from_slice(&hdr);
|
pes.extend_from_slice(&hdr);
|
||||||
pes.extend_from_slice(&pts);
|
pes.extend_from_slice(&pts);
|
||||||
pes.extend_from_slice(data);
|
|
||||||
|
// Video: convert MKV length-prefixed NALs to Annex B start codes
|
||||||
|
if is_video && data.len() > 4 {
|
||||||
|
let mut pos = 0;
|
||||||
|
while pos + 4 <= data.len() {
|
||||||
|
let nal_len = u32::from_be_bytes([data[pos], data[pos + 1], data[pos + 2], data[pos + 3]]) as usize;
|
||||||
|
pos += 4;
|
||||||
|
if nal_len == 0 || pos + nal_len > data.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pes.extend_from_slice(&[0x00, 0x00, 0x00, 0x01]);
|
||||||
|
pes.extend_from_slice(&data[pos..pos + nal_len]);
|
||||||
|
pos += nal_len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pes.extend_from_slice(data);
|
||||||
|
}
|
||||||
|
|
||||||
let mut off = 0;
|
let mut off = 0;
|
||||||
let mut pusi = true;
|
let mut pusi = true;
|
||||||
|
|||||||
+30
-18
@@ -104,6 +104,18 @@ pub struct TsDemuxer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TsDemuxer {
|
impl TsDemuxer {
|
||||||
|
/// Take the remainder bytes (leftover from last feed() that didn't
|
||||||
|
/// align to a 192-byte packet boundary).
|
||||||
|
pub fn take_remainder(&mut self) -> Vec<u8> {
|
||||||
|
std::mem::take(&mut self.remainder)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the remainder bytes. Used to transfer alignment state from
|
||||||
|
/// one demuxer to another without losing sync.
|
||||||
|
pub fn set_remainder(&mut self, data: Vec<u8>) {
|
||||||
|
self.remainder = data;
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new demuxer tracking the given PIDs.
|
/// Create a new demuxer tracking the given PIDs.
|
||||||
pub fn new(pids: &[u16]) -> Self {
|
pub fn new(pids: &[u16]) -> Self {
|
||||||
let mut pid_index = [-1i16; 8192];
|
let mut pid_index = [-1i16; 8192];
|
||||||
@@ -363,8 +375,8 @@ pub fn scan_streams(data: &[u8]) -> Option<Vec<crate::disc::Stream>> {
|
|||||||
0x1B => Some(Stream::Video(VideoStream {
|
0x1B => Some(Stream::Video(VideoStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::H264,
|
codec: Codec::H264,
|
||||||
resolution: "1080p".into(),
|
resolution: Resolution::R1080p,
|
||||||
frame_rate: String::new(),
|
frame_rate: FrameRate::Unknown,
|
||||||
hdr: HdrFormat::Sdr,
|
hdr: HdrFormat::Sdr,
|
||||||
color_space: ColorSpace::Bt709,
|
color_space: ColorSpace::Bt709,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
@@ -373,8 +385,8 @@ pub fn scan_streams(data: &[u8]) -> Option<Vec<crate::disc::Stream>> {
|
|||||||
0x24 => Some(Stream::Video(VideoStream {
|
0x24 => Some(Stream::Video(VideoStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::Hevc,
|
codec: Codec::Hevc,
|
||||||
resolution: "2160p".into(),
|
resolution: Resolution::R2160p,
|
||||||
frame_rate: String::new(),
|
frame_rate: FrameRate::Unknown,
|
||||||
hdr: HdrFormat::Sdr,
|
hdr: HdrFormat::Sdr,
|
||||||
color_space: ColorSpace::Bt709,
|
color_space: ColorSpace::Bt709,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
@@ -383,8 +395,8 @@ pub fn scan_streams(data: &[u8]) -> Option<Vec<crate::disc::Stream>> {
|
|||||||
0xEA => Some(Stream::Video(VideoStream {
|
0xEA => Some(Stream::Video(VideoStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::Vc1,
|
codec: Codec::Vc1,
|
||||||
resolution: "1080p".into(),
|
resolution: Resolution::R1080p,
|
||||||
frame_rate: String::new(),
|
frame_rate: FrameRate::Unknown,
|
||||||
hdr: HdrFormat::Sdr,
|
hdr: HdrFormat::Sdr,
|
||||||
color_space: ColorSpace::Bt709,
|
color_space: ColorSpace::Bt709,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
@@ -393,8 +405,8 @@ pub fn scan_streams(data: &[u8]) -> Option<Vec<crate::disc::Stream>> {
|
|||||||
0x02 => Some(Stream::Video(VideoStream {
|
0x02 => Some(Stream::Video(VideoStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::Mpeg2,
|
codec: Codec::Mpeg2,
|
||||||
resolution: "1080i".into(),
|
resolution: Resolution::R1080i,
|
||||||
frame_rate: String::new(),
|
frame_rate: FrameRate::Unknown,
|
||||||
hdr: HdrFormat::Sdr,
|
hdr: HdrFormat::Sdr,
|
||||||
color_space: ColorSpace::Bt709,
|
color_space: ColorSpace::Bt709,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
@@ -403,45 +415,45 @@ pub fn scan_streams(data: &[u8]) -> Option<Vec<crate::disc::Stream>> {
|
|||||||
0x81 => Some(Stream::Audio(AudioStream {
|
0x81 => Some(Stream::Audio(AudioStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::Ac3,
|
codec: Codec::Ac3,
|
||||||
channels: "5.1".into(),
|
channels: AudioChannels::Surround51,
|
||||||
language: "und".into(),
|
language: "und".into(),
|
||||||
sample_rate: "48kHz".into(),
|
sample_rate: SampleRate::S48,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
label: String::new(),
|
label: String::new(),
|
||||||
})),
|
})),
|
||||||
0x83 => Some(Stream::Audio(AudioStream {
|
0x83 => Some(Stream::Audio(AudioStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::TrueHd,
|
codec: Codec::TrueHd,
|
||||||
channels: "5.1".into(),
|
channels: AudioChannels::Surround51,
|
||||||
language: "und".into(),
|
language: "und".into(),
|
||||||
sample_rate: "48kHz".into(),
|
sample_rate: SampleRate::S48,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
label: String::new(),
|
label: String::new(),
|
||||||
})),
|
})),
|
||||||
0x84 | 0xA1 => Some(Stream::Audio(AudioStream {
|
0x84 | 0xA1 => Some(Stream::Audio(AudioStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::Ac3Plus,
|
codec: Codec::Ac3Plus,
|
||||||
channels: "5.1".into(),
|
channels: AudioChannels::Surround51,
|
||||||
language: "und".into(),
|
language: "und".into(),
|
||||||
sample_rate: "48kHz".into(),
|
sample_rate: SampleRate::S48,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
label: String::new(),
|
label: String::new(),
|
||||||
})),
|
})),
|
||||||
0x85 | 0x86 => Some(Stream::Audio(AudioStream {
|
0x85 | 0x86 => Some(Stream::Audio(AudioStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::DtsHdMa,
|
codec: Codec::DtsHdMa,
|
||||||
channels: "5.1".into(),
|
channels: AudioChannels::Surround51,
|
||||||
language: "und".into(),
|
language: "und".into(),
|
||||||
sample_rate: "48kHz".into(),
|
sample_rate: SampleRate::S48,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
label: String::new(),
|
label: String::new(),
|
||||||
})),
|
})),
|
||||||
0x82 => Some(Stream::Audio(AudioStream {
|
0x82 => Some(Stream::Audio(AudioStream {
|
||||||
pid: es_pid,
|
pid: es_pid,
|
||||||
codec: Codec::Dts,
|
codec: Codec::Dts,
|
||||||
channels: "5.1".into(),
|
channels: AudioChannels::Surround51,
|
||||||
language: "und".into(),
|
language: "und".into(),
|
||||||
sample_rate: "48kHz".into(),
|
sample_rate: SampleRate::S48,
|
||||||
secondary: false,
|
secondary: false,
|
||||||
label: String::new(),
|
label: String::new(),
|
||||||
})),
|
})),
|
||||||
|
|||||||
Reference in New Issue
Block a user