X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-commonfmt%2Fsrc%2Fdemuxers%2Favi.rs;h=73bd02f9731139c93f08fa270dec22c7bceb6a3c;hp=739cd012c3c3d971c258f33238af35c0f3b81ca1;hb=da88eeb81c3c1a8b36081f3838f16c038cb68027;hpb=956ef3a088a7cf14292b874ab6f49d2c3e31090a diff --git a/nihav-commonfmt/src/demuxers/avi.rs b/nihav-commonfmt/src/demuxers/avi.rs index 739cd01..73bd02f 100644 --- a/nihav-commonfmt/src/demuxers/avi.rs +++ b/nihav-commonfmt/src/demuxers/avi.rs @@ -1,6 +1,7 @@ use nihav_core::demuxers::*; use nihav_registry::register; use nihav_core::demuxers::DemuxerError::*; +use std::str::FromStr; macro_rules! mktag { ($a:expr, $b:expr, $c:expr, $d:expr) => ({ @@ -52,6 +53,7 @@ struct AVIDemuxer<'a> { sstate: StreamState, tb_num: u32, tb_den: u32, + strm_duration: u32, key_offs: Vec, pal: Vec, } @@ -97,7 +99,7 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> { if self.movi_size == 0 { return Err(EOF); } continue; } - if tag[0] == b'i' && tag[1] == b'x' { + if (tag[0] == b'i' && tag[1] == b'x') || (&tag == b"idx1") { return Err(EOF); } if tag[0] < b'0' || tag[0] > b'9' || tag[1] < b'0' || tag[1] > b'9' { @@ -119,7 +121,10 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> { continue; } let (tb_num, tb_den) = stream.get_timebase(); - let ts = NATimeInfo::new(Some(self.cur_frame[stream_no as usize]), None, None, tb_num, tb_den); + let mut ts = NATimeInfo::new(Some(self.cur_frame[stream_no as usize]), None, None, tb_num, tb_den); + if stream.get_media_type() == StreamType::Audio && tb_num == 1 && stream.get_info().get_name() == "pcm" { + ts.pts = None; + } let mut pkt = self.src.read_packet(stream, ts, is_keyframe, size)?; for pe in self.pal.iter_mut() { if pe.stream_no == (stream_no as usize) { @@ -135,7 +140,7 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> { } } - 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); @@ -152,6 +157,13 @@ impl<'a> DemuxCore<'a> for AVIDemuxer<'a> { Ok(()) } + fn get_duration(&self) -> u64 { 0 } +} + +impl<'a> NAOptionHandler for AVIDemuxer<'a> { + fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } + fn set_options(&mut self, _options: &[NAOption]) { } + fn query_option_value(&self, _name: &str) -> Option { None } } impl<'a> AVIDemuxer<'a> { @@ -167,6 +179,7 @@ impl<'a> AVIDemuxer<'a> { sstate: StreamState::new(), tb_num: 0, tb_den: 0, + strm_duration: 0, key_offs: Vec::new(), pal: Vec::new(), } @@ -292,7 +305,8 @@ impl<'a> AVIDemuxer<'a> { newpal[i * 4] = self.src.read_byte()?; newpal[i * 4 + 1] = self.src.read_byte()?; newpal[i * 4 + 2] = self.src.read_byte()?; - newpal[i * 4 + 3] = self.src.read_byte()?; + newpal[i * 4 + 3] = 0; + self.src.read_byte()?; // flags } pe.pal = Arc::new(newpal); pe.changed = true; @@ -353,7 +367,7 @@ fn parse_strh(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> dmx.tb_num = dmx.src.read_u32le()?; //scale dmx.tb_den = dmx.src.read_u32le()?; //rate dmx.src.read_skip(4)?; //start - dmx.src.read_skip(4)?; //length + dmx.strm_duration = dmx.src.read_u32le()?; dmx.src.read_skip(4)?; //buf size dmx.src.read_skip(4)?; //quality dmx.src.read_skip(4)?; //sample size @@ -392,7 +406,7 @@ fn parse_strf(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> fn parse_strf_vids(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult { if size < 40 { return Err(InvalidData); } let bi_size = dmx.src.read_u32le()?; - if (bi_size as usize) > size { return Err(InvalidData); } + if (bi_size as usize) < 40 { return Err(InvalidData); } let width = dmx.src.read_u32le()?; let height = dmx.src.read_u32le()? as i32; let planes = dmx.src.read_u16le()?; @@ -408,33 +422,84 @@ fn parse_strf_vids(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize let flip = height < 0; let format = if bitcount > 8 { RGB24_FORMAT } else { PAL8_FORMAT }; - let vhdr = NAVideoInfo::new(width as usize, if flip { -height as usize } else { height as usize}, flip, PAL8_FORMAT); + let mut vhdr = NAVideoInfo::new(width as usize, if flip { -height as usize } else { height as usize}, flip, format); + vhdr.bits = (planes as u8) * (bitcount as u8); + let cname = if find_raw_rgb_fmt(&compression, planes, bitcount, flip, &mut vhdr) { + "rawvideo-ms" + } else if find_raw_yuv_fmt(&compression, &mut vhdr) { + "rawvideo" + } else { + match register::find_codec_from_avi_fourcc(&compression) { + None => "unknown", + Some(name) => name, + } + }; let vci = NACodecTypeInfo::Video(vhdr); let edata = dmx.read_extradata(size - 40)?; if colors > 0 { if let Some(ref buf) = edata { let mut pal = [0u8; 1024]; for (dpal, spal) in pal.chunks_mut(4).take(colors as usize).zip(buf.chunks(4)) { - dpal[0] = spal[0]; + dpal[0] = spal[2]; dpal[1] = spal[1]; - dpal[2] = spal[2]; - dpal[3] = spal[3]; + dpal[2] = spal[0]; + dpal[3] = 0; } let pal = PalInfo { pal: Arc::new(pal), changed: true, stream_no: strmgr.get_num_streams() }; dmx.pal.push(pal); } } - let cname = match register::find_codec_from_avi_fourcc(&compression) { - None => "unknown", - Some(name) => name, - }; let vinfo = NACodecInfo::new(cname, vci, edata); - let res = strmgr.add_stream(NAStream::new(StreamType::Video, u32::from(dmx.sstate.strm_no), vinfo, dmx.tb_num, dmx.tb_den)); + let res = strmgr.add_stream(NAStream::new(StreamType::Video, u32::from(dmx.sstate.strm_no), vinfo, dmx.tb_num, dmx.tb_den, u64::from(dmx.strm_duration))); if res.is_none() { return Err(MemoryError); } dmx.sstate.reset(); Ok(size) } +fn find_raw_rgb_fmt(compr: &[u8; 4], planes: u16, bitcount: u16, flip: bool, vhdr: &mut NAVideoInfo) -> bool { + match compr { + &[0, 0, 0, 0] | b"DIB " => { + if planes != 1 { + return false; + } + let fmt_name = match bitcount { + 8 => "pal8", + 16 => "bgr555", + 24 => "bgr24", + 32 => "bgra24", + _ => return false, + }; + if let Ok(fmt) = NAPixelFormaton::from_str(fmt_name) { + vhdr.format = fmt; + vhdr.flipped = !flip; + true + } else { + false + } + }, + _ => false, + } +} + +fn find_raw_yuv_fmt(compr: &[u8; 4], vhdr: &mut NAVideoInfo) -> bool { + let (fmt_name, swapuv) = match compr { + b"UYVY" | b"UYNY" | b"UYNV" | b"2vuy" => ("uyvy", false), + b"I420" | b"IYUV" => ("yuv420p", false), + b"YV12" => ("yuv420p", true), + b"YVU9" => ("yuv410p", true), + _ => return false, + }; + if let Ok(fmt) = NAPixelFormaton::from_str(fmt_name) { + vhdr.format = fmt; + if swapuv { + vhdr.format.comp_info.swap(1, 2); + } + true + } else { + false + } +} + #[allow(unused_variables)] fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult { if size < 16 { return Err(InvalidData); } @@ -445,15 +510,22 @@ fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize let block_align = dmx.src.read_u16le()?; let bits_per_sample = dmx.src.read_u16le()?; - let soniton = NASoniton::new(bits_per_sample as u8, SONITON_FLAG_SIGNED); + let signed = bits_per_sample > 8; + let soniton = NASoniton::new(bits_per_sample as u8, if signed { SONITON_FLAG_SIGNED } else { 0 }); let ahdr = NAAudioInfo::new(samplespersec, channels as u8, soniton, block_align as usize); - let edata = dmx.read_extradata(size - 16)?; + let edata = if size > 16 { + let edata_size = dmx.src.read_u16le()? as usize; + validate!(edata_size + 18 <= size); + dmx.read_extradata(size - 18)? + } else { + None + }; let cname = match register::find_codec_from_wav_twocc(w_format_tag) { None => "unknown", Some(name) => name, }; let ainfo = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata); - let res = strmgr.add_stream(NAStream::new(StreamType::Audio, u32::from(dmx.sstate.strm_no), ainfo, dmx.tb_num, dmx.tb_den)); + let res = strmgr.add_stream(NAStream::new(StreamType::Audio, u32::from(dmx.sstate.strm_no), ainfo, dmx.tb_num, dmx.tb_den, u64::from(dmx.strm_duration))); if res.is_none() { return Err(MemoryError); } dmx.sstate.reset(); Ok(size) @@ -462,7 +534,7 @@ fn parse_strf_auds(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize fn parse_strf_xxxx(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> DemuxerResult { let edata = dmx.read_extradata(size)?; let info = NACodecInfo::new("unknown", NACodecTypeInfo::None, edata); - let res = strmgr.add_stream(NAStream::new(StreamType::Data, u32::from(dmx.sstate.strm_no), info, dmx.tb_num, dmx.tb_den)); + let res = strmgr.add_stream(NAStream::new(StreamType::Data, u32::from(dmx.sstate.strm_no), info, dmx.tb_num, dmx.tb_den, u64::from(dmx.strm_duration))); if res.is_none() { return Err(MemoryError); } dmx.sstate.reset(); Ok(size) @@ -497,17 +569,27 @@ fn parse_junk(dmx: &mut AVIDemuxer, strmgr: &mut StreamManager, size: usize) -> Ok(size) } +#[allow(clippy::verbose_bit_mask)] fn parse_idx1(src: &mut ByteReader, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex, size: usize, movi_pos: u64, key_offs: &mut Vec) -> DemuxerResult { validate!((size & 15) == 0); let mut tag = [0u8; 4]; let num_entries = size >> 4; let mut counter = [0u64; 100]; + let mut add_offset = 0; + let mut set_offset = false; for _ in 0..num_entries { src.read_buf(&mut tag)?; let flags = src.read_u32le()?; - let offset = src.read_u32le()? as u64; + let mut offset = src.read_u32le()? as u64; let _length = src.read_u32le()?; + if !set_offset && offset < movi_pos { + add_offset = movi_pos - offset; + } + set_offset = true; + + offset += add_offset; + if tag[0] < b'0' || tag[0] > b'9' || tag[1] < b'0' || tag[1] > b'9' { return Err(InvalidData); } @@ -519,7 +601,8 @@ fn parse_idx1(src: &mut ByteReader, strmgr: &mut StreamManager, seek_idx: &mut S let (tb_num, tb_den) = str.get_timebase(); let pts = counter[stream_no]; let time = NATimeInfo::ts_to_time(pts, 1000, tb_num, tb_den); - seek_idx.add_entry(stream_no as u32, SeekEntry { time, pts, pos: offset + movi_pos - 4 }); + validate!(offset >= movi_pos); + seek_idx.add_entry(stream_no as u32, SeekEntry { time, pts, pos: offset }); } key_offs.push(offset); }