Talk:Gremlin Digital Video
Jump to navigation
Jump to search
(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");
}
}