From da74e59f43fa47a59c5f0bd0b610b8f0eaa9298e Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Mon, 4 May 2026 20:07:35 +0200 Subject: [PATCH] mov: support several descriptors per track --- nihav-commonfmt/src/demuxers/mov/mod.rs | 10 +- nihav-commonfmt/src/demuxers/mov/pktread.rs | 1 + nihav-commonfmt/src/demuxers/mov/track.rs | 534 +++++++++++--------- 3 files changed, 288 insertions(+), 257 deletions(-) diff --git a/nihav-commonfmt/src/demuxers/mov/mod.rs b/nihav-commonfmt/src/demuxers/mov/mod.rs index 77802d7..e76a7ce 100644 --- a/nihav-commonfmt/src/demuxers/mov/mod.rs +++ b/nihav-commonfmt/src/demuxers/mov/mod.rs @@ -310,12 +310,12 @@ fn read_trak(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> Dem track.call_read_trak(dmx.src, size)?; validate!(track.tkhd_found); if !track.stsd_found { - track.stream = Some(NAStream::new(StreamType::Data, track.track_no, DUMMY_CODEC_INFO, track.tb_num, track.tb_den, 0)); + track.streams.push(NAStream::new(StreamType::Data, track.track_no, DUMMY_CODEC_INFO, track.tb_num, track.tb_den, 0)); } // invent keyframes for video stream if none were reported if !track.stss_found && track.stream_type == StreamType::Video { let mut intraonly = false; - if let Some(ref stream) = track.stream { + if let Some(stream) = track.streams.first() { if let Some(desc) = get_codec_description(stream.get_info().get_name()) { intraonly = (desc.caps & CODEC_CAP_INTRAONLY) != 0; } @@ -503,11 +503,9 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> { validate!(self.mdat_pos > 0); validate!(!self.tracks.is_empty()); for track in self.tracks.iter_mut() { - let mut strm = None; - std::mem::swap(&mut track.stream, &mut strm); - if let Some(stream) = strm { + for stream in track.streams.drain(..) { let str_id = strmgr.add_stream(stream).unwrap(); - track.track_str_id = str_id; + track.track_str_ids.push(str_id); } } match self.demux_mode { diff --git a/nihav-commonfmt/src/demuxers/mov/pktread.rs b/nihav-commonfmt/src/demuxers/mov/pktread.rs index 5ec9889..59f2e50 100644 --- a/nihav-commonfmt/src/demuxers/mov/pktread.rs +++ b/nihav-commonfmt/src/demuxers/mov/pktread.rs @@ -142,6 +142,7 @@ pub struct QTPacketDemuxer { pub chunk_offsets: Vec, pub time_to_sample: Vec<(u32, u32)>, pub sample_map: Vec<(u32, u32)>, + pub desc_map: Vec<(u32, u32)>, pub sample_size: u32, pub frame_samples: usize, pub ctts_map: RLESearcher, diff --git a/nihav-commonfmt/src/demuxers/mov/track.rs b/nihav-commonfmt/src/demuxers/mov/track.rs index c6d94e8..4b967e5 100644 --- a/nihav-commonfmt/src/demuxers/mov/track.rs +++ b/nihav-commonfmt/src/demuxers/mov/track.rs @@ -268,267 +268,272 @@ fn read_stsd(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult let _flags = br.read_u24be()?; let entries = br.read_u32be()?; validate!(entries > 0); - let esize = u64::from(br.read_u32be()?); - validate!(esize + 8 <= size); - let mut fcc = [0u8; 4]; + for desc_no in 0..entries { + let estart = br.tell(); + let esize = u64::from(br.read_u32be()?); + let end_pos = br.tell() - 4 + esize; + validate!(esize > 8 && end_pos <= start_pos + size); + let mut fcc = [0u8; 4]; br.read_buf(&mut fcc)?; br.read_skip(6)?; - let _data_ref = br.read_u16be()?; - - track.pkt_demux.fcc = fcc; - - let codec_info; - match track.stream_type { - StreamType::Video => { - let _ver = br.read_u16be()?; - let _revision = br.read_u16le()?; - let _vendor = br.read_u32be()?; - let _temp_quality = br.read_u32be()?; - let _spat_quality = br.read_u32be()?; - let width = br.read_u16be()? as usize; - let height = br.read_u16be()? as usize; - let _hor_res = br.read_u32be()?; - let _vert_res = br.read_u32be()?; - let data_size = br.read_u32be()?; - if !track.ver_m1 { - validate!(data_size == 0); - } - let _frame_count = br.read_u16be()? as usize; - let _cname_len = br.read_byte()? as usize; - br.read_skip(31)?; // actual compressor name - let depth = br.read_u16be()?; - let ctable_id = br.read_u16be()?; - let grayscale = depth > 0x20 || depth == 1; - let depth = if grayscale { depth & 0x1F } else { depth }; - if ctable_id == 0 { - let max_pal_size = start_pos + size - br.tell(); - if depth <= 8 { - let mut pal = [0; 1024]; - read_palette(br, max_pal_size, &mut pal)?; - track.pal = Some(Arc::new(pal)); - } else { - br.read_skip(max_pal_size as usize)?; + let _data_ref = br.read_u16be()?; + + track.pkt_demux.fcc = fcc; + + let codec_info; + match track.stream_type { + StreamType::Video => { + let _ver = br.read_u16be()?; + let _revision = br.read_u16le()?; + let _vendor = br.read_u32be()?; + let _temp_quality = br.read_u32be()?; + let _spat_quality = br.read_u32be()?; + let width = br.read_u16be()? as usize; + let height = br.read_u16be()? as usize; + let _hor_res = br.read_u32be()?; + let _vert_res = br.read_u32be()?; + let data_size = br.read_u32be()?; + if !track.ver_m1 { + validate!(data_size == 0); } - } else if (depth <= 8) && !grayscale { - match depth & 0x1F { - 2 => { + let _frame_count = br.read_u16be()? as usize; + let _cname_len = br.read_byte()? as usize; + br.read_skip(31)?; // actual compressor name + let depth = br.read_u16be()?; + let ctable_id = br.read_u16be()?; + let grayscale = depth > 0x20 || depth == 1; + let depth = if grayscale { depth & 0x1F } else { depth }; + if ctable_id == 0 { + let max_pal_size = start_pos + size - br.tell(); + if depth <= 8 { let mut pal = [0; 1024]; - pal[..4 * 4].copy_from_slice(&MOV_DEFAULT_PAL_2BIT); + read_palette(br, max_pal_size, &mut pal)?; track.pal = Some(Arc::new(pal)); - }, - 4 => { - let mut pal = [0; 1024]; - pal[..16 * 4].copy_from_slice(&MOV_DEFAULT_PAL_4BIT); - track.pal = Some(Arc::new(pal)); - }, - 8 => { - track.pal = Some(Arc::new(MOV_DEFAULT_PAL_8BIT)); - }, - _ => {}, - }; - } else if grayscale && ctable_id != 0xFFFF { - let mut pal = [0; 1024]; - let cdepth = depth & 0x1F; - let size = 1 << cdepth; - for i in 0..size { - let mut clr = ((size - 1 - i) as u8) << (8 - cdepth); - let mut off = 8 - cdepth; - while off >= cdepth { - clr |= clr >> (8 - off); - off -= cdepth; + } else { + br.read_skip(max_pal_size as usize)?; } - if off > 0 { - clr |= clr >> (8 - off); + } else if (depth <= 8) && !grayscale { + match depth & 0x1F { + 2 => { + let mut pal = [0; 1024]; + pal[..4 * 4].copy_from_slice(&MOV_DEFAULT_PAL_2BIT); + track.pal = Some(Arc::new(pal)); + }, + 4 => { + let mut pal = [0; 1024]; + pal[..16 * 4].copy_from_slice(&MOV_DEFAULT_PAL_4BIT); + track.pal = Some(Arc::new(pal)); + }, + 8 => { + track.pal = Some(Arc::new(MOV_DEFAULT_PAL_8BIT)); + }, + _ => {}, + }; + } else if grayscale && ctable_id != 0xFFFF { + let mut pal = [0; 1024]; + let cdepth = depth & 0x1F; + let size = 1 << cdepth; + for i in 0..size { + let mut clr = ((size - 1 - i) as u8) << (8 - cdepth); + let mut off = 8 - cdepth; + while off >= cdepth { + clr |= clr >> (8 - off); + off -= cdepth; + } + if off > 0 { + clr |= clr >> (8 - off); + } + pal[i * 4] = clr; + pal[i * 4 + 1] = clr; + pal[i * 4 + 2] = clr; } - pal[i * 4] = clr; - pal[i * 4 + 1] = clr; - pal[i * 4 + 2] = clr; + track.pal = Some(Arc::new(pal)); } - track.pal = Some(Arc::new(pal)); - } // todo other atoms, put as extradata - let cname = if let Some(name) = find_codec_from_mov_video_fourcc(&fcc) { - name - } else if let Some(name) = find_codec_from_avi_fourcc(&fcc) { - name - } else { - "unknown" - }; - let format = if cname == "rawvideo" { - if &fcc == b"j420" { - validate!(depth == 12); - YUV420_FORMAT + let cname = if let Some(name) = find_codec_from_mov_video_fourcc(&fcc) { + name + } else if let Some(name) = find_codec_from_avi_fourcc(&fcc) { + name } else { - match depth { - 1..=8 | 33..=40 => PAL8_FORMAT, - 15 | 16 => QT_RGB555_FORMAT, - 24 => RGB24_FORMAT, - 32 => ARGB_FORMAT, - _ => { - println!("unknown depth {depth}"); - return Err(DemuxerError::NotImplemented); + "unknown" + }; + let format = if cname == "rawvideo" { + if &fcc == b"j420" { + validate!(depth == 12); + YUV420_FORMAT + } else { + match depth { + 1..=8 | 33..=40 => PAL8_FORMAT, + 15 | 16 => QT_RGB555_FORMAT, + 24 => RGB24_FORMAT, + 32 => ARGB_FORMAT, + _ => { + println!("unknown depth {depth}"); + return Err(DemuxerError::NotImplemented); + } } } - } - } else if depth > 8 && depth <= 32 { - RGB24_FORMAT - } else { - PAL8_FORMAT - }; - let mut vhdr = NAVideoInfo::new(width, height, false, format); - vhdr.bits = depth as u8; - if track.ver_m1 { // skip the rest for the beta version of QT - br.seek(SeekFrom::Start(start_pos + size))?; - } - //skip various common atoms - while br.tell() - start_pos + 8 < size { - let mut buf = [0u8; 8]; - br.peek_buf(&mut buf)?; - let tsize = read_u32be(&buf).unwrap() as usize; - let tag = &buf[4..8]; - validate!(tsize >= 8); - match tag { - b"pasp" | b"clap" | b"gama" => { - br.read_skip(tsize)?; + } else if depth > 8 && depth <= 32 { + RGB24_FORMAT + } else { + PAL8_FORMAT + }; + let mut vhdr = NAVideoInfo::new(width, height, false, format); + vhdr.bits = depth as u8; + if track.ver_m1 { // skip the rest for the beta version of QT + br.seek(SeekFrom::Start(start_pos + size))?; + } + //skip various common atoms + while br.tell() - start_pos + 8 < size { + let mut buf = [0u8; 8]; + br.peek_buf(&mut buf)?; + let tsize = read_u32be(&buf).unwrap() as usize; + let tag = &buf[4..8]; + validate!(tsize >= 8); + match tag { + b"pasp" | b"clap" | b"gama" => { + br.read_skip(tsize)?; + }, + _ => break, + }; + } + let edata = if br.tell() < end_pos { + let edata_size = br.read_u32be()? as usize; + validate!(edata_size >= 4); + let mut buf = vec![0; edata_size - 4]; + br.read_buf(buf.as_mut_slice())?; + Some(buf) + } else { + None + }; + codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Video(vhdr), edata); + }, + StreamType::Audio if track.ver_m1 => { + br.read_skip(8)?; + let nchannels = br.read_u16be()?; + validate!(nchannels == 1 || nchannels == 2); + let sample_size = br.read_u16be()?; + validate!(sample_size == 8 || sample_size == 16); + br.read_u32be()?; + let sample_rate = br.read_u32be()? >> 16; + let cname = if fcc == [0; 4] || &fcc == b"raw " { "pcm" } else { "unknown" }; + let mut soniton = NASoniton::new(sample_size as u8, SONITON_FLAG_SIGNED | SONITON_FLAG_BE); + if sample_size == 8 { + soniton.signed = false; + } + let ahdr = NAAudioInfo::new(sample_rate, nchannels as u8, soniton, 1); + let edata = parse_audio_edata(br, estart, esize)?; + codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata); + track.pkt_demux.mode = if cname == "pcm" { PacketMode::RawAudio } else { PacketMode::AudioCBR }; + track.pkt_demux.bsize = (sample_size / 8) as usize; + track.pkt_demux.channels = nchannels as usize; + track.pkt_demux.bits = sample_size as usize; + if track.tb_den <= 1 { + track.tb_den = sample_rate; + } + }, + StreamType::Audio => { + let sver = br.read_u16be()?; + let _revision = br.read_u16le()?; + let _vendor = br.read_u32be()?; + let mut nchannels = br.read_u16be()?; + if sver != 2 { + validate!(nchannels <= 64); + } + let sample_size = br.read_u16be()?; + validate!(sample_size <= 128); + let compr_id = br.read_u16be()?; + let packet_size = br.read_u16be()? as usize; + validate!(packet_size == 0); + let mut sample_rate = br.read_u32be()? >> 16; + if sver != 2 { + validate!(sample_rate > 0); + } + let cname = if let Some(name) = find_codec_from_mov_audio_fourcc(&fcc) { + name + } else if let (true, Some(name)) = ((fcc[0] == b'm' && fcc[1] == b's'), find_codec_from_wav_twocc(u16::from(fcc[2]) * 256 + u16::from(fcc[3]))) { + name + } else { + "unknown" + }; + let mut soniton = NASoniton::new(sample_size as u8, SONITON_FLAG_SIGNED | SONITON_FLAG_BE); + if &fcc == b"raw " && sample_size == 8 { + soniton.signed = false; + } + if &fcc == b"sowt" { + soniton.be = false; + } + let mut block_align = 1; + match sver { + 1 => { + let samples_per_packet = br.read_u32be()?; + let _bytes_per_packet = br.read_u32be()?; + let bytes_per_frame = br.read_u32be()?; + let _bytes_per_sample = br.read_u32be()?; + track.pkt_demux.bsize = bytes_per_frame as usize; + track.pkt_demux.frame_samples = samples_per_packet as usize; + track.tb_num = samples_per_packet.max(1); + block_align = bytes_per_frame as usize; + }, + 2 => { + br.read_u32be()?; // some size + let srate = br.read_f64be()?; + validate!(srate > 1.0); + sample_rate = srate as u32; + let channels = br.read_u32be()?; + validate!(channels > 0 && channels < 255); + nchannels = channels as u16; + br.read_u32be()?; // always 0x7F000000 + let _bits_per_csample = br.read_u32be()?; + let _codec_flags = br.read_u32be()?; + let bytes_per_frame = br.read_u32be()?; + let samples_per_packet = br.read_u32be()?; + track.pkt_demux.bsize = bytes_per_frame as usize; + track.pkt_demux.frame_samples = samples_per_packet as usize; + track.tb_num = samples_per_packet; + }, + _ => { + track.pkt_demux.bsize = (sample_size / 8) as usize; }, - _ => break, - }; - } - let edata = if br.tell() - start_pos + 4 < size { - let edata_size = br.read_u32be()? as usize; - validate!(edata_size >= 4); - let mut buf = vec![0; edata_size - 4]; - br.read_buf(buf.as_mut_slice())?; - Some(buf) - } else { - None }; - codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Video(vhdr), edata); - }, - StreamType::Audio if track.ver_m1 => { - br.read_skip(8)?; - let nchannels = br.read_u16be()?; - validate!(nchannels == 1 || nchannels == 2); - let sample_size = br.read_u16be()?; - validate!(sample_size == 8 || sample_size == 16); - br.read_u32be()?; - let sample_rate = br.read_u32be()? >> 16; - let cname = if fcc == [0; 4] || &fcc == b"raw " { "pcm" } else { "unknown" }; - let mut soniton = NASoniton::new(sample_size as u8, SONITON_FLAG_SIGNED | SONITON_FLAG_BE); - if sample_size == 8 { - soniton.signed = false; - } - let ahdr = NAAudioInfo::new(sample_rate, nchannels as u8, soniton, 1); - let edata = parse_audio_edata(br, start_pos, size)?; - codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata); - track.pkt_demux.mode = if cname == "pcm" { PacketMode::RawAudio } else { PacketMode::AudioCBR }; - track.pkt_demux.bsize = (sample_size / 8) as usize; - track.pkt_demux.channels = nchannels as usize; - track.pkt_demux.bits = sample_size as usize; - if track.tb_den <= 1 { - track.tb_den = sample_rate; - } - }, - StreamType::Audio => { - let sver = br.read_u16be()?; - let _revision = br.read_u16le()?; - let _vendor = br.read_u32be()?; - let mut nchannels = br.read_u16be()?; - if sver != 2 { - validate!(nchannels <= 64); - } - let sample_size = br.read_u16be()?; - validate!(sample_size <= 128); - let compr_id = br.read_u16be()?; - let packet_size = br.read_u16be()? as usize; - validate!(packet_size == 0); - let mut sample_rate = br.read_u32be()? >> 16; - if sver != 2 { - validate!(sample_rate > 0); - } - let cname = if let Some(name) = find_codec_from_mov_audio_fourcc(&fcc) { - name - } else if let (true, Some(name)) = ((fcc[0] == b'm' && fcc[1] == b's'), find_codec_from_wav_twocc(u16::from(fcc[2]) * 256 + u16::from(fcc[3]))) { - name + if track.tb_den <= 1 { + track.tb_den = sample_rate; + track.pkt_demux.tb_den = sample_rate; + } + track.pkt_demux.mode = if matches!(&fcc, + b"NONE" | b"raw " | b"twos" | b"sowt" | + b"in24" | b"in32" | b"fl32" | b"fl64" | + /*b"ima4" |*/ b"ms\x00\x02" | b"ms\x00\x11" | + b"alaw" | b"ulaw" | + b"MAC3" | b"MAC6") { + PacketMode::RawAudio + } else if sver == 2 || compr_id == 0xFFFE { + PacketMode::AudioVBR } else { - "unknown" + PacketMode::AudioCBR }; - let mut soniton = NASoniton::new(sample_size as u8, SONITON_FLAG_SIGNED | SONITON_FLAG_BE); - if &fcc == b"raw " && sample_size == 8 { - soniton.signed = false; - } - if &fcc == b"sowt" { - soniton.be = false; - } - let mut block_align = 1; - match sver { - 1 => { - let samples_per_packet = br.read_u32be()?; - let _bytes_per_packet = br.read_u32be()?; - let bytes_per_frame = br.read_u32be()?; - let _bytes_per_sample = br.read_u32be()?; - track.pkt_demux.bsize = bytes_per_frame as usize; - track.pkt_demux.frame_samples = samples_per_packet as usize; - track.tb_num = samples_per_packet.max(1); - block_align = bytes_per_frame as usize; - }, - 2 => { - br.read_u32be()?; // some size - let srate = br.read_f64be()?; - validate!(srate > 1.0); - sample_rate = srate as u32; - let channels = br.read_u32be()?; - validate!(channels > 0 && channels < 255); - nchannels = channels as u16; - br.read_u32be()?; // always 0x7F000000 - let _bits_per_csample = br.read_u32be()?; - let _codec_flags = br.read_u32be()?; - let bytes_per_frame = br.read_u32be()?; - let samples_per_packet = br.read_u32be()?; - track.pkt_demux.bsize = bytes_per_frame as usize; - track.pkt_demux.frame_samples = samples_per_packet as usize; - track.tb_num = samples_per_packet; - }, - _ => { - track.pkt_demux.bsize = (sample_size / 8) as usize; - }, - }; - if track.tb_den <= 1 { - track.tb_den = sample_rate; - track.pkt_demux.tb_den = sample_rate; - } - track.pkt_demux.mode = if matches!(&fcc, - b"NONE" | b"raw " | b"twos" | b"sowt" | - b"in24" | b"in32" | b"fl32" | b"fl64" | - /*b"ima4" |*/ b"ms\x00\x02" | b"ms\x00\x11" | - b"alaw" | b"ulaw" | - b"MAC3" | b"MAC6") { - PacketMode::RawAudio - } else if sver == 2 || compr_id == 0xFFFE { - PacketMode::AudioVBR - } else { - PacketMode::AudioCBR - }; - let ahdr = NAAudioInfo::new(sample_rate, nchannels as u8, soniton, block_align); - let edata = parse_audio_edata(br, start_pos, size)?; - codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata); - track.pkt_demux.channels = nchannels as usize; - track.pkt_demux.bits = sample_size as usize; - }, - StreamType::None => { - return Err(DemuxerError::InvalidData); - }, - _ => { + let ahdr = NAAudioInfo::new(sample_rate, nchannels as u8, soniton, block_align); + let edata = parse_audio_edata(br, estart, esize)?; + codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata); + track.pkt_demux.channels = nchannels as usize; + track.pkt_demux.bits = sample_size as usize; + }, + StreamType::None => { + return Err(DemuxerError::InvalidData); + }, + _ => { //todo put it all into extradata - let edata = None; - codec_info = NACodecInfo::new("unknown", NACodecTypeInfo::None, edata); - }, - }; - track.pkt_demux.tb_num = track.tb_num; - track.pkt_demux.tb_den = track.tb_den; + let edata = None; + codec_info = NACodecInfo::new("unknown", NACodecTypeInfo::None, edata); + }, + }; + track.pkt_demux.tb_num = track.tb_num; + track.pkt_demux.tb_den = track.tb_den; + validate!(br.tell() <= end_pos); + br.seek(SeekFrom::Start(end_pos))?; + track.streams.push(NAStream::new(track.stream_type, track.track_no | (desc_no << 16), codec_info, track.tb_num, track.tb_den, u64::from(track.pkt_demux.duration))); + } let read_size = br.tell() - start_pos; - validate!(read_size <= size); - track.stream = Some(NAStream::new(track.stream_type, track.track_no, codec_info, track.tb_num, track.tb_den, u64::from(track.pkt_demux.duration))); track.stsd_found = true; Ok(read_size) } @@ -614,6 +619,7 @@ fn read_stsc(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult validate!(version == 0); let _flags = br.read_u24be()?; let entries = br.read_u32be()? as usize; + let mut last_sd = 0; if track.ver_m1 { validate!(entries < ((u32::MAX / 16) - 8) as usize); validate!((entries * 16 + 8) as u64 == size); @@ -621,8 +627,12 @@ fn read_stsc(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult br.read_u32be()?; let chunk_no = br.read_u32be()?; let nsamples = br.read_u32be()?; - let _sampledesc = br.read_u32be()?; + let sampledesc = br.read_u32be()?; track.pkt_demux.sample_map.push((chunk_no, nsamples)); + if sampledesc != last_sd { + track.pkt_demux.desc_map.push((chunk_no, sampledesc)); + last_sd = sampledesc; + } } return Ok(size); } @@ -634,9 +644,13 @@ fn read_stsc(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult let chunk_no = br.read_u32be()?; validate!(chunk_no > last_chunk_no); let nsamples = br.read_u32be()?; - let _sample_desc = br.read_u32be()?; + let sample_desc = br.read_u32be()?; track.pkt_demux.sample_map.push((chunk_no, nsamples)); last_chunk_no = chunk_no; + if sample_desc != last_sd { + track.pkt_demux.desc_map.push((chunk_no, sample_desc)); + last_sd = sample_desc; + } } Ok(size) } @@ -876,7 +890,7 @@ fn read_trun(track: &mut Track, br: &mut dyn ByteIO, size: u64) -> DemuxerResult pub struct Track { pub ver_m1: bool, pub track_id: u32, - pub track_str_id: usize, + pub track_str_ids: Vec, pub track_no: u32, pub tb_num: u32, pub tb_den: u32, @@ -888,7 +902,7 @@ pub struct Track { pub stream_type: StreamType, pub width: usize, pub height: usize, - pub stream: Option, + pub streams: Vec, pub pal: Option>, pub pkt_demux: QTPacketDemuxer, @@ -904,7 +918,7 @@ impl Track { stsd_found: false, stss_found: false, track_id: 0, - track_str_id: 0, + track_str_ids: Vec::new(), track_no, tb_num: 1, tb_den, @@ -912,7 +926,7 @@ impl Track { stream_type: StreamType::None, width: 0, height: 0, - stream: None, + streams: Vec::new(), depth: 0, pal: None, ver_m1: false, @@ -936,7 +950,7 @@ impl Track { } fn rescale(&mut self, tb_num: u32) { self.tb_div = tb_num; - if let Some(ref mut stream) = self.stream { + for stream in self.streams.iter_mut() { let tb_den = stream.tb_den; let (tb_num, tb_den) = reduce_timebase(tb_num * stream.tb_num, tb_den); stream.duration /= u64::from(self.tb_div); @@ -953,13 +967,31 @@ impl Track { #[allow(clippy::too_many_arguments)] pub fn process_packet(src: &mut dyn ByteIO, strmgr: &StreamManager, track: &mut Track, ts: NATimeInfo, offset: u64, size: usize, first: bool, is_kf: bool) -> DemuxerResult { + let cur_desc = if track.track_str_ids.len() > 1 { + let cur_chunk_no = if track.pkt_demux.mode == PacketMode::OneToOne { + track.pkt_demux.cur_sample + } else { + track.pkt_demux.cur_chunk + }; + let mut cur_desc = 1; + for &(chunk_no, desc_no) in track.pkt_demux.desc_map.iter() { + if chunk_no as usize <= cur_chunk_no { + cur_desc = desc_no; + } + if chunk_no as usize >= cur_chunk_no { + break; + } + } + cur_desc as usize - 1 + } else { 0 }; if let Some(cpts) = ts.get_pts() { let cts = NATimeInfo::rescale_ts(cpts, ts.tb_num, ts.tb_den, 1, 1000); track.pkt_demux.cur_ts = Some(cts); } else { track.pkt_demux.cur_ts = None; } - let stream = strmgr.get_stream(track.track_str_id); + let str_idx = if cur_desc < track.track_str_ids.len() { cur_desc } else { 0 }; + let stream = strmgr.get_stream(track.track_str_ids[str_idx]); if stream.is_none() { return Err(DemuxerError::InvalidData); } let stream = stream.unwrap(); src.seek(SeekFrom::Start(offset))?; -- 2.39.5