From: Kostya Shishkov Date: Tue, 7 May 2024 16:12:27 +0000 (+0200) Subject: add some packetisers for WSS formats in ARMovie X-Git-Url: https://git.nihav.org/?a=commitdiff_plain;h=e3af9911ad107a09e99c033a74f15c40581b8e26;p=nihav.git add some packetisers for WSS formats in ARMovie --- diff --git a/nihav-acorn/Cargo.toml b/nihav-acorn/Cargo.toml index 3266be9..0372971 100644 --- a/nihav-acorn/Cargo.toml +++ b/nihav-acorn/Cargo.toml @@ -11,7 +11,7 @@ path = "../nihav-core" path = "../nihav-codec-support" [features] -default = ["all_decoders", "all_demuxers"] +default = ["all_decoders", "all_demuxers", "all_packetisers"] all_decoders = ["all_video_decoders", "all_audio_decoders"] all_video_decoders = ["decoder_movinglines", "decoder_movingblocks", "decoder_movingblockshq", "decoder_linepack", "decoder_rawvideo"] @@ -29,4 +29,10 @@ decoder_rawaudio = ["decoders"] all_demuxers = ["demuxer_armovie"] demuxers = [] -demuxer_armovie = ["demuxers"] \ No newline at end of file +demuxer_armovie = ["demuxers"] + +all_packetisers = ["packetiser_cinepak", "packetiser_msvideo1"] +packetisers = [] + +packetiser_cinepak = ["packetisers"] +packetiser_msvideo1 = ["packetisers"] \ No newline at end of file diff --git a/nihav-acorn/src/codecs/mod.rs b/nihav-acorn/src/codecs/mod.rs index 28ce17f..232e162 100644 --- a/nihav-acorn/src/codecs/mod.rs +++ b/nihav-acorn/src/codecs/mod.rs @@ -60,6 +60,9 @@ pub fn acorn_register_all_decoders(rd: &mut RegisteredDecoders) { } } +#[cfg(any(feature="packetiser_cinepak", feature="packetiser_msvideo1"))] +mod wss_packetisers; + const ACORN_PACKETISERS: &[PacketiserInfo] = &[ #[cfg(feature="decoder_rawvideo")] PacketiserInfo { name: "arm_rawvideo", get_packetiser: rawvideo::get_packetiser }, @@ -75,6 +78,11 @@ const ACORN_PACKETISERS: &[PacketiserInfo] = &[ #[cfg(feature="decoder_rawaudio")] PacketiserInfo { name: "arm_rawaudio", get_packetiser: rawaudio::get_packetiser }, + +#[cfg(feature="packetiser_cinepak")] + PacketiserInfo { name: "cinepak", get_packetiser: wss_packetisers::get_packetiser_cinepak }, +#[cfg(feature="packetiser_msvideo1")] + PacketiserInfo { name: "msvideo1", get_packetiser: wss_packetisers::get_packetiser_msvideo1 }, ]; /// Registers all available packetisers provided by this crate. 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()) +} diff --git a/nihav-acorn/src/demuxers/armovie.rs b/nihav-acorn/src/demuxers/armovie.rs index 95c8dad..4b2b3f6 100644 --- a/nihav-acorn/src/demuxers/armovie.rs +++ b/nihav-acorn/src/demuxers/armovie.rs @@ -13,6 +13,9 @@ const VIDEO_CODECS: &[(i32, &str)] = &[ (122, "escape122"), (124, "escape124"), (130, "escape130"), + (600, "msvideo1"), + (601, "msvideo1"), + (602, "cinepak"), (800, "linepack"), (802, "movie16_3"), ]; @@ -278,7 +281,13 @@ impl<'a> RawDemuxCore<'a> for ARMovieDemuxer<'a> { let mut edata = vec![video_codec as u8, (video_codec >> 8) as u8]; edata.extend_from_slice(&vformat); - let vci = NACodecTypeInfo::Video(NAVideoInfo::new(width, height, false, YUV420_FORMAT)); + let fmt = match video_codec { + 600 => PAL8_FORMAT, + 601 => RGB565_FORMAT, + _ => YUV420_FORMAT, + }; + + let vci = NACodecTypeInfo::Video(NAVideoInfo::new(width, height, false, fmt)); let vinfo = NACodecInfo::new(codec_name, vci, Some(edata)); let ret = strmgr.add_stream(NAStream::new(StreamType::Video, stream_id, vinfo, tb_num, tb_den, (frm_per_chunk * num_chunks) as u64)); if ret.is_some() {