Talk:Gremlin Digital Video

From MultimediaWiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

(c) Kostya http://sprunge.us/PTHd

use formats;
use super::*;
use io::byteio::*;

struct GremlinVideoDecoder {
    info:       Rc<NACodecInfo>,
    pal:        [u8; 768],
    frame:      Vec<u8>,
    scale_v:    bool,
    scale_h:    bool,
}

struct Bits16 {
    queue: u16,
    fill:  u8,
}

struct Bits32 {
    queue: u32,
    fill:  u8,
}

const PREAMBLE_SIZE: usize = 4096;

impl Bits16 {
    fn new() -> Self { Bits16 { queue: 0, fill: 0 } }
    fn read_2bits(&mut self, br: &mut ByteReader) -> ByteIOResult<u16> {
        if self.fill == 0 {
            self.queue |= (br.read_byte()? as u16) << self.fill;
            self.fill  += 8;
        }
        let res = self.queue & 0x3;
        self.queue >>= 2;
        self.fill   -= 2;
        Ok(res)
    }
}

impl Bits32 {
    fn new() -> Self { Bits32 { queue: 0, fill: 0 } }
    fn fill(&mut self, br: &mut ByteReader) -> ByteIOResult<()> {
        self.queue = br.read_u32le()?;
        self.fill  = 32;
        Ok(())
    }
    fn read_bits(&mut self, br: &mut ByteReader, nbits: u8) -> ByteIOResult<u32> {
        let res = self.queue & ((1 << nbits) - 1);
        self.queue >>= nbits;
        self.fill   -= nbits;
        if self.fill <= 16 {
            self.queue |= (br.read_u16le()? as u32) << self.fill;
            self.fill  += 16;
        }
        Ok(res)
    }
}

impl GremlinVideoDecoder {
    fn new() -> Self {
        let dummy_info = Rc::new(DUMMY_CODEC_INFO);
        GremlinVideoDecoder {
            info: dummy_info, pal: [0; 768], frame: Vec::new(),
            scale_v: false, scale_h: false
        }
    }

    fn lz_copy(&mut self, idx: usize, offset: isize, len: usize) -> DecoderResult<()> {
        if idx + len > self.frame.len() { return Err(DecoderError::InvalidData); }
        if offset == -1 {
            let c = self.frame[idx - 1];
            for i in 0..len { self.frame[idx + i] = c; }
        } else if offset < 0 {
            let start = idx - (-offset as usize);
            for i in 0..len { self.frame[idx + i] = self.frame[start + i]; }
        } else {
            if idx + (offset as usize) + len > self.frame.len() { return Err(DecoderError::InvalidData); }
            let start = idx + (offset as usize);
            for i in 0..len { self.frame[idx + i] = self.frame[start + i]; }
        }
        Ok(())
    }

    fn rescale(&mut self, w: usize, h: usize, scale_v: bool, scale_h: bool) {
        if (self.scale_v == scale_v) && (self.scale_h == scale_h) { return; }

        if self.scale_h && self.scale_v {
            for j in 0..h {
                let y = h - j - 1;
                for i in 0..w {
                    let x = w - i - 1;
                    self.frame[PREAMBLE_SIZE + x + y * w] = self.frame[PREAMBLE_SIZE + x/2 + (y/2) * (w/2)];
                }
            }
        } else if self.scale_h {
            for j in 0..h {
                let y = h - j - 1;
                for x in 0..w {
                    self.frame[PREAMBLE_SIZE + x + y * w] = self.frame[PREAMBLE_SIZE + x + (y/2) * w];
                }
            }
        } else if self.scale_v {
            for j in 0..h {
                let y = h - j - 1;
                for i in 0..w {
                    let x = w - i - 1;
                    self.frame[PREAMBLE_SIZE + x + y * w] = self.frame[PREAMBLE_SIZE + x/2 + y * (w/2)];
                }
            }
        }

        if scale_h && scale_v {
            for y in 0..h/2 {
                for x in 0..w/2 {
                    self.frame[PREAMBLE_SIZE + x + y * (w/2)] = self.frame[PREAMBLE_SIZE + x*2 + y*2 * w];
                }
            }
        } else if scale_h {
            for y in 0..h/2 {
                for x in 0..w {
                    self.frame[PREAMBLE_SIZE + x + y * w] = self.frame[PREAMBLE_SIZE + x + y*2 * w];
                }
            }
        } else if scale_v {
            for y in 0..h {
                for x in 0..w/2 {
                    self.frame[PREAMBLE_SIZE + x + y * w] = self.frame[PREAMBLE_SIZE + x*2 + y * w];
                }
            }
        }

        self.scale_v = scale_v;
        self.scale_h = scale_h;
    }

