introduce stream and container duration
[nihav.git] / nihav-commonfmt / src / demuxers / mov.rs
index d90ff8377214c597557e5ccba74cea39390a7ecd..9236baa1b0667d0132745e31e3465d959dafe193 100644 (file)
@@ -239,7 +239,7 @@ fn read_cmov(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> Dem
     dmx.duration = ddmx.duration;
     dmx.tb_den = ddmx.tb_den;
     std::mem::swap(&mut dmx.pal, &mut ddmx.pal);
-    
+
     Ok(size)
 }
 
@@ -292,7 +292,7 @@ fn read_tkhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
     let _mtime              = br.read_u32be()?;
     let track_id            = br.read_u32be()?;
                               br.read_skip(4)?;
-    let _duration           = br.read_u32be()?;
+    let duration            = br.read_u32be()?;
                               br.read_skip(8)?;
     let _layer              = br.read_u16be()?;
     let _alt_group          = br.read_u16be()?;
@@ -304,6 +304,7 @@ fn read_tkhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
     track.width  = width  >> 16;
     track.height = height >> 16;
     track.track_id = track_id;
+    track.duration = duration;
 
     track.tkhd_found = true;
     Ok(KNOWN_TKHD_SIZE)
@@ -428,6 +429,14 @@ const STBL_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
 fn parse_audio_edata(br: &mut ByteReader, start_pos: u64, size: u64) -> DemuxerResult<Option<Vec<u8>>> {
     let read_part = br.tell() - start_pos;
     if read_part + 8 < size {
+        let mut buf = [0; 8];
+                              br.peek_buf(&mut buf)?;
+        if &buf[4..8] != b"wave" {
+            let mut buf = vec![0; (size - read_part) as usize];
+                              br.read_buf(&mut buf)?;
+            return Ok(Some(buf));
+        }
+
         let csize           = br.read_u32be()? as u64;
         let ctag            = br.read_u32be()?;
         validate!(read_part + csize <= size);
@@ -554,7 +563,8 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
             let edata = if br.tell() - start_pos + 4 < size {
 //todo skip various common atoms
                     let edata_size  = br.read_u32be()? as usize;
-                    let mut buf = vec![0; edata_size];
+                    validate!(edata_size >= 4);
+                    let mut buf = vec![0; edata_size - 4];
                                   br.read_buf(buf.as_mut_slice())?;
                     Some(buf)
                 } else {
@@ -586,10 +596,14 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
             let soniton = NASoniton::new(sample_size as u8, SONITON_FLAG_SIGNED | SONITON_FLAG_BE);
             let block_align = 1;
             if sver == 1 {
-                let _samples_per_packet     = br.read_u32be()?;
+                let samples_per_packet      = br.read_u32be()?;
                 let _bytes_per_packet       = br.read_u32be()?;
-                let _bytes_per_frame        = 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;
+            } else {
+                track.bsize = sample_size as usize;
             }
             let ahdr = NAAudioInfo::new(sample_rate >> 16, nchannels as u8, soniton, block_align);
             let edata = parse_audio_edata(br, start_pos, size)?;
@@ -608,7 +622,7 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
     };
     let read_size = br.tell() - start_pos;
     validate!(read_size <= size);
-    track.stream = Some(NAStream::new(track.stream_type, track.track_no, codec_info, 1, track.tb_den));
+    track.stream = Some(NAStream::new(track.stream_type, track.track_no, codec_info, 1, track.tb_den, u64::from(track.duration)));
     track.stsd_found = true;
     Ok(read_size)
 }
@@ -658,6 +672,9 @@ fn read_stsz(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult
     let sample_size         = br.read_u32be()?;
     if sample_size != 0 {
         track.sample_size = sample_size;
+        if track.sample_size != 1 || track.bsize == 0 {
+            track.bsize = sample_size as usize;
+        }
         Ok(8)
     } else {
         let entries             = br.read_u32be()? as usize;
@@ -702,6 +719,7 @@ struct Track {
     track_str_id:   usize,
     track_no:       u32,
     tb_den:         u32,
+    duration:       u32,
     depth:          u8,
     tkhd_found:     bool,
     stsd_found:     bool,
@@ -710,12 +728,14 @@ struct Track {
     height:         usize,
     channels:       usize,
     bits:           usize,
+    bsize:          usize,
     fcc:            [u8; 4],
     keyframes:      Vec<u32>,
     chunk_sizes:    Vec<u32>,
     chunk_offsets:  Vec<u64>,
     sample_map:     Vec<(u32, u32)>,
     sample_size:    u32,
+    frame_samples:  usize,
     stream:         Option<NAStream>,
     cur_chunk:      usize,
     cur_sample:     usize,
@@ -733,17 +753,20 @@ impl Track {
             track_str_id:   0,
             track_no,
             tb_den,
+            duration:       0,
             stream_type:    StreamType::None,
             width:          0,
             height:         0,
             channels:       0,
             bits:           0,
+            bsize:          0,
             fcc:            [0; 4],
             keyframes:      Vec::new(),
             chunk_sizes:    Vec::new(),
             chunk_offsets:  Vec::new(),
             sample_map:     Vec::new(),
             sample_size:    0,
+            frame_samples:  0,
             stream:         None,
             depth:          0,
             cur_chunk:      0,
@@ -773,7 +796,7 @@ impl Track {
     }
     fn calculate_chunk_size(&self, nsamp: usize) -> usize {
         if nsamp == 0 {
-            self.sample_size as usize
+            self.bsize
         } else {
             match &self.fcc {
                 b"NONE" | b"raw " | b"twos" | b"sowt" => {
@@ -799,7 +822,7 @@ impl Track {
                 b"ms\x00\x21" => { //IMA ADPCM
                     (nsamp / 2 + 4) * self.channels
                 },
-                _ => self.sample_size as usize,
+                _ => self.bsize,
             }
         }
     }
@@ -834,6 +857,14 @@ impl Track {
             self.last_offset += size as u64;
             if self.stream_type == StreamType::Video {
                 self.samples_left -= 1;
+            } else if self.frame_samples != 0 && self.bsize != 0 {
+                let nblocks = size / self.bsize;
+                if nblocks > 0 {
+                    let consumed = (nblocks * self.frame_samples).min(self.samples_left);
+                    self.samples_left -= consumed;
+                } else {
+                    self.samples_left = 0;
+                }
             } else {
                 self.samples_left = 0;
             }
@@ -855,7 +886,7 @@ impl Track {
             }
             self.calculate_chunk_size(nsamp as usize)
         } else {
-            self.sample_size as usize
+            self.bsize
         }
     }
     fn seek(&mut self, pts: u64) {
@@ -934,7 +965,7 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> {
         Err(DemuxerError::EOF)
     }
 
-    fn seek(&mut self, time: u64, seek_index: &SeekIndex) -> DemuxerResult<()> {
+    fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
         let ret = seek_index.find_pos(time);
         if ret.is_none() {
             return Err(DemuxerError::SeekError);
@@ -945,6 +976,13 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> {
         }
         Ok(())
     }
+    fn get_duration(&self) -> u64 {
+        if self.tb_den != 0 {
+            u64::from(self.duration) * 1000 / u64::from(self.tb_den)
+        } else {
+            0
+        }
+    }
 }
 
 impl<'a> NAOptionHandler for MOVDemuxer<'a> {