X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-acorn%2Fsrc%2Fcodecs%2Fwss_packetisers.rs;fp=nihav-acorn%2Fsrc%2Fcodecs%2Fwss_packetisers.rs;h=6bdd1a95fffb849c7bed3f4cf647db47f56268b1;hb=e3af9911ad107a09e99c033a74f15c40581b8e26;hp=0000000000000000000000000000000000000000;hpb=495496ba02a782e17314b5c36be98de0ae4a7989;p=nihav.git diff --git a/nihav-acorn/src/codecs/wss_packetisers.rs b/nihav-acorn/src/codecs/wss_packetisers.rs new file mode 100644 index 0000000..6bdd1a9 --- /dev/null +++ b/nihav-acorn/src/codecs/wss_packetisers.rs @@ -0,0 +1,159 @@ +use nihav_core::codecs::*; +use nihav_core::io::byteio::*; + +struct Palette { + data: [u8; 1024], +} + +impl Default for Palette { + fn default() -> Self { + Self { data: [0; 1024] } + } +} + +impl Palette { + fn read_data(&mut self, src: &[u8]) { + for (dst, src) in self.data.chunks_exact_mut(4).zip(src.chunks_exact(4)) { + let clr = read_u32le(src).unwrap(); + let r = (clr & 0x1F) as u8; + dst[0] = (r << 3) | (r >> 2); + let g = ((clr >> 5) & 0x1F) as u8; + dst[1] = (g << 3) | (g >> 2); + let b = ((clr >> 10) & 0x1F) as u8; + dst[2] = (b << 3) | (b >> 2); + dst[3] = 0; + } + } + fn get_side_data(&self) -> NASideData { + NASideData::Palette(true, Arc::new(self.data)) + } +} + +#[derive(Default)] +struct WssPacketiser { + stream: Option, + buf: Vec, + csizes: Vec, + frameno: u32, + frame_size: usize, + palette: Palette, + pal_mode: bool, + has_pal: bool, +} + +impl WssPacketiser { + fn new() -> Self { Self::default() } + fn remove_payload(&mut self, size: usize) { + self.buf.drain(..size); + if !self.csizes.is_empty() { + if self.csizes[0] >= size { + self.csizes[0] -= size; + // skip possible padding at the end of chunk + if self.csizes[0] == 1 { + self.buf.remove(0); + self.csizes[0] -= 1; + } + if self.csizes[0] == 0 { + self.csizes.remove(0); + } + } else { + println!("ran past input chunk end!"); + self.csizes.clear(); + } + } + } +} + +impl NAPacketiser for WssPacketiser { + fn attach_stream(&mut self, stream: NAStreamRef) { + self.stream = Some(stream); + } + fn add_data(&mut self, src: &[u8]) -> bool { + self.csizes.push(src.len()); + self.buf.extend_from_slice(src); + self.buf.len() < (1 << 10) + } + fn parse_stream(&mut self, id: u32) -> DecoderResult { + if let Some(ref stream) = self.stream { + let mut stream = NAStream::clone(stream); + stream.id = id; + Ok(stream.into_ref()) + } else { + Err(DecoderError::MissingReference) + } + } + fn skip_junk(&mut self) -> DecoderResult { + Err(DecoderError::NotImplemented) + } + fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult> { + loop { + if self.buf.len() < 4 || self.buf.len() < self.frame_size { + return Ok(None); + } + + if self.frame_size == 0 { + self.frame_size = read_u32le(&self.buf)? as usize; + if self.frame_size == 0 { + self.remove_payload(4); + self.frameno += 1; + continue; + } + if self.frame_size == 0xFFFFFFFF { + self.pal_mode = true; + self.frame_size = 1024; + } + self.frame_size += 4; + validate!(self.frame_size > 16); + if self.buf.len() >= self.frame_size { + if self.pal_mode { + self.palette.read_data(&self.buf[4..][..1024]); + self.remove_payload(self.frame_size); + self.pal_mode = false; + self.has_pal = true; + self.frame_size = 0; + continue; + } + break; + } + } + } + + let mut data = Vec::with_capacity(self.frame_size); + data.extend_from_slice(&self.buf[16..self.frame_size]); + self.remove_payload(self.frame_size); + + let mut is_intra = false; + if let Some(ref stream) = self.stream { + #[allow(clippy::single_match)] + match stream.get_info().get_name() { + "cinepak" => is_intra = (data[0] & 1) == 0, + _ => {}, + }; + } + + let ts = NATimeInfo::new(Some(u64::from(self.frameno)), None, None, stream.tb_num, stream.tb_den); + self.frameno += 1; + self.frame_size = 0; + + let mut pkt = NAPacket::new(stream, ts, is_intra, data); + if self.has_pal { + pkt.add_side_data(self.palette.get_side_data()); + } + + Ok(Some(pkt)) + } + fn reset(&mut self) { + self.buf.clear(); + } + fn bytes_left(&self) -> usize { self.buf.len() } +} + +#[cfg(feature="packetiser_cinepak")] +pub fn get_packetiser_cinepak() -> Box { + Box::new(WssPacketiser::new()) +} + +#[cfg(feature="packetiser_msvideo1")] +pub fn get_packetiser_msvideo1() -> Box { + Box::new(WssPacketiser::new()) +}