From: Kostya Shishkov Date: Wed, 31 May 2017 17:33:20 +0000 (+0200) Subject: Gremlin Video decoder X-Git-Url: https://git.nihav.org/?a=commitdiff_plain;h=e120f8fd4ce8dedad96d9ee73963b0dc344d273e;p=nihav.git Gremlin Video decoder --- diff --git a/Cargo.toml b/Cargo.toml index 033ec23..a7cb1da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,8 @@ demuxer_gdv = ["demuxers"] decoders = [] all_decoders = ["all_video_decoders", "all_audio_decoders"] -all_video_decoders = ["decoder_indeo2", "decoder_indeo3"] +all_video_decoders = ["decoder_gdvvid", "decoder_indeo2", "decoder_indeo3"] +decoder_gdvvid = ["decoders"] decoder_indeo2 = ["decoders"] decoder_indeo3 = ["decoders"] diff --git a/src/codecs/gremlinvideo.rs b/src/codecs/gremlinvideo.rs new file mode 100644 index 0000000..e6478aa --- /dev/null +++ b/src/codecs/gremlinvideo.rs @@ -0,0 +1,515 @@ +use formats; +use super::*; +use io::byteio::*; + +struct GremlinVideoDecoder { + info: Rc, + pal: [u8; 768], + frame: Vec, + 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 { + 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 { + 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) -> 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 { + 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 { + 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>> = 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"); + } +} diff --git a/src/codecs/mod.rs b/src/codecs/mod.rs index d1a970f..8ce4e50 100644 --- a/src/codecs/mod.rs +++ b/src/codecs/mod.rs @@ -107,6 +107,8 @@ macro_rules! validate { ($a:expr) => { if !$a { return Err(DecoderError::InvalidData); } }; } +#[cfg(feature="decoder_gdvvid")] +mod gremlinvideo; #[cfg(feature="decoder_indeo2")] mod indeo2; #[cfg(feature="decoder_indeo3")] @@ -115,6 +117,8 @@ mod indeo3; mod pcm; const DECODERS: &[DecoderInfo] = &[ +#[cfg(feature="decoder_gdvvid")] + DecoderInfo { name: "gdv-video", get_decoder: gremlinvideo::get_decoder }, #[cfg(feature="decoder_indeo2")] DecoderInfo { name: "indeo2", get_decoder: indeo2::get_decoder }, #[cfg(feature="decoder_indeo3")]