    fn output_frame(&mut self, bufinfo: &mut NABufferType, w: usize, h: usize) {
        let bufo = bufinfo.get_vbuf();
        let mut buf = bufo.unwrap();
        let paloff = buf.get_offset(1);
        let stride = buf.get_stride(0);
        let mut data = buf.get_data_mut();
        let mut dst = data.as_mut_slice();
        let mut sidx = PREAMBLE_SIZE;
        let mut didx = 0;

        for i in 0..768 { dst[paloff + i] = self.pal[i]; }
        if !self.scale_v && !self.scale_h {
            for _ in 0..h {
                for x in 0..w { dst[didx + x] = self.frame[sidx + x]; }
                sidx += w;
                didx += stride;
            }
        } else {
            for y in 0..h {
                if !self.scale_v {
                    for x in 0..w { dst[didx + x] = self.frame[sidx + x]; }
                } else {
                    for x in 0..w { dst[didx + x] = self.frame[sidx + x/2]; }
                }
                if !self.scale_h || ((y & 1) == 1) {
                    sidx += if !self.scale_v { w } else { w/2 };
                }
                didx += stride;
            }
        }
    }

    fn decode_method2(&mut self, br: &mut ByteReader) -> DecoderResult<()> {
        let mut bits = Bits16::new();

        let mut size = self.info.get_properties().get_video_info().unwrap().get_width() *
                        self.info.get_properties().get_video_info().unwrap().get_height();
        let mut idx = PREAMBLE_SIZE;
        for c in 0..256 {
            for i in 0..16 { self.frame[c * 16 + i] = c as u8; }
        }
        while size > 0 {
            let tag = bits.read_2bits(br)?;
            if tag == 0 {
                self.frame[idx] = br.read_byte()?;
                size -= 1;
                idx  += 1;
            } else if tag == 1 {
                let b = br.read_byte()?;
                let len = ((b & 0xF) as usize) + 3;
                let top = (b >> 4) as isize;
                let off = (top << 8) + (br.read_byte()? as isize) - 4096;
                validate!(len <= size);
                size -= len;
                self.lz_copy(idx, off, len)?; 
                idx += len;
            } else if tag == 2 {
                let len = (br.read_byte()? as usize) + 2;
                validate!(len <= size);
                size -= len;
                idx += len;
            } else {
                break;
            }
        }
        Ok(())
    }

    fn decode_method5(&mut self, br: &mut ByteReader, skip: usize) -> DecoderResult<()> {
        let mut bits = Bits16::new();

        let mut size = self.info.get_properties().get_video_info().unwrap().get_width() *
                        self.info.get_properties().get_video_info().unwrap().get_height();
        let mut idx = PREAMBLE_SIZE;
        validate!(size >= skip);
        size -= skip;
        idx  += skip;
        while size > 0 {
            let tag = bits.read_2bits(br)?;
            if tag == 0 {
                self.frame[idx] = br.read_byte()?;
                size -= 1;
                idx  += 1;
            } else if tag == 1 {
                let b = br.read_byte()?;
                let len = ((b & 0xF) as usize) + 3;
                let top = (b >> 4) as isize;
                let off = (top << 8) + (br.read_byte()? as isize) - 4096;
                validate!(len <= size);
                size -= len;
                self.lz_copy(idx, off, len)?; 
                idx += len;
            } else if tag == 2 {
                let b = br.read_byte()?;
                if b == 0 { break; }
                let len: usize = if b != 0xFF { b as usize } else { br.read_u16le()? as usize };
                validate!(len <= size);
                size -= len;
                idx += len;
            } else {
                let b = br.read_byte()?;
                let len = ((b & 0x3) as usize) + 2;
                let off = -((b >> 2) as isize) - 1;
                validate!(len <= size);
                size -= len;
                self.lz_copy(idx, off, len)?; 
                idx += len;
            }
        }
        Ok(())
    }

