Flash support
[nihav.git] / nihav-flash / src / codecs / flashsv.rs
diff --git a/nihav-flash/src/codecs/flashsv.rs b/nihav-flash/src/codecs/flashsv.rs
new file mode 100644 (file)
index 0000000..26e0eb4
--- /dev/null
@@ -0,0 +1,423 @@
+use nihav_core::frame::*;
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::compr::deflate::*;
+
+#[derive(Default)]
+struct FSVShuffler {
+    lastframe: Option<NAVideoBufferRef<u8>>,
+    keyframe:  Option<NAVideoBufferRef<u8>>,
+}
+
+#[allow(dead_code)]
+impl FSVShuffler {
+    fn new() -> Self { Self::default() }
+    fn clear(&mut self) {
+        self.keyframe  = None;
+        self.lastframe = None;
+    }
+    fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
+        self.lastframe = Some(buf);
+    }
+    fn add_keyframe(&mut self, buf: NAVideoBufferRef<u8>) {
+        self.keyframe = Some(buf);
+    }
+    fn clone_ref(&mut self) -> Option<NAVideoBufferRef<u8>> {
+        if let Some(ref mut frm) = self.lastframe {
+            let newfrm = frm.copy_buffer();
+            *frm = newfrm.clone().into_ref();
+            Some(newfrm.into_ref())
+        } else {
+            None
+        }
+    }
+    fn has_last_frame(&self) -> bool { self.lastframe.is_some() }
+    fn get_key_frame(&mut self) -> Option<NAVideoBufferRef<u8>> {
+        match self.keyframe {
+            Some(ref frm) => Some(frm.clone()),
+            None => None,
+        }
+    }
+    fn get_last_frame(&mut self) -> Option<NAVideoBufferRef<u8>> {
+        match self.lastframe {
+            Some(ref frm) => Some(frm.clone()),
+            None => None,
+        }
+    }
+}
+
+
+struct FSVDecoder {
+    info:       NACodecInfoRef,
+    shuf:       FSVShuffler,
+    w:          usize,
+    h:          usize,
+    block_w:    usize,
+    block_h:    usize,
+    ver1:       bool,
+    has_pal:    bool,
+    has_ifrm:   bool,
+    tile:       Vec<u8>,
+    cbuf:       [u8; 65536],
+    pal:        [u8; 128 * 3],
+    inflate:    Inflate,
+    kdata:      Vec<u8>,
+    bpos:       Vec<usize>,
+    bsize:      Vec<usize>,
+}
+
+impl FSVDecoder {
+    fn new(ver1: bool) -> Self {
+        Self {
+            info:       NACodecInfo::new_dummy(),
+            shuf:       FSVShuffler::new(),
+            w:          0,
+            h:          0,
+            block_w:    0,
+            block_h:    0,
+            ver1,
+            has_pal:    false,
+            has_ifrm:   false,
+            tile:       Vec::new(),
+            cbuf:       [0; 65536],
+            pal:        DEFAULT_PAL,
+            inflate:    Inflate::new(),
+            kdata:      Vec::new(),
+            bpos:       Vec::new(),
+            bsize:      Vec::new(),
+        }
+    }
+    fn decode_v1(&mut self, br: &mut ByteReader, data: &mut [u8], stride: usize) -> DecoderResult<bool> {
+        let mut is_intra = true;
+        for (yy, row) in data.chunks_mut(stride * self.block_h).enumerate() {
+            let cur_h = (self.h - yy * self.block_h).min(self.block_h);
+            for x in (0..self.w).step_by(self.block_w) {
+                let cur_w = (self.w - x).min(self.block_w);
+
+                let data_size           = br.read_u16be()? as usize;
+                if data_size > 0 {
+                                          br.read_buf(&mut self.cbuf[..data_size])?;
+                    self.inflate = Inflate::new();
+                    if self.inflate.decompress_block(&self.cbuf[..data_size], &mut self.tile[..cur_w * cur_h * 3]).is_err() {
+                        return Err(DecoderError::InvalidData);
+                    }
+                    for (dst, src) in row[x * 3..].chunks_mut(stride).zip(self.tile.chunks(cur_w * 3)) {
+                        dst[..cur_w * 3].copy_from_slice(src);
+                    }
+                } else {
+                    is_intra = false;
+                }
+            }
+        }
+        Ok(is_intra)
+    }
+    fn decode_v2(&mut self, br: &mut ByteReader, data: &mut [u8], stride: usize, keyframe: bool) -> DecoderResult<bool> {
+        let mut is_intra = !self.has_ifrm;
+        let bstride = (self.w + self.block_w - 1) / self.block_w;
+        for y in (0..self.h).step_by(self.block_h) {
+            let cur_h = (self.h - y).min(self.block_h);
+            for x in (0..self.w).step_by(self.block_w) {
+                let cur_w = (self.w - x).min(self.block_w);
+
+                let mut data_size       = br.read_u16be()? as usize;
+                validate!(!keyframe || data_size > 0);
+                if data_size == 0 {
+                    is_intra = false;
+                    continue;
+                }
+                let blk_start = br.tell();
+                let flags               = br.read_byte()?;
+                let depth = (flags >> 3) & 3;
+                validate!(depth == 0 || depth == 2);
+                let has_diff = (flags & 4) != 0;
+                let cpriming = (flags & 2) != 0;
+                let ppriming = (flags & 1) != 0;
+                let (start, height) = if has_diff {
+                        let start       = br.read_byte()? as usize;
+                        let height      = br.read_byte()? as usize;
+                        validate!(start + height <= cur_h);
+                        (start, height)
+                    } else {
+                        (0, cur_h)
+                    };
+                if has_diff {
+                    let ret = self.shuf.get_key_frame();
+                    if ret.is_none() {
+                        return Err(DecoderError::MissingReference);
+                    }
+                    let src = ret.unwrap();
+                    let src = src.get_data();
+                    for (dst, src) in data[x * 3 + y * stride..].chunks_mut(stride).take(cur_h).zip(src[x * 3 + y * stride..].chunks(stride)) {
+                        dst[..cur_w * 3].copy_from_slice(&src[..cur_w * 3]);
+                    }
+                }
+                if height != cur_h {
+                    is_intra = false;
+                }
+                let ppos = if cpriming {
+                        let xpos        = br.read_byte()? as usize;
+                        let ypos        = br.read_byte()? as usize;
+                        xpos + ypos * bstride
+                    } else {
+                        x / self.block_w + y / self.block_h * bstride
+                    };
+                data_size -= (br.tell() - blk_start) as usize;
+                if keyframe {
+                    self.bpos.push(br.tell() as usize);
+                    self.bsize.push(data_size);
+                }
+                if data_size > 0 {
+                                          br.read_buf(&mut self.cbuf[..data_size])?;
+                    self.inflate = Inflate::new();
+                    if cpriming || ppriming {
+                        if self.bpos.is_empty() {
+                            return Err(DecoderError::MissingReference);
+                        }
+                        let ret = self.inflate.decompress_block(&self.kdata[self.bpos[ppos]..][..self.bsize[ppos]], &mut self.tile);
+                        if ret.is_err() {
+                            return Err(DecoderError::InvalidData);
+                        }
+                        let ssize = ret.unwrap();
+                        self.inflate = Inflate::new();
+                        self.inflate.set_dict(&self.tile[..ssize]);
+                    }
+                    let ret = self.inflate.decompress_block(&self.cbuf[..data_size], &mut self.tile[..cur_w * height * 3]);
+                    if ret.is_err() {
+                        return Err(DecoderError::InvalidData);
+                    }
+                    let src_len = ret.unwrap();
+
+                    let dst = &mut data[x * 3 + y * stride..];
+                    match depth {
+                        0 => {
+                            validate!(src_len == cur_w * cur_h * 3);
+                            for (dst, src) in dst.chunks_mut(stride).skip(start).take(height).zip(self.tile.chunks(cur_w * 3)) {
+                                dst[..cur_w * 3].copy_from_slice(src);
+                            }
+                        },
+                        2 => {
+                            let mut mr = MemoryReader::new_read(&self.tile[..src_len]);
+                            let mut br = ByteReader::new(&mut mr);
+                            for line in dst.chunks_mut(stride).skip(start).take(height) {
+                                for rgb in line.chunks_mut(3).take(cur_w) {
+                                    let b           = br.read_byte()?;
+                                    if (b & 0x80) == 0 {
+                                        rgb.copy_from_slice(&self.pal[(b as usize) * 3..][..3]);
+                                    } else {
+                                        let c       = br.read_byte()?;
+                                        let clr = (u16::from(b & 0x7F) << 8) | u16::from(c);
+                                        let r = (clr >> 10) as u8;
+                                        let g = ((clr >> 5) & 0x1F) as u8;
+                                        let b = (clr & 0x1F) as u8;
+                                        rgb[0] = (r << 3) | (r >> 2);
+                                        rgb[1] = (g << 3) | (g >> 2);
+                                        rgb[2] = (b << 3) | (b >> 2);
+                                    }
+                                }
+                            }
+                        },
+                        _ => unreachable!(),
+                    };
+                } else {
+                    is_intra = false;
+                }
+            }
+        }
+        if self.has_ifrm {
+unimplemented!();
+        }
+        Ok(is_intra)
+    }
+}
+
+impl NADecoder for FSVDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            let w = vinfo.get_width();
+            let h = vinfo.get_height();
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, true, RGB24_FORMAT));
+            self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+
+        validate!(src.len() > 4);
+        let mut mr = MemoryReader::new_read(&src);
+        let mut br = ByteReader::new(&mut mr);
+
+        let hdr0                        = br.read_u16be()? as usize;
+        let hdr1                        = br.read_u16be()? as usize;
+        let w = hdr0 & 0xFFF;
+        let h = hdr1 & 0xFFF;
+        let blk_w = (hdr0 >> 12) * 16 + 16;
+        let blk_h = (hdr1 >> 12) * 16 + 16;
+        validate!(w != 0 && h != 0 && blk_w != 0 && blk_h != 0);
+
+        if !self.ver1 {
+            let flags                   = br.read_byte()?;
+            self.has_pal  = (flags & 1) != 0;
+            self.has_ifrm = (flags & 2) != 0;
+            if self.has_pal {
+                let pal_sz              = br.read_u16be()? as usize;
+                                          br.read_buf(&mut self.cbuf[..pal_sz])?;
+                self.inflate = Inflate::new();
+                if self.inflate.decompress_block(&self.cbuf[..pal_sz], &mut self.pal).is_err() {
+                    return Err(DecoderError::InvalidData);
+                }
+            }
+            if pkt.keyframe {
+                self.kdata.clear();
+                self.kdata.extend_from_slice(&src);
+                self.bpos.clear();
+                self.bsize.clear();
+            }
+        }
+        if self.w != w || self.h != h || self.block_w != blk_w || self.block_h != blk_h {
+            self.flush();
+            self.tile.resize(blk_w * blk_h * 3, 0);
+            self.w = w;
+            self.h = h;
+            self.block_w = blk_w;
+            self.block_h = blk_h;
+        }
+
+        let mut buf = if let Some(buffer) = self.shuf.clone_ref() {
+                buffer
+            } else {
+                let vinfo = self.info.get_properties().get_video_info().unwrap();
+                let bufinfo = alloc_video_buffer(vinfo, 0)?;
+                bufinfo.get_vbuf().unwrap()
+            };
+        let stride = buf.get_stride(0);
+        let data = buf.get_data_mut().unwrap();
+        let is_intra = if self.ver1 {
+                self.decode_v1(&mut br, data, stride)?
+            } else {
+                self.decode_v2(&mut br, data, stride, pkt.keyframe)?
+            };
+
+        if !is_intra && !self.shuf.has_last_frame() {
+            return Err(DecoderError::MissingReference);
+        }
+
+        if pkt.is_keyframe() {
+            self.shuf.add_keyframe(buf.clone());
+        }
+        self.shuf.add_frame(buf.clone());
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::VideoPacked(buf));
+        frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
+        Ok(frm.into_ref())
+    }
+    fn flush(&mut self) {
+        self.shuf.clear();
+    }
+}
+
+impl NAOptionHandler for FSVDecoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+    Box::new(FSVDecoder::new(true))
+}
+
+pub fn get_decoder_v2() -> Box<dyn NADecoder + Send> {
+    Box::new(FSVDecoder::new(false))
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::flash_register_all_decoders;
+    use crate::flash_register_all_demuxers;
+    #[test]
+    fn test_flashsv1() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        flash_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        flash_register_all_decoders(&mut dec_reg);
+
+        test_decoding("flv", "flashsv", "assets/Flash/screen.flv",
+                      Some(3000), &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
+                            [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
+                            [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
+                            [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
+                            [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
+                            [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
+                            [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
+                            [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
+                            [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
+                            [0xc04d4d1c, 0xbb1f4b4f, 0xe9f3d85e, 0xa40aff68],
+                            [0x172e5bbe, 0xe44caba3, 0x6cb2a263, 0xcb79a89a]]));
+    }
+    #[test]
+    fn test_flashsv2() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        flash_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        flash_register_all_decoders(&mut dec_reg);
+
+        test_decoding("flv", "flashsv2", "assets/Flash/screen2.flv",
+                      Some(4700), &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
+                            [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
+                            [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
+                            [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
+                            [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
+                            [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
+                            [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
+                            [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
+                            [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
+                            [0x9809efc2, 0xec5385aa, 0xb5eb9320, 0x4a47188e],
+                            [0x40c77877, 0x58183722, 0x5700eb17, 0x27a00e33],
+                            [0x802c2c6a, 0x3e08dd62, 0xa6c94df3, 0xc6318a6f],
+                            [0x2aa70255, 0x652f0ca4, 0xe79817f9, 0x4f67e7ba],
+                            [0x5cf34d91, 0xdfc54992, 0x4368180d, 0xfbe747d4],
+                            [0x266d8bc4, 0x2b492ef4, 0xb42401a0, 0x23e530ec],
+                            [0xa0e46b1c, 0x47d0620e, 0x0cbcb15b, 0x243e7f13]]));
+    }
+}
+
+const DEFAULT_PAL: [u8; 128 * 3] = [
+     0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x99, 0x99, 0x99,
+    0xCC, 0xCC, 0xCC, 0xFF, 0xFF, 0xFF, 0x33, 0x00, 0x00, 0x66, 0x00, 0x00,
+    0x99, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x33, 0x00,
+    0x00, 0x66, 0x00, 0x00, 0x99, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xFF, 0x00,
+    0x00, 0x00, 0x33, 0x00, 0x00, 0x66, 0x00, 0x00, 0x99, 0x00, 0x00, 0xCC,
+    0x00, 0x00, 0xFF, 0x33, 0x33, 0x00, 0x66, 0x66, 0x00, 0x99, 0x99, 0x00,
+    0xCC, 0xCC, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x33, 0x33, 0x00, 0x66, 0x66,
+    0x00, 0x99, 0x99, 0x00, 0xCC, 0xCC, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x33,
+    0x66, 0x00, 0x66, 0x99, 0x00, 0x99, 0xCC, 0x00, 0xCC, 0xFF, 0x00, 0xFF,
+    0xFF, 0xFF, 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC,
+    0xFF, 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC, 0xFF,
+    0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC, 0xFF, 0xFF,
+    0xCC, 0xCC, 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF,
+    0xCC, 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF, 0xCC,
+    0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF, 0xCC, 0xCC,
+    0x99, 0x99, 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF,
+    0x99, 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF, 0x99,
+    0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF, 0x99, 0x99,
+    0x66, 0x66, 0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF,
+    0x66, 0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF, 0x66,
+    0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF, 0x66, 0x66,
+    0x33, 0x33, 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF,
+    0x33, 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF, 0x33,
+    0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF, 0x33, 0x33,
+    0x00, 0x33, 0x66, 0x33, 0x66, 0x00, 0x66, 0x00, 0x33, 0x00, 0x66, 0x33,
+    0x33, 0x00, 0x66, 0x66, 0x33, 0x00, 0x33, 0x66, 0x99, 0x66, 0x99, 0x33,
+    0x99, 0x33, 0x66, 0x33, 0x99, 0x66, 0x66, 0x33, 0x99, 0x99, 0x66, 0x33,
+    0x66, 0x99, 0xCC, 0x99, 0xCC, 0x66, 0xCC, 0x66, 0x99, 0x66, 0xCC, 0x99,
+    0x99, 0x66, 0xCC, 0xCC, 0x99, 0x66, 0x99, 0xCC, 0xFF, 0xCC, 0xFF, 0x99,
+    0xFF, 0x99, 0xCC, 0x99, 0xFF, 0xCC, 0xCC, 0x99, 0xFF, 0xFF, 0xCC, 0x99,
+    0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x55, 0x55, 0x55,
+    0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xDD, 0xDD, 0xDD, 0xEE, 0xEE, 0xEE
+];