-use std::rc::Rc;
-use std::cell::RefCell;
use nihav_core::frame::*;
use nihav_core::formats;
use nihav_core::formats::{NAChannelType, NAChannelMap};
use nihav_core::io::byteio::*;
struct GremlinVideoDecoder {
- info: Rc<NACodecInfo>,
+ info: NACodecInfoRef,
pal: [u8; 768],
frame: Vec<u8>,
+ frame16: Vec<u16>,
scale_v: bool,
scale_h: bool,
+ is_16bit: bool,
}
struct Bits8 {
self.queue >>= nbits;
self.fill -= nbits;
if self.fill <= 16 {
- self.queue |= (br.read_u16le()? as u32) << self.fill;
+ self.queue |= u32::from(br.read_u16le()?) << 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
+ info: NACodecInfoRef::default(), pal: [0; 768],
+ frame: Vec::new(), frame16: Vec::new(),
+ scale_v: false, scale_h: false, is_16bit: false,
}
}
Ok(())
}
+ fn lz_copy16(&mut self, idx: usize, offset: isize, len: usize) -> DecoderResult<()> {
+ if idx + len > self.frame16.len() { return Err(DecoderError::InvalidData); }
+ if offset == -1 {
+ let c = self.frame16[idx - 1];
+ for i in 0..len { self.frame16[idx + i] = c; }
+ } else if offset < 0 {
+ let start = idx - (-offset as usize);
+ for i in 0..len { self.frame16[idx + i] = self.frame16[start + i]; }
+ } else {
+ if idx + (offset as usize) + len > self.frame16.len() { return Err(DecoderError::InvalidData); }
+ let start = idx + (offset as usize);
+ for i in 0..len { self.frame16[idx + i] = self.frame16[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; }
self.scale_h = scale_h;
}
+ fn rescale16(&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.frame16[PREAMBLE_SIZE + x + y * w] = self.frame16[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.frame16[PREAMBLE_SIZE + x + y * w] = self.frame16[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.frame16[PREAMBLE_SIZE + x + y * w] = self.frame16[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.frame16[PREAMBLE_SIZE + x + y * (w/2)] = self.frame16[PREAMBLE_SIZE + x*2 + y*2 * w];
+ }
+ }
+ } else if scale_h {
+ for y in 0..h/2 {
+ for x in 0..w {
+ self.frame16[PREAMBLE_SIZE + x + y * w] = self.frame16[PREAMBLE_SIZE + x + y*2 * w];
+ }
+ }
+ } else if scale_v {
+ for y in 0..h {
+ for x in 0..w/2 {
+ self.frame16[PREAMBLE_SIZE + x + y * w] = self.frame16[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 data = buf.get_data_mut().unwrap();
let 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]; }
+ dst[paloff..][..768].copy_from_slice(&self.pal);
if !self.scale_v && !self.scale_h {
for _ in 0..h {
- for x in 0..w { dst[didx + x] = self.frame[sidx + x]; }
+ dst[didx..][..w].copy_from_slice(&self.frame[sidx..][..w]);
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]; }
+ dst[didx..][..w].copy_from_slice(&self.frame[sidx..][..w]);
} else {
for x in 0..w { dst[didx + x] = self.frame[sidx + x/2]; }
}
}
}
+ fn output_frame16(&mut self, bufinfo: &mut NABufferType, w: usize, h: usize) {
+ let bufo = bufinfo.get_vbuf16();
+ let mut buf = bufo.unwrap();
+ let stride = buf.get_stride(0);
+ let data = buf.get_data_mut().unwrap();
+ let dst = data.as_mut_slice();
+
+ if !self.scale_v && !self.scale_h {
+ for (dline, sline) in dst.chunks_mut(stride).zip(self.frame16[PREAMBLE_SIZE..].chunks(w)).take(h) {
+ dline[..w].copy_from_slice(sline);
+ }
+ } else if !self.scale_h {
+ for (dline, sline) in dst.chunks_mut(stride).zip(self.frame16[PREAMBLE_SIZE..].chunks(w / 2)).take(h) {
+ for (dst, &src) in dline.chunks_mut(2).zip(sline.iter()) {
+ dst[0] = src;
+ dst[1] = src;
+ }
+ }
+ } else if !self.scale_v {
+ for (dline, sline) in dst.chunks_mut(stride * 2).zip(self.frame16[PREAMBLE_SIZE..].chunks(w)).take(h) {
+ dline[..w].copy_from_slice(sline);
+ dline[stride..][..w].copy_from_slice(sline);
+ }
+ } else {
+ for (dline, sline) in dst.chunks_mut(stride).zip(self.frame16[PREAMBLE_SIZE..].chunks(w / 2)).take(h) {
+ for x in 0..w/2 {
+ dline[x * 2] = sline[x];
+ dline[x * 2 + 1] = sline[x];
+ dline[x * 2 + stride] = sline[x];
+ dline[x * 2 + 1 + stride] = sline[x];
+ }
+ }
+ }
+ }
+
fn decode_method2(&mut self, br: &mut ByteReader) -> DecoderResult<()> {
let mut bits = Bits8::new();
Ok(())
}
+ fn decode_method2_16bit(&mut self, br: &mut ByteReader) -> DecoderResult<()> {
+ let mut bits = Bits8::new();
+
+ if self.frame16[8] != 64 {
+ for (i, dst) in self.frame16[..PREAMBLE_SIZE].chunks_mut(4).enumerate() {
+ let val = (i as u16) << 5;
+ for el in dst.iter_mut() {
+ *el = val;
+ }
+ }
+ }
+
+ 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;
+ while size > 0 {
+ let tag = bits.read_2bits(br)?;
+ if tag == 0 {
+ self.frame16[idx] = br.read_u16le()?;
+ size -= 1;
+ idx += 1;
+ } else if tag == 1 {
+ let b = br.read_byte()?;
+ let len = ((b & 0xF) as usize) + 3;
+ let bot = (b >> 4) as isize;
+ let off = ((br.read_byte()? as isize) << 4) + bot - 4096;
+ validate!(len <= size);
+ size -= len;
+ self.lz_copy16(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 = Bits8::new();
Ok(())
}
+ #[allow(clippy::identity_op)]
fn decode_method68(&mut self, br: &mut ByteReader,
skip: usize, use8: bool) -> DecoderResult<()> {
let mut bits = Bits32::new();
}
}
+const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
+ comp_info: [
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 1, next_elem: 2 }),
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 2, next_elem: 2 }),
+ None, None],
+ elem_size: 2, be: false, alpha: false, palette: false };
+
impl NADecoder for GremlinVideoDecoder {
- fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ 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();
- if !vinfo.get_format().is_paletted() { return Err(DecoderError::NotImplemented); }
- let fmt = formats::PAL8_FORMAT;
+ self.is_16bit = !vinfo.get_format().is_paletted();
+ let fmt = if !self.is_16bit { PAL8_FORMAT } else { RGB555_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;
+ self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+
+ if !self.is_16bit {
+ 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);
+ 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 + i] = (cc << 2) | (cc >> 4);
+ }
}
+ } else {
+ self.frame16.resize(PREAMBLE_SIZE + w * h, 0);
}
Ok(())
} else {
Err(DecoderError::InvalidData)
}
}
- fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
let src = pkt.get_buffer();
let mut mr = MemoryReader::new_read(&src);
let mut br = ByteReader::new(&mut mr);
let scale_v = (flags & 0x10) != 0;
let scale_h = (flags & 0x20) != 0;
- self.rescale(w, h, scale_v, scale_h);
+ if !self.is_16bit {
+ self.rescale(w, h, scale_v, scale_h);
+ } else {
+ self.rescale16(w, h, scale_v, scale_h);
+ }
+ if self.is_16bit && (cmethod != 2) && (cmethod != 3) {
+ return Err(DecoderError::NotImplemented);
+ }
if (cmethod == 0) || (cmethod == 1) {
+ validate!(!self.is_16bit);
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);
+ self.pal[c * 3 + i] = (b << 2) | (b >> 4);
}
}
if cmethod == 1 {
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)))
+ return Ok(frm.into_ref())
} 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)))
+ return Ok(frm.into_ref())
} else if cmethod == 2 {
- self.decode_method2(&mut br)?;
+ if !self.is_16bit {
+ self.decode_method2(&mut br)?;
+ } else {
+ self.decode_method2_16bit(&mut br)?;
+ }
} else if cmethod == 5 {
self.decode_method5(&mut br, (flags >> 8) as usize)?;
} else if cmethod == 6 {
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();
+ let mut bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
- self.output_frame(&mut bufinfo, w, h);
+ if !self.is_16bit {
+ self.output_frame(&mut bufinfo, w, h);
+ } else {
+ self.output_frame16(&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)))
+ Ok(frm.into_ref())
+ }
+ fn flush(&mut self) {
}
}
-pub fn get_decoder_video() -> Box<NADecoder> {
+impl NAOptionHandler for GremlinVideoDecoder {
+ 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_video() -> Box<dyn NADecoder + Send> {
Box::new(GremlinVideoDecoder::new())
}
}
impl NADecoder for GremlinAudioDecoder {
- fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), ainfo.get_channels(), formats::SND_S16P_FORMAT, ainfo.get_block_len());
self.chmap = get_default_chmap(ainfo.get_channels());
Err(DecoderError::InvalidData)
}
}
- fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
let info = pkt.get_stream().get_info();
if let NACodecTypeInfo::Audio(_) = info.get_properties() {
let pktbuf = pkt.get_buffer();
let samples = pktbuf.len() / self.chmap.num_channels();
- let mut abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
+ let abuf = alloc_audio_buffer(self.ainfo, samples, self.chmap.clone())?;
let mut adata = abuf.get_abuf_i16().unwrap();
let off1 = adata.get_offset(1);
- let mut buf = adata.get_data_mut();
+ let buf = adata.get_data_mut().unwrap();
if self.chmap.num_channels() == 2 {
for (i, e) in pktbuf.chunks(2).enumerate() {
self.state0 = self.state0.wrapping_add(self.delta_tab[e[0] as usize]);
let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
frm.set_duration(Some(samples as u64));
frm.set_keyframe(false);
- Ok(Rc::new(RefCell::new(frm)))
+ Ok(frm.into_ref())
} else {
Err(DecoderError::InvalidData)
}
}
+ fn flush(&mut self) {
+ }
+}
+
+impl NAOptionHandler for GremlinAudioDecoder {
+ 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_audio() -> Box<NADecoder> {
+pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
Box::new(GremlinAudioDecoder::new())
}
#[cfg(test)]
mod test {
- use crate::test::dec_video::test_file_decoding;
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::game_register_all_decoders;
+ use crate::game_register_all_demuxers;
+
+ // samples: intro1.gdv from Normality, SHELI_S.GDV from Jungle Strike
+ #[test]
+ fn test_gdv_video() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ game_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ game_register_all_decoders(&mut dec_reg);
+
+ test_decoding("gdv", "gdv-video", "assets/Game/intro1.gdv", Some(10), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x7ea302bf, 0xc3e210cf, 0x6e341376, 0x9e976056]));
+ }
+ #[test]
+ fn test_gdv_video16() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ game_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ game_register_all_decoders(&mut dec_reg);
+
+ test_decoding("gdv", "gdv-video", "assets/Game/SHELI_S.GDV", Some(10), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x9acfdefd, 0x12687f8c, 0x9ef1cd56, 0x019240bb]));
+ }
#[test]
- fn test_gdv() {
- test_file_decoding("gdv", "assets/intro1.gdv", Some(10), true, false, None);
+ fn test_gdv_audio() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ game_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ game_register_all_decoders(&mut dec_reg);
+
+ test_decoding("gdv", "gdv-audio", "assets/Game/intro1.gdv", None, &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e]));
}
}