    fn decode_method68(&mut self, br: &mut ByteReader,
                       skip: usize, use8: bool) -> DecoderResult<()> {
        let mut bits = Bits32::new();

        let mut size = self.info.get_properties().get_video_info().unwrap().get_width() *
                        self.info.get_properties().get_video_info().unwrap().get_height();
        let mut idx = PREAMBLE_SIZE;
        validate!(size >= skip);
        size -= skip;
        idx  += skip;
        bits.fill(br)?;
        while size > 0 {
            let tag = bits.read_bits(br, 2)?;
            if tag == 0 { //draw
                let b = bits.read_bits(br, 1)?;
                if b == 0 {
                    self.frame[idx] = br.read_byte()?;
                    size -= 1;
                    idx  += 1;
                } else {
                    let mut len: usize = 2;
                    let mut lbits = 0;
                    loop {
                        lbits += 1;
                        let val = bits.read_bits(br, lbits)?;
                        len += val as usize;
                        if val != ((1 << lbits) - 1) { break; }
                        validate!(lbits < 16);
                    }
                    validate!(len <= size);
                    for i in 0..len { self.frame[idx + i] = br.read_byte()?; }
                    size -= len;
                    idx  += len;
                }
            } else if tag == 1 { //skip
                let b = bits.read_bits(br, 1)?;
                let len: usize;
                if b == 0 {
                    len = (bits.read_bits(br, 4)? as usize) + 2;
                } else {
                    let bb = br.read_byte()?;
                    if (bb & 0x80) == 0 {
                        len = (bb as usize) + 18;
                    } else {
                        let top = ((bb & 0x7F) as usize) << 8;
                        len = top + (br.read_byte()? as usize) + 146;
                    }
                }
                validate!(len <= size);
                size -= len;
                idx  += len;
            } else if tag == 2 {
                let subtag = bits.read_bits(br, 2)? as usize;
                if subtag != 3 {
                    let top = (bits.read_bits(br, 4)? as usize) << 8;
                    let offs = top + (br.read_byte()? as usize);
                    if (subtag != 0) || (offs <= 0xF80) {
                        let len = (subtag as usize) + 3;
                        self.lz_copy(idx, (offs as isize) - 4096, len)?;
                        idx += len;
                    } else {
                        if offs == 0xFFF { return Ok(()); }
                        let real_off = ((offs >> 4) & 0x7) + 1;
                        let len = ((offs & 0xF) + 2) * 2;
                        validate!(len <= size);
                        size -= len;
                        let c1 = self.frame[idx - real_off];
                        let c2 = self.frame[idx - real_off + 1];
                        for i in 0..len/2 {
                            self.frame[idx + i*2 + 0] = c1;
                            self.frame[idx + i*2 + 1] = c2;
                        }
                        idx += len;
                    }
                } else {
                    let b = br.read_byte()?;
                    let off = ((b & 0x7F) as usize) + 1;
                    let len = if (b & 0x80) == 0 { 2 } else { 3 };
                    validate!(len <= size);
                    size -= len;
                    self.lz_copy(idx, -(off as isize), len)?; 
                    idx += len;
                }
            } else {
                let len: usize;
                let off: isize;
                if use8 {
                    let b = br.read_byte()?;
                    if (b & 0xC0) == 0xC0 {
                        len = ((b & 0x3F) as usize) + 8;
                        let q = bits.read_bits(br, 4)? as isize;
                        off = (q << 8) + (br.read_byte()? as isize) + 1;
                    } else {
                        let ofs1: isize;
                        if (b & 0x80) == 0 {
                            len = ((b >> 4) as usize) + 6;
                            ofs1 = (b & 0xF) as isize;
                        } else {
                            len = ((b & 0x3F) as usize) + 14;
                            ofs1 = bits.read_bits(br, 4)? as isize;
                        }
                        off = (ofs1 << 8) + (br.read_byte()? as isize) - 4096;
                    }
                } else {
                    let b = br.read_byte()?;
                    if (b >> 4) == 0xF {
                        len = (br.read_byte()? as usize) + 21;
                    } else {
                        len = ((b >> 4) as usize) + 6;
                    }
                    let ofs1 = (b & 0xF) as isize;
                    off = (ofs1 << 8) + (br.read_byte()? as isize) - 4096;
                }
                validate!(len <= size);
                size -= len;
                self.lz_copy(idx, off, len)?; 
                idx += len;
            }
        }
        Ok(())
    }
}

