replace vec.truncate(0) with vec.clear()
[nihav.git] / nihav-commonfmt / src / demuxers / mov.rs
index 9a77496fc2717e70ba563b2756adacd18ae65ba6..90ca6c5eb0726a1a34ce74f9315c252dc00fb550 100644 (file)
@@ -205,6 +205,7 @@ const MOOV_CHUNK_HANDLERS: &[RootChunkHandler] = &[
     RootChunkHandler { ctype: mktag!(b"trak"), parse: read_trak },
     RootChunkHandler { ctype: mktag!(b"meta"), parse: read_meta },
     RootChunkHandler { ctype: mktag!(b"mvex"), parse: read_mvex },
+    RootChunkHandler { ctype: mktag!(b"iods"), parse: skip_chunk_mov },
 ];
 
 fn read_mvhd(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
@@ -291,6 +292,10 @@ fn read_mvex(_dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, _size: u64) ->
     Ok(0)
 }
 
+fn skip_chunk_mov(_dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, _size: u64) -> DemuxerResult<u64> {
+    Ok(0)
+}
+
 fn read_trak(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
     let mut track = Track::new(dmx.cur_track as u32, dmx.tb_den);
     track.print_chunks = dmx.print_chunks;
@@ -684,15 +689,19 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
             let sver            = br.read_u16be()?;
             let _revision       = br.read_u16le()?;
             let _vendor         = br.read_u32be()?;
-            let nchannels       = br.read_u16be()?;
-            validate!(nchannels <= 64);
+            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 sample_rate     = br.read_u32be()?;
-            validate!(sample_rate > (1 << 16));
+            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]))) {
@@ -705,18 +714,38 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
                 soniton.signed = false;
             }
             let block_align = 1;
-            if 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.bsize = bytes_per_frame as usize;
-                track.frame_samples = samples_per_packet as usize;
-                track.tb_num = samples_per_packet;
-            } else {
-                track.bsize = (sample_size / 8) as usize;
-            }
-            track.tb_den = sample_rate >> 16;
+            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.bsize = bytes_per_frame as usize;
+                    track.frame_samples = samples_per_packet as usize;
+                    track.tb_num = samples_per_packet;
+                },
+                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.bsize = bytes_per_frame as usize;
+                    track.frame_samples = samples_per_packet as usize;
+                    track.tb_num = samples_per_packet;
+                },
+                _ => {
+                    track.bsize = (sample_size / 8) as usize;
+                },
+            };
+            track.tb_den = sample_rate;
             track.raw_audio = match &fcc {
                     b"NONE" | b"raw " | b"twos" | b"sowt" |
                     b"in24" | b"in32" | b"fl32" | b"fl64" |
@@ -725,7 +754,7 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
                     b"MAC3" | b"MAC6" => true,
                     _ => false,
                 };
