X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-commonfmt%2Fsrc%2Fdemuxers%2Fmov.rs;h=d90ff8377214c597557e5ccba74cea39390a7ecd;hb=89b16ac8f770b22585d0f70def9c952ffb48f33c;hp=0c23b02c8adeee1e635ed170517a086ffbf5db56;hpb=2736c15a4e47e346a6a05e12c988b230ec80d2d1;p=nihav.git diff --git a/nihav-commonfmt/src/demuxers/mov.rs b/nihav-commonfmt/src/demuxers/mov.rs index 0c23b02..d90ff83 100644 --- a/nihav-commonfmt/src/demuxers/mov.rs +++ b/nihav-commonfmt/src/demuxers/mov.rs @@ -1,5 +1,6 @@ use nihav_core::demuxers::*; use nihav_registry::register::*; +use nihav_core::compr::deflate::*; macro_rules! mktag { ($a:expr, $b:expr, $c:expr, $d:expr) => ({ @@ -169,6 +170,7 @@ fn read_moov(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> Dem const MOOV_CHUNK_HANDLERS: &[RootChunkHandler] = &[ RootChunkHandler { ctype: mktag!(b"mvhd"), parse: read_mvhd }, + RootChunkHandler { ctype: mktag!(b"cmov"), parse: read_cmov }, RootChunkHandler { ctype: mktag!(b"ctab"), parse: read_ctab }, RootChunkHandler { ctype: mktag!(b"trak"), parse: read_trak }, RootChunkHandler { ctype: mktag!(b"meta"), parse: read_meta }, @@ -202,6 +204,45 @@ fn read_mvhd(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> De Ok(KNOWN_MVHD_SIZE) } +fn read_cmov(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult { + let br = &mut dmx.src; + validate!(size > 24); + let dcom_size = br.read_u32be()?; + let dcom_tag = br.read_tag()?; + let compr_type = br.read_tag()?; + validate!(&dcom_tag == b"dcom" && dcom_size == 12); + if &compr_type != b"zlib" { + return Err(DemuxerError::NotImplemented); + } + let cmvd_size = u64::from(br.read_u32be()?); + let cmvd_tag = br.read_tag()?; + validate!(&cmvd_tag == b"cmvd" && cmvd_size > 14 && cmvd_size == size - 12); + let comp_size = (cmvd_size - 12) as usize; + let uncomp_size = br.read_u32be()? as usize; + validate!(uncomp_size > 8); + let mut sbuf = vec![0; comp_size]; + let mut dbuf = vec![0; uncomp_size]; + br.read_buf(sbuf.as_mut_slice())?; + let ret = Inflate::uncompress(sbuf.as_slice(), dbuf.as_mut_slice()); + if ret.is_err() { + return Err(DemuxerError::InvalidData); + } + let len = ret.unwrap(); + validate!(len == uncomp_size); + let mut mr = MemoryReader::new_read(dbuf.as_slice()); + let mut br = ByteReader::new(&mut mr); + let (ctype, csize) = read_chunk_header(&mut br)?; + validate!(ctype == mktag!(b"moov")); + let mut ddmx = MOVDemuxer::new(&mut br); + ddmx.read_moov(strmgr, csize)?; + std::mem::swap(&mut dmx.tracks, &mut ddmx.tracks); + dmx.duration = ddmx.duration; + dmx.tb_den = ddmx.tb_den; + std::mem::swap(&mut dmx.pal, &mut ddmx.pal); + + Ok(size) +} + fn read_ctab(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult { let mut pal = [0; 1024]; let size = read_palette(&mut dmx.src, size, &mut pal)?; @@ -384,6 +425,39 @@ const STBL_CHUNK_HANDLERS: &[TrackChunkHandler] = &[ TrackChunkHandler { ctype: mktag!(b"stsh"), parse: skip_chunk }, ]; +fn parse_audio_edata(br: &mut ByteReader, start_pos: u64, size: u64) -> DemuxerResult>> { + let read_part = br.tell() - start_pos; + if read_part + 8 < size { + let csize = br.read_u32be()? as u64; + let ctag = br.read_u32be()?; + validate!(read_part + csize <= size); + validate!(ctag == mktag!(b"wave")); + if csize == 8 { + return Ok(None); + } + let mut buf = [0; 8]; + br.peek_buf(&mut buf)?; + if &buf[4..8] == b"frma" { + br.read_skip(12)?; + if csize > 20 { + let mut buf = vec![0; (csize - 20) as usize]; + br.read_buf(&mut buf)?; + Ok(Some(buf)) + } else { + Ok(None) + } + } else if csize > 8 { + let mut buf = vec![0; (csize as usize) - 8]; + br.read_buf(&mut buf)?; + Ok(Some(buf)) + } else { + Ok(None) + } + } else { + Ok(None) + } +} + fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult { const KNOWN_STSD_SIZE: u64 = 24; validate!(size >= KNOWN_STSD_SIZE); @@ -393,7 +467,7 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult let _flags = br.read_u24be()?; let entries = br.read_u32be()?; validate!(entries > 0); - let esize = br.read_u32be()? as u64; + let esize = u64::from(br.read_u32be()?); validate!(esize + 8 <= size); let mut fcc = [0u8; 4]; br.read_buf(&mut fcc)?; @@ -421,13 +495,15 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult br.read_skip(31)?; // actual compressor name let depth = br.read_u16be()?; let ctable_id = br.read_u16be()?; - validate!(((depth & 0x1F) <= 8) || (ctable_id == 0xFFFF)); + let grayscale = depth > 0x20 || depth == 1; + let depth = if grayscale { depth & 0x1F } else { depth }; + validate!(depth <= 8 || (ctable_id == 0xFFFF)); if ctable_id == 0 { let max_pal_size = start_pos + size - br.tell(); let mut pal = [0; 1024]; read_palette(br, max_pal_size, &mut pal)?; track.pal = Some(Arc::new(pal)); - } else if (depth & 0x20) == 0 && (depth & 0x1F) <= 8 { + } else if (depth <= 8) && !grayscale { match depth & 0x1F { 2 => { let mut pal = [0; 1024]; @@ -444,12 +520,12 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult }, _ => {}, }; - } else if (depth & 0x1F) <= 8 { + } 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; + let mut clr = ((size - 1 - i) as u8) << (8 - cdepth); let mut off = 8 - cdepth; while off >= cdepth { clr |= clr >> (8 - off); @@ -473,21 +549,21 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult "unknown" }; let format = if depth > 8 { RGB24_FORMAT } else { PAL8_FORMAT }; - let vhdr = NAVideoInfo::new(width, height, false, format); - let edata; - if br.tell() - start_pos + 4 < size { + let mut vhdr = NAVideoInfo::new(width, height, false, format); + vhdr.bits = depth as u8; + 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]; + let edata_size = br.read_u32be()? as usize; + let mut buf = vec![0; edata_size]; br.read_buf(buf.as_mut_slice())?; - edata = Some(buf); - } else { - edata = None; - } + Some(buf) + } else { + None + }; codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Video(vhdr), edata); }, StreamType::Audio => { - let _ver = br.read_u16be()?; + let sver = br.read_u16be()?; let _revision = br.read_u16le()?; let _vendor = br.read_u32be()?; let nchannels = br.read_u16be()?; @@ -509,8 +585,14 @@ fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult //todo adjust format for various PCM kinds 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 _bytes_per_packet = br.read_u32be()?; + let _bytes_per_frame = br.read_u32be()?; + let _bytes_per_sample = br.read_u32be()?; + } let ahdr = NAAudioInfo::new(sample_rate >> 16, nchannels as u8, soniton, block_align); - let edata = None; + let edata = parse_audio_edata(br, start_pos, size)?; codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata); track.channels = nchannels as usize; track.bits = sample_size as usize; @@ -676,7 +758,7 @@ impl Track { read_chunk_list!(track; "minf", read_minf, MINF_CHUNK_HANDLERS); read_chunk_list!(track; "stbl", read_stbl, STBL_CHUNK_HANDLERS); fn fill_seek_index(&self, seek_index: &mut SeekIndex) { - if self.keyframes.len() > 0 { + if !self.keyframes.is_empty() { seek_index.mode = SeekIndexMode::Present; } for kf_time in self.keyframes.iter() { @@ -760,9 +842,9 @@ impl Track { } } fn get_size(&self, sample_no: usize) -> usize { - if self.chunk_sizes.len() > 0 { + if !self.chunk_sizes.is_empty() { self.chunk_sizes[sample_no] as usize - } else if self.sample_map.len() > 0 { + } else if !self.sample_map.is_empty() { let mut nsamp = 0; for (idx, samples) in self.sample_map.iter() { if *idx as usize <= self.cur_chunk { @@ -781,7 +863,7 @@ impl Track { self.samples_left = 0; if self.stream_type == StreamType::Audio { self.cur_chunk = self.cur_sample; - } else if self.chunk_offsets.len() != self.chunk_sizes.len() && self.sample_map.len() > 0{ + } else if self.chunk_offsets.len() != self.chunk_sizes.len() && !self.sample_map.is_empty() { let mut csamp = 0; self.cur_chunk = 0; let mut cmap = self.sample_map.iter(); @@ -816,7 +898,7 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> { fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> { self.read_root(strmgr)?; validate!(self.mdat_pos > 0); - validate!(self.tracks.len() > 0); + validate!(!self.tracks.is_empty()); for track in self.tracks.iter() { track.fill_seek_index(seek_index); } @@ -826,7 +908,7 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> { } fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult { - if self.tracks.len() == 0 { + if self.tracks.is_empty() { return Err(DemuxerError::EOF); } for _ in 0..self.tracks.len() { @@ -849,7 +931,7 @@ impl<'a> DemuxCore<'a> for MOVDemuxer<'a> { return Ok(pkt); } } - return Err(DemuxerError::EOF); + Err(DemuxerError::EOF) } fn seek(&mut self, time: u64, seek_index: &SeekIndex) -> DemuxerResult<()> {