add some packetisers for WSS formats in ARMovie
authorKostya Shishkov <kostya.shishkov@gmail.com>
Tue, 7 May 2024 16:12:27 +0000 (18:12 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Tue, 7 May 2024 16:12:27 +0000 (18:12 +0200)
nihav-acorn/Cargo.toml
nihav-acorn/src/codecs/mod.rs
nihav-acorn/src/codecs/wss_packetisers.rs [new file with mode: 0644]
nihav-acorn/src/demuxers/armovie.rs

index 3266be9e7c42d29c605da41a2d3df733fbf9062a..03729717b403faed9bb544370aaebff40e66d8c7 100644 (file)
@@ -11,7 +11,7 @@ path = "../nihav-core"
 path = "../nihav-codec-support"
 
 [features]
 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"]
 
 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 = []
 
 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
index 28ce17fdc0e2bddc72255f543834bc920a337172..232e162ed13c614268882abe8fa89bec7d93625f 100644 (file)
@@ -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 },
 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="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.
 ];
 
 /// 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 (file)
index 0000000..6bdd1a9
--- /dev/null
@@ -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<NAStreamRef>,
+    buf:        Vec<u8>,
+    csizes:     Vec<usize>,
+    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<NAStreamRef> {
+        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<usize> {
+        Err(DecoderError::NotImplemented)
+    }
+    fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> {
+        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<dyn NAPacketiser + Send> {
+    Box::new(WssPacketiser::new())
+}
+
+#[cfg(feature="packetiser_msvideo1")]
+pub fn get_packetiser_msvideo1() -> Box<dyn NAPacketiser + Send> {
+    Box::new(WssPacketiser::new())
+}
index 95c8dad8aa66ff98b18f08d1ef38289a1cd9960b..4b2b3f6c53a3295557eee3e749204351eb9880d2 100644 (file)
@@ -13,6 +13,9 @@ const VIDEO_CODECS: &[(i32, &str)] = &[
     (122, "escape122"),
     (124, "escape124"),
     (130, "escape130"),
     (122, "escape122"),
     (124, "escape124"),
     (130, "escape130"),
+    (600, "msvideo1"),
+    (601, "msvideo1"),
+    (602, "cinepak"),
     (800, "linepack"),
     (802, "movie16_3"),
 ];
     (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 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() {
             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() {