impl NADecoder for GremlinVideoDecoder {
    fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
            let w = vinfo.get_width();
            let h = vinfo.get_height();
            if !vinfo.get_format().is_paletted() { return Err(DecoderError::NotImplemented); }
            let fmt = formats::PAL8_FORMAT;
            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt));
            self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()));

            self.frame.resize(PREAMBLE_SIZE + w * h, 0);
            for i in 0..2 {
                for j in 0..256 {
                    for k in 0..8 {
                        self.frame[i * 2048 + j * 8 + k] = j as u8;
                    }
                }
            }
            let edata = info.get_extradata().unwrap();
            validate!(edata.len() == 768);
            for c in 0..256 {
                for i in 0..3 {
                    let cc = edata[c * 3 + i];
                    self.pal[c * 3 + (2 - i)] = (cc << 2) | (cc >> 4);
                }
            }
            Ok(())
        } else {
            Err(DecoderError::InvalidData)
        }
    }
    fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
        let src = pkt.get_buffer();
        let mut mr = MemoryReader::new_read(&src);
        let mut br = ByteReader::new(&mut mr);
        let flags = br.read_u32le()?;
        let w = self.info.get_properties().get_video_info().unwrap().get_width();
        let h = self.info.get_properties().get_video_info().unwrap().get_height();

        let cmethod = flags & 0xF;
        let is_intra = (flags & 0x40) != 0;
        let scale_v = (flags & 0x10) != 0;
        let scale_h = (flags & 0x20) != 0;

        self.rescale(w, h, scale_v, scale_h);

        if (cmethod == 0) || (cmethod == 1) {
            for c in 0..256 {
                for i in 0..3 {
                    let b = br.read_byte()?;
                    self.pal[c * 3 + (2 - i)] = (b << 2) | (b >> 4);
                }
            }
            if cmethod == 1 {
                for i in PREAMBLE_SIZE..self.frame.len() { self.frame[i] = 0x00; }
            }
            let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
            frm.set_keyframe(false);
            frm.set_frame_type(FrameType::Skip);
            return Ok(Rc::new(RefCell::new(frm)))
        } else if cmethod == 3 {
            let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
            frm.set_keyframe(false);
            frm.set_frame_type(FrameType::Skip);
            return Ok(Rc::new(RefCell::new(frm)))
        } else if cmethod == 2 {
            self.decode_method2(&mut br)?;
        } else if cmethod == 5 {
            self.decode_method5(&mut br, (flags >> 8) as usize)?;
        } else if cmethod == 6 {
            self.decode_method68(&mut br, (flags >> 8) as usize, false)?;
        } else if cmethod == 8 {
            self.decode_method68(&mut br, (flags >> 8) as usize, true)?;
        } else {
            return Err(DecoderError::NotImplemented);
        }

        let bufret = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0);
        if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
        let mut bufinfo = bufret.unwrap();

        self.output_frame(&mut bufinfo, w, h);

        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
        frm.set_keyframe(is_intra);
        frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
        Ok(Rc::new(RefCell::new(frm)))
    }
}

pub fn get_decoder() -> Box<NADecoder> {
    Box::new(GremlinVideoDecoder::new())
}

#[cfg(test)]
mod test {
    use codecs::*;
    use demuxers::*;
    use io::byteio::*;
    use std::fs::File;

    #[test]
    fn test_gdv() {
        let gdv_dmx = find_demuxer("gdv").unwrap();
        let mut file = File::open("assets/intro1.gdv").unwrap();
        let mut fr = FileReader::new_read(&mut file);
        let mut br = ByteReader::new(&mut fr);
        let mut dmx = gdv_dmx.new_demuxer(&mut br);
        dmx.open().unwrap();

        let mut decs: Vec<Option<Box<NADecoder>>> = Vec::new();
        for i in 0..dmx.get_num_streams() {
            let s = dmx.get_stream(i).unwrap();
            let info = s.get_info();
            let decfunc = find_decoder(info.get_name());
            if !info.is_video() {
                decs.push(None);
            } else if let Some(df) = decfunc {
                let mut dec = (df)();
                dec.init(info).unwrap();
                decs.push(Some(dec));
            } else {
panic!("decoder {} not found", info.get_name());
            }
        }

        loop {
            let pktres = dmx.get_frame();
            if let Err(e) = pktres {
                if e == DemuxerError::EOF { break; }
            }
            let pkt = pktres.unwrap();
            let streamno = pkt.get_stream().get_id() as usize;
            if let Some(ref mut dec) = decs[streamno] {
                let frm = dec.decode(&pkt).unwrap();
                if pkt.get_stream().get_info().is_video() {
                    if frm.borrow().get_frame_type() != FrameType::Skip {
                        write_palppm("gdv", streamno, pkt.get_pts().unwrap(), frm);
                    }
                }
            }
            if pkt.get_pts().unwrap() > 8 { break; }
        }
//panic!("end");
    }
}