X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-realmedia%2Fsrc%2Fdemuxers%2Frealmedia.rs;h=74581d934c93774385b144637e03009753d9e6b7;hp=b9eb9c741530636bacf58bc2f57366d89036e5c7;hb=a480a0de101483d802a11e72d758dae00fa4860a;hpb=33b5a8f0020ee3e6e0cc39ba9f6219965502df84 diff --git a/nihav-realmedia/src/demuxers/realmedia.rs b/nihav-realmedia/src/demuxers/realmedia.rs index b9eb9c7..74581d9 100644 --- a/nihav-realmedia/src/demuxers/realmedia.rs +++ b/nihav-realmedia/src/demuxers/realmedia.rs @@ -53,13 +53,15 @@ impl RMVideoStream { self.frame.resize(frame_size + self.hdr_size, 0); self.frame[0] = (num_slices - 1) as u8; self.frame_pos = 0; - self.add_slice(1, data); + self.add_slice(1, data).unwrap(); } - fn add_slice(&mut self, slice_no: usize, data: &[u8]) { + fn add_slice(&mut self, slice_no: usize, data: &[u8]) -> DemuxerResult<()> { + validate!(self.hdr_size + self.frame_pos + data.len() <= self.frame.len()); self.write_slice_info(slice_no); let dslice = &mut self.frame[self.hdr_size + self.frame_pos..][..data.len()]; dslice.copy_from_slice(data); self.frame_pos += data.len(); + Ok(()) } fn write_slice_info(&mut self, slice_no: usize) { let off = 1 + (slice_no - 1) * 8; @@ -224,7 +226,7 @@ impl RMAudioStream { self.sub_packet = 0; if self.deint == Deinterleaver::Sipro { - sipro_restore(&mut self.buf, factor, fsize); + sipro_restore(&mut self.buf, factor, iinfo.frame_size as usize); } let mut frames_iter = self.buf.chunks(fsize); @@ -349,6 +351,7 @@ impl CommonStreamData { struct RealMediaDemuxer<'a> { src: &'a mut ByteReader<'a>, data_pos: u64, + data_end: u64, next_data: u64, data_ver: u16, num_packets: u32, @@ -356,6 +359,9 @@ struct RealMediaDemuxer<'a> { str_data: CommonStreamData, + data_chunks: Vec<(u64, u32, u16)>, + cur_data_chunk: usize, + queued_pkts: Vec, slice_buf: Vec, } @@ -406,17 +412,17 @@ fn read_multiple_frame(src: &mut ByteReader, stream: NAStreamRef, keyframe: bool struct RMDemuxCommon {} impl RMDemuxCommon { - fn parse_stream_info(str_data: &mut CommonStreamData, strmgr: &mut StreamManager, stream_no: u32, edata: &Vec) -> DemuxerResult { + fn parse_stream_info(str_data: &mut CommonStreamData, strmgr: &mut StreamManager, stream_no: u32, edata: &[u8], duration: u32) -> DemuxerResult { let mut is_mlti = false; - let mut mr = MemoryReader::new_read(edata.as_slice()); + let mut mr = MemoryReader::new_read(edata); let mut src = ByteReader::new(&mut mr); let tag = src.read_u32be()?; let tag2 = src.peek_u32be()?; //println!("tag1 {:X} tag2 {:X}", tag, tag2); if tag == mktag!('.', 'r', 'a', 0xFD) { - Self::parse_audio_stream(strmgr, &mut str_data.streams, stream_no, &mut src, edata.as_slice())?; + Self::parse_audio_stream(strmgr, &mut str_data.streams, stream_no, &mut src, edata, duration)?; } else if ((tag2 == mktag!('V', 'I', 'D', 'O')) || (tag2 == mktag!('I', 'M', 'A', 'G'))) && ((tag as usize) <= edata.len()) { - Self::parse_video_stream(strmgr, &mut str_data.streams, stream_no, &mut src, edata.as_slice(), tag2)?; + Self::parse_video_stream(strmgr, &mut str_data.streams, stream_no, &mut src, edata, tag2, duration)?; } else if tag == mktag!(b"LSD:") { let extradata = Some(edata.to_owned()); @@ -429,7 +435,7 @@ impl RMDemuxCommon { let soniton = NASoniton::new(samp_size as u8, SONITON_FLAG_SIGNED); let ahdr = NAAudioInfo::new(sample_rate, channels as u8, soniton, 1); let nainfo = NACodecInfo::new("ralf", NACodecTypeInfo::Audio(ahdr), extradata); - let res = strmgr.add_stream(NAStream::new(StreamType::Audio, stream_no as u32, nainfo, 1, sample_rate)); + let res = strmgr.add_stream(NAStream::new(StreamType::Audio, stream_no as u32, nainfo, 1, 1000, u64::from(duration))); if res.is_none() { return Err(MemoryError); } let astr = RMAudioStream::new(None); str_data.streams.push(RMStreamType::Audio(astr)); @@ -461,9 +467,9 @@ impl RMDemuxCommon { let stream_no = str_data.mlti_mapper.get_substream_no(); //todo check that all substreams are of the same type"); if tag == mktag!('.', 'r', 'a', 0xFD) { - Self::parse_audio_stream(strmgr, &mut str_data.streams, stream_no, &mut hsrc, hdrsrc)?; + Self::parse_audio_stream(strmgr, &mut str_data.streams, stream_no, &mut hsrc, hdrsrc, duration)?; } else if (tag2 == mktag!('V', 'I', 'D', 'O')) && ((tag as usize) <= hdr_size) { - Self::parse_video_stream(strmgr, &mut str_data.streams, stream_no, &mut hsrc, hdrsrc, tag2)?; + Self::parse_video_stream(strmgr, &mut str_data.streams, stream_no, &mut hsrc, hdrsrc, tag2, duration)?; } else { println!("unknown MLTI substream {:08X} / {:08X}", tag, tag2); return Err(DemuxerError::InvalidData); @@ -476,7 +482,7 @@ println!("unknown MLTI substream {:08X} / {:08X}", tag, tag2); } Ok(is_mlti) } - fn parse_audio_stream(strmgr: &mut StreamManager, streams: &mut Vec, stream_no: u32, src: &mut ByteReader, edata_: &[u8]) -> DemuxerResult<()> { + fn parse_audio_stream(strmgr: &mut StreamManager, streams: &mut Vec, stream_no: u32, src: &mut ByteReader, edata_: &[u8], duration: u32) -> DemuxerResult<()> { let ver = src.read_u16be()?; let ainfo = match ver { 3 => { @@ -510,8 +516,9 @@ println!(" got ainfo {:?}", ainfo); let eslice = &edata_[(src.tell() as usize)..]; Some(eslice.to_vec()) }; + let duration = if duration == 0 { ainfo.get_duration(1000) } else { u64::from(duration) }; let nainfo = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), extradata); - let res = strmgr.add_stream(NAStream::new(StreamType::Audio, stream_no as u32, nainfo, 1, srate)); + let res = strmgr.add_stream(NAStream::new(StreamType::Audio, stream_no as u32, nainfo, 1, 1000, duration)); if res.is_none() { return Err(MemoryError); } let astr = RMAudioStream::new(ainfo.ileave_info); @@ -519,7 +526,7 @@ println!(" got ainfo {:?}", ainfo); Ok(()) } #[allow(unused_variables)] - fn parse_video_stream(strmgr: &mut StreamManager, streams: &mut Vec, stream_no: u32, src: &mut ByteReader, edata_: &[u8], tag2: u32) -> DemuxerResult<()> { + fn parse_video_stream(strmgr: &mut StreamManager, streams: &mut Vec, stream_no: u32, src: &mut ByteReader, edata_: &[u8], tag2: u32, duration: u32) -> DemuxerResult<()> { src.read_skip(4)?; let fcc = src.read_u32be()?; let width = src.read_u16be()? as usize; @@ -527,11 +534,11 @@ println!(" got ainfo {:?}", ainfo); let bpp = src.read_u16be()?; let pad_w = src.read_u16be()?; let pad_h = src.read_u16be()?; - let fps; + let _fps; if tag2 == mktag!('V', 'I', 'D', 'O') { - fps = src.read_u32be()?; + _fps = src.read_u32be()?; } else { - fps = 0x10000; + _fps = 0x10000; } let extradata: Option>; if src.left() > 0 { @@ -544,7 +551,7 @@ println!(" got ainfo {:?}", ainfo); let vhdr = NAVideoInfo::new(width, height, false, RGB24_FORMAT); let vinfo = NACodecInfo::new(cname, NACodecTypeInfo::Video(vhdr), extradata); - let res = strmgr.add_stream(NAStream::new(StreamType::Video, stream_no as u32, vinfo, 0x10000, fps)); + let res = strmgr.add_stream(NAStream::new(StreamType::Video, stream_no as u32, vinfo, 1, 1000, u64::from(duration))); if res.is_none() { return Err(DemuxerError::MemoryError); } let vstr = RMVideoStream::new(); @@ -576,7 +583,7 @@ println!(" got ainfo {:?}", ainfo); if packet_num == 1 { vstr.start_slice(num_pkts, frame_size as usize, slice_buf.as_slice()); } else { - vstr.add_slice(packet_num as usize, slice_buf.as_slice()); + vstr.add_slice(packet_num as usize, slice_buf.as_slice())?; } if (packet_num as usize) < num_pkts { return Err(DemuxerError::TryAgain); @@ -606,7 +613,7 @@ println!(" got ainfo {:?}", ainfo); if packet_num == 1 && frame_size == tail_size { vstr.start_slice(num_pkts, frame_size as usize, slice_buf.as_slice()); } else { - vstr.add_slice(packet_num as usize, slice_buf.as_slice()); + vstr.add_slice(packet_num as usize, slice_buf.as_slice())?; } while src.tell() < pos + (payload_size as u64) { @@ -646,9 +653,8 @@ println!(" got ainfo {:?}", ainfo); } impl<'a> DemuxCore<'a> for RealMediaDemuxer<'a> { - #[allow(unused_variables)] - fn open(&mut self, strmgr: &mut StreamManager, _seek_idx: &mut SeekIndex) -> DemuxerResult<()> { - self.read_header(strmgr)?; + fn open(&mut self, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex) -> DemuxerResult<()> { + self.read_header(strmgr, seek_idx)?; Ok(()) } @@ -659,12 +665,16 @@ impl<'a> DemuxCore<'a> for RealMediaDemuxer<'a> { return Ok(pkt); } loop { - if self.cur_packet >= self.num_packets { - if (self.next_data != 0) && (self.next_data == self.src.tell()) { + if (self.cur_packet >= self.num_packets) || (self.src.tell() >= self.data_end) { + self.cur_data_chunk += 1; + if self.cur_data_chunk < self.data_chunks.len() { + let (pos, _, _) = self.data_chunks[self.cur_data_chunk]; + self.src.seek(SeekFrom::Start(pos))?; let res = read_chunk(self.src); if let Ok((id, size, ver)) = res { self.data_pos = self.src.tell(); self.data_ver = ver; + self.data_end = self.data_pos + (size as u64); if self.parse_data_start().is_ok() { continue; } @@ -731,9 +741,36 @@ impl<'a> DemuxCore<'a> for RealMediaDemuxer<'a> { } #[allow(unused_variables)] - fn seek(&mut self, time: u64, seek_idx: &SeekIndex) -> DemuxerResult<()> { - Err(NotImplemented) + fn seek(&mut self, time: NATimePoint, seek_idx: &SeekIndex) -> DemuxerResult<()> { + self.queued_pkts.clear(); + let ret = seek_idx.find_pos(time); + if ret.is_none() { + return Err(DemuxerError::SeekError); + } + let ret = ret.unwrap(); + let seek_pos = ret.pos; + for (pos, size, ver) in self.data_chunks.iter() { + if seek_pos < *pos { continue; } + let end = *pos + (*size as u64); + if seek_pos < end { + self.cur_packet = 0; + self.data_pos = seek_pos; + self.data_ver = *ver; + self.data_end = end; + self.src.seek(SeekFrom::Start(seek_pos))?; + return Ok(()); + } + } + Err(DemuxerError::SeekError) } + + fn get_duration(&self) -> u64 { 0 } +} + +impl<'a> NAOptionHandler for RealMediaDemuxer<'a> { + fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } + fn set_options(&mut self, _options: &[NAOption]) { } + fn query_option_value(&self, _name: &str) -> Option { None } } fn read_chunk(src: &mut ByteReader) -> DemuxerResult<(u32, u32, u16)> { @@ -774,6 +811,16 @@ struct RealAudioInfo { ileave_info: Option } +impl RealAudioInfo { + fn get_duration(&self, base: u32) -> u64 { + if self.bytes_per_minute != 0 { + u64::from(self.total_bytes) * 60 * u64::from(base) / u64::from(self.bytes_per_minute) + } else { + 0 + } + } +} + fn skip_ra_metadata(src: &mut ByteReader) -> DemuxerResult<()> { let title_len = src.read_byte()? as usize; src.read_skip(title_len)?; @@ -939,17 +986,20 @@ impl<'a> RealMediaDemuxer<'a> { RealMediaDemuxer { src: io, data_pos: 0, + data_end: 0, next_data: 0, data_ver: 0, num_packets: 0, cur_packet: 0, str_data: CommonStreamData::new(), + data_chunks: Vec::new(), + cur_data_chunk: 0, queued_pkts: Vec::new(), slice_buf: Vec::new(), } } #[allow(unused_variables)] - fn read_header(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> { + fn read_header(&mut self, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex) -> DemuxerResult<()> { let (id, size, ver) = read_chunk(self.src)?; validate!((id == mktag!(b".RMF")) || (id == mktag!(b".RMP"))); validate!(size >= RMVB_HDR_SIZE); @@ -988,20 +1038,25 @@ impl<'a> RealMediaDemuxer<'a> { //warn maybe? break; } - let res = self.parse_chunk(strmgr); + let res = self.parse_chunk(strmgr, seek_idx); match res { Ok(last) => { if last { break; } }, Err(DemuxerError::IOError) => { break; }, Err(etype) => { - if self.data_pos == 0 { // data is not found, report error + if self.data_chunks.is_empty() { // data is not found, report error return Err(etype); } }, }; } //println!("now @ {:X} / {}", self.src.tell(), self.data_pos); - validate!(self.data_pos > 0); - self.src.seek(SeekFrom::Start(self.data_pos))?; + validate!(!self.data_chunks.is_empty()); + self.cur_data_chunk = 0; + let (pos, size, ver) = self.data_chunks[self.cur_data_chunk]; + self.data_pos = pos; + self.data_ver = ver; + self.data_end = pos + (size as u64); + self.src.seek(SeekFrom::Start(self.data_pos + 10))?; self.parse_data_start()?; Ok(()) } @@ -1016,15 +1071,21 @@ impl<'a> RealMediaDemuxer<'a> { self.next_data = next_data_hdr as u64; Ok(()) } - fn parse_chunk(&mut self, strmgr: &mut StreamManager) -> DemuxerResult { + fn parse_chunk(&mut self, strmgr: &mut StreamManager, seek_idx: &mut SeekIndex) -> DemuxerResult { let (id, size, ver) = read_chunk(self.src)?; let end_pos = self.src.tell() - 10 + (size as u64); validate!((ver == 0) || (ver == 2)); if id == mktag!(b"CONT") { self.parse_content_desc()?; } else if id == mktag!(b"MDPR") { self.parse_mdpr(strmgr)?; } - else if id == mktag!(b"DATA") { if self.data_pos == 0 { self.data_ver = ver; self.data_pos = self.src.tell(); } } - else if id == mktag!(b"INDX") { /* do nothing for now */ } + else if id == mktag!(b"DATA") { + self.data_chunks.push((self.src.tell() - 10, size, ver)); + } + else if id == mktag!(b"INDX") { + if !seek_idx.skip_index { + self.parse_index(seek_idx, (size as usize) - 10, ver)?; + } + } else if id == 0 { return Ok(true); } else { println!("unknown chunk type {:08X}", id); } @@ -1072,7 +1133,7 @@ impl<'a> RealMediaDemuxer<'a> { let mut is_mlti = false; if edata_size > 8 { if let Some(edata_) = edata { - is_mlti = RMDemuxCommon::parse_stream_info(&mut self.str_data, strmgr, stream_no, &edata_)?; + is_mlti = RMDemuxCommon::parse_stream_info(&mut self.str_data, strmgr, stream_no, &edata_, duration)?; } } else { self.str_data.streams.push(RMStreamType::Unknown); @@ -1083,6 +1144,38 @@ impl<'a> RealMediaDemuxer<'a> { Ok(()) } + fn parse_index(&mut self, seek_idx: &mut SeekIndex, chunk_size: usize, ver: u16) -> DemuxerResult<()> { + if ver != 0 && ver != 2 { return Ok(()); } + let num_entries = self.src.read_u32be()? as usize; + let str_id = self.src.read_u16be()? as u32; + let _next_idx = self.src.read_u32be()?; + if ver == 2 { + self.src.read_u32be()?; + } + if ver == 0 { + validate!(chunk_size == num_entries * 14 + 10); + } else { + validate!(chunk_size == num_entries * 18 + 14); + } + if num_entries == 0 { return Ok(()); } + + seek_idx.add_stream(str_id); + let idx = seek_idx.get_stream_index(str_id).unwrap(); + for _ in 0..num_entries { + let iver = self.src.read_u16be()?; + validate!(iver == ver); + let ts = self.src.read_u32be()? as u64; + if ver == 2 { + self.src.read_u32be()?; + } + let pos = self.src.read_u32be()? as u64; + let _pkt_no = self.src.read_u32be()?; + idx.add_entry(SeekEntry { time: ts, pts: 0, pos }); + } + idx.filled = true; + seek_idx.mode = SeekIndexMode::Present; + Ok(()) + } } fn read_string_size(src: &mut ByteReader, size: usize) -> DemuxerResult { @@ -1148,7 +1241,7 @@ println!(" got ainfo {:?}", ainfo); Some(dta) }; let nainfo = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), extradata); - let res = strmgr.add_stream(NAStream::new(StreamType::Audio, 0, nainfo, 1, srate)); + let res = strmgr.add_stream(NAStream::new(StreamType::Audio, 0, nainfo, 1, srate, ainfo.get_duration(ainfo.sample_rate))); if res.is_none() { return Err(MemoryError); } let astr = RMAudioStream::new(ainfo.ileave_info); @@ -1183,9 +1276,17 @@ println!(" got ainfo {:?}", ainfo); } #[allow(unused_variables)] - fn seek(&mut self, time: u64, seek_idx: &SeekIndex) -> DemuxerResult<()> { + fn seek(&mut self, time: NATimePoint, seek_idx: &SeekIndex) -> DemuxerResult<()> { Err(NotImplemented) } + + fn get_duration(&self) -> u64 { 0 } +} + +impl<'a> NAOptionHandler for RealAudioDemuxer<'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> RealAudioDemuxer<'a> { @@ -1334,6 +1435,7 @@ impl RecordDemuxer { cur_str_no += 1; let mut parsed = false; let mut real_stream_no = 0; + let mut duration = 0; for _ in 0..num { let rec = IVRRecord::read(src)?; //println!(" strm property {}", rec); @@ -1342,11 +1444,14 @@ impl RecordDemuxer { if name == b"StreamNumber\0" { real_stream_no = val; } + if name == b"Duration\0" { + duration = val; + } }, IVRRecord::BinaryData(ref name, ref val) => { if name == b"OpaqueData\0" { validate!(!parsed); - let is_mlti = RMDemuxCommon::parse_stream_info(str_data, strmgr, stream_no, val)?; + let is_mlti = RMDemuxCommon::parse_stream_info(str_data, strmgr, stream_no, val, duration)?; if !is_mlti { str_data.str_ids.push(stream_no); } @@ -1522,9 +1627,17 @@ println!("R1M kind"); } #[allow(unused_variables)] - fn seek(&mut self, time: u64, seek_idx: &SeekIndex) -> DemuxerResult<()> { + fn seek(&mut self, time: NATimePoint, seek_idx: &SeekIndex) -> DemuxerResult<()> { Err(NotImplemented) } + + fn get_duration(&self) -> u64 { 0 } +} + +impl<'a> NAOptionHandler for RealIVRDemuxer<'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> RealIVRDemuxer<'a> { @@ -1612,7 +1725,8 @@ mod test { let mut br = ByteReader::new(&mut fr); let mut dmx = RealMediaDemuxer::new(&mut br); let mut sm = StreamManager::new(); - dmx.open(&mut sm).unwrap(); + let mut si = SeekIndex::new(); + dmx.open(&mut sm, &mut si).unwrap(); loop { let pktres = dmx.get_frame(&mut sm); @@ -1634,7 +1748,8 @@ mod test { let mut br = ByteReader::new(&mut fr); let mut dmx = RealAudioDemuxer::new(&mut br); let mut sm = StreamManager::new(); - dmx.open(&mut sm).unwrap(); + let mut si = SeekIndex::new(); + dmx.open(&mut sm, &mut si).unwrap(); loop { let pktres = dmx.get_frame(&mut sm); @@ -1655,7 +1770,8 @@ mod test { let mut br = ByteReader::new(&mut fr); let mut dmx = RealIVRDemuxer::new(&mut br); let mut sm = StreamManager::new(); - dmx.open(&mut sm).unwrap(); + let mut si = SeekIndex::new(); + dmx.open(&mut sm, &mut si).unwrap(); loop { let pktres = dmx.get_frame(&mut sm);