-            let ahdr = NAAudioInfo::new(sample_rate >> 16, nchannels as u8, soniton, block_align);
+            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.channels  = nchannels as usize;
@@ -762,7 +791,7 @@ fn read_stts(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
         validate!(tb_num != 0);
         track.rescale(tb_num);
     } else {
-        track.time_to_sample.truncate(0);
+        track.time_to_sample.clear();
         track.time_to_sample.reserve(entries);
         for _ in 0..entries {
             let count       = br.read_u32be()?;
@@ -979,6 +1008,9 @@ fn read_trun(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
         track.ctts_map.reserve(sample_count);
     }
 
+    if track.chunk_offsets.len() < (std::u32::MAX as usize) {
+        track.keyframes.push((track.chunk_offsets.len() + 1) as u32);
+    }
     for _ in 0..sample_count {
         if sample_duration_present {
             let _duration       = br.read_u32be()?;
@@ -1053,6 +1085,7 @@ struct Track {
     stream:         Option<NAStream>,
     cur_chunk:      usize,
     cur_sample:     usize,
+    cur_ts:         Option<u64>,
     samples_left:   usize,
     last_offset:    u64,
     pal:            Option<Arc<[u8; 1024]>>,
@@ -1077,7 +1110,7 @@ impl TimeSearcher {
     fn reset(&mut self) {
         *self = Self::default();
     }
-    fn map_time(&mut self, sample: u32, tts: &Vec<(u32, u32)>) -> u64 {
+    fn map_time(&mut self, sample: u32, tts: &[(u32, u32)]) -> u64 {
         if tts.is_empty() {
             u64::from(sample)
         } else if sample >= self.sbase {
@@ -1115,7 +1148,7 @@ struct RLESearcher<T> {
 impl<T:Default+Copy> RLESearcher<T> {
     fn new() -> Self { Self::default() }
     fn resize(&mut self, size: usize) {
-        self.array.truncate(0);
+        self.array.clear();
         self.array.reserve(size);
     }
     fn reserve(&mut self, size: usize) {
@@ -1195,6 +1228,7 @@ impl Track {
             depth:          0,
             cur_chunk:      0,
             cur_sample:     0,
+            cur_ts:         None,
             samples_left:   0,
             last_offset:    0,
             pal:            None,
@@ -1363,9 +1397,11 @@ impl Track {
             self.bsize
         }
     }
+    #[allow(clippy::collapsible_if)]
     fn seek(&mut self, pts: u64, tpoint: NATimePoint) -> DemuxerResult<()> {
         self.cur_sample = pts as usize;
         self.samples_left = 0;
+        self.cur_ts = None;
         if self.stream_type == StreamType::Audio {
             if let NATimePoint::Milliseconds(ms) = tpoint {
                 let exp_pts = NATimeInfo::time_to_ts(ms, 1000, self.tb_num, self.tb_den);
@@ -1503,6 +1539,25 @@ impl Track {
     }
 }
 
+fn process_packet(src: &mut ByteReader, strmgr: &StreamManager, track: &mut Track, pts: NATimeInfo, offset: u64, size: usize, first: bool) -> DemuxerResult<NAPacket> {
+    if let Some(cpts) = pts.get_pts() {
+        let ts = NATimeInfo::ts_to_time(cpts, 1000, pts.tb_num, pts.tb_den);
+        track.cur_ts = Some(ts);
+    } else {
+        track.cur_ts = None;
+    }
+    let str = strmgr.get_stream(track.track_str_id);
+    if str.is_none() { return Err(DemuxerError::InvalidData); }
+    let stream = str.unwrap();
+    src.seek(SeekFrom::Start(offset))?;
+    let mut pkt = src.read_packet(stream, pts, false, size)?;
+    if let Some(ref pal) = track.pal {
+        let side_data = NASideData::Palette(first, pal.clone());
+        pkt.add_side_data(side_data);
+    }
+    Ok(pkt)
+}
+
 impl<'a> DemuxCore<'a> for MOVDemuxer<'a> {
     fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
         self.read_root(strmgr)?;
@@ -1528,6 +1583,30 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> {
         if self.tracks.is_empty() {
             return Err(DemuxerError::EOF);
         }
+        let mut has_all_time = true;
+        let mut min_ts = std::u64::MAX;
+        for trk in self.tracks.iter() {
+            if let Some(ts) = trk.cur_ts {
+                min_ts = min_ts.min(ts);
+            } else {
+                has_all_time = false;
+                break;
+            }
+        }
+        if has_all_time {
+            for (trk_no, track) in self.tracks.iter_mut().enumerate() {
+                if let Some(ts) = track.cur_ts {
+                    if ts == min_ts {
+                        let first = track.cur_sample == 0;
+                        if let Some((pts, offset, size)) = track.get_next_chunk() {
+                            self.cur_track = trk_no + 1;
+                            return process_packet(&mut self.src, strmgr, track, pts, offset, size, first);
+                        }
+                    }
+                }
+            }
+        }
+
         for _ in 0..self.tracks.len() {
             if self.cur_track >= self.tracks.len() {
                 self.cur_track = 0;
@@ -1536,16 +1615,7 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> {
             self.cur_track += 1;
             let first = track.cur_sample == 0;
             if let Some((pts, offset, size)) = track.get_next_chunk() {
-                let str = strmgr.get_stream(track.track_str_id);
-                if str.is_none() { return Err(DemuxerError::InvalidData); }
-                let stream = str.unwrap();
-                self.src.seek(SeekFrom::Start(offset))?;
-                let mut pkt = self.src.read_packet(stream, pts, false, size)?;
-                if let Some(ref pal) = track.pal {
-                    let side_data = NASideData::Palette(first, pal.clone());
-                    pkt.add_side_data(side_data);
-                }
-                return Ok(pkt);
+                return process_packet(&mut self.src, strmgr, track, pts, offset, size, first);
             }
         }
         Err(DemuxerError::EOF)
@@ -1604,6 +1674,7 @@ const DEMUXER_OPTIONS: &[NAOptionDefinition] = &[
 
 impl<'a> NAOptionHandler for MOVDemuxer<'a> {
     fn get_supported_options(&self) -> &[NAOptionDefinition] { DEMUXER_OPTIONS }
+    #[allow(clippy::single_match)]
     fn set_options(&mut self, options: &[NAOption]) {
         for option in options.iter() {
             for opt_def in DEMUXER_OPTIONS.iter() {