1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
3 use nihav_core::compr::lz_copy;
5 const FRAME_HEADER: usize = 24;
7 struct RobotVideoDecoder {
17 impl RobotVideoDecoder {
20 info: NACodecInfoRef::default(),
31 struct BitReader<'a, 'b> {
32 br: &'a mut ByteReader<'b>,
38 impl<'a, 'b> BitReader<'a, 'b> {
39 fn new(br: &'a mut ByteReader<'b>, size: usize) -> Self {
40 let end = br.tell() + (size as u64);
47 fn refill(&mut self) -> DecoderResult<()> {
48 while self.bits <= 24 && self.br.tell() < self.end {
49 self.bbuf |= u32::from(self.br.read_byte()?) << (24 - self.bits);
54 fn read_bit(&mut self) -> DecoderResult<bool> {
56 if self.bits == 0 { return Err(DecoderError::ShortData); }
57 let bit = (self.bbuf >> 31) != 0;
62 fn read(&mut self, nbits: u8) -> DecoderResult<u32> {
64 if self.bits < nbits { return Err(DecoderError::ShortData); }
65 let ret = self.bbuf >> (32 - nbits);
72 fn lzs_unpack(br: &mut ByteReader, csize: usize, dst: &mut [u8]) -> DecoderResult<()> {
73 let mut br = BitReader::new(br, csize);
78 let offset = (if br.read_bit()? {
79 let off = br.read(7)?;
81 validate!(dpos == dst.len());
89 let mut len = br.read(2)?;
107 let len = len as usize;
109 validate!(offset <= dpos);
110 validate!(dpos + len <= dst.len());
111 lz_copy(dst, dpos, offset, len);
114 dst[dpos] = br.read(8)? as u8;
120 fn unpack_cell(br: &mut ByteReader, cell_size: usize, nchunks: usize, dst: &mut Vec<u8>, limit: usize) -> DecoderResult<()> {
121 let mut data_left = cell_size;
124 for _ in 0..nchunks {
125 validate!(data_left >= 10);
126 let csize = br.read_u32le()? as usize;
127 validate!(csize <= data_left);
128 let rsize = br.read_u32le()? as usize;
129 validate!(rsize + dst.len() <= limit);
130 let method = br.read_u16le()?;
134 let cur_size = dst.len();
135 dst.resize(cur_size + rsize, 0);
137 0 => { lzs_unpack(br, csize, &mut dst[cur_size..])?; },
139 validate!(rsize == csize);
140 br.read_buf(&mut dst[cur_size..])?;
142 _ => return Err(DecoderError::NotImplemented),
149 fn blit(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize) {
150 for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)) {
151 dline[..sstride].copy_from_slice(sline);
155 fn blit_scaled(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, scale: u8) {
156 let mut slines = src.chunks(sstride);
159 let mut cur_line = slines.next().unwrap();
161 for dline in dst.chunks_mut(dstride) {
162 dline[..sstride].copy_from_slice(cur_line);
166 if let Some(line) = slines.next() {
175 impl NADecoder for RobotVideoDecoder {
176 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
177 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
178 self.width = vinfo.get_width();
179 self.height = vinfo.get_height();
180 self.frame.resize(self.width * self.height, 0);
181 if let Some(ref edata) = info.get_extradata() {
182 validate!(edata.len() > 2);
183 self.version = edata[0];
184 validate!(self.version >= 4 && self.version <= 6);
186 validate!(edata.len() > 39);
187 let pal_start = read_u16le(&edata[25+2..])? as usize;
188 let pal_len = read_u16le(&edata[29+2..])? as usize;
189 validate!(pal_len > 0 && pal_start + pal_len <= 256);
192 let dpal = self.pal[pal_start * 3..].chunks_exact_mut(3);
193 for (dst, quad) in dpal.zip(edata[37+2..].chunks_exact(4)) {
194 dst.copy_from_slice(&quad[1..]);
197 1 => self.pal[pal_start * 3..][..pal_len * 3].copy_from_slice(&edata[37+2..][..pal_len * 3]),
198 _ => return Err(DecoderError::NotImplemented),
201 for (i, entry) in self.pal.chunks_exact_mut(3).enumerate() {
208 return Err(DecoderError::InvalidData);
210 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, PAL8_FORMAT));
211 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
215 Err(DecoderError::InvalidData)
218 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
219 let src = pkt.get_buffer();
220 validate!(src.len() > FRAME_HEADER);
222 let mut mr = MemoryReader::new_read(&src);
223 let mut br = ByteReader::new(&mut mr);
225 let ncells = br.read_u16le()? as usize;
226 validate!(ncells > 0 && ncells <= 10);
227 for el in self.frame.iter_mut() { *el = 0xFF; }
230 let scale = br.read_byte()?;
231 let width = br.read_u16le()? as usize;
232 let height = br.read_u16le()? as usize;
234 let xoff = br.read_u16le()? as usize;
235 let yoff = br.read_u16le()? as usize;
236 validate!(xoff + width <= self.width && yoff + height <= self.height);
237 let mut cell_size = br.read_u16le()? as usize;
239 if self.version == 6 && ncells == 1 && (src.len() - 18 >= 0x10000) {
240 cell_size += (src.len() - 18) & !0xFFFF;
242 if self.version > 4 {
243 let nchunks = br.read_u16le()? as usize;
244 validate!(nchunks > 0);
247 unpack_cell(&mut br, cell_size, nchunks, &mut self.cell_buf, width * height)?;
250 self.cell_buf.resize(width * height, 0);
251 lzs_unpack(&mut br, cell_size, &mut self.cell_buf)?;
254 blit(&mut self.frame[xoff + yoff * self.width..], self.width, &self.cell_buf, width);
256 blit_scaled(&mut self.frame[xoff + yoff * self.width..], self.width, &self.cell_buf, width, scale);
260 let buf = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
261 let mut vbuf = buf.get_vbuf().unwrap();
262 let paloff = vbuf.get_offset(1);
263 let stride = vbuf.get_stride(0);
264 let data = vbuf.get_data_mut().unwrap();
266 blit(data, stride, &self.frame, self.width);
267 data[paloff..][..768].copy_from_slice(&self.pal);
269 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buf);
270 let ftype = if pkt.keyframe { FrameType::I } else { FrameType::P };
271 frm.set_frame_type(ftype);
274 fn flush(&mut self) {
278 impl NAOptionHandler for RobotVideoDecoder {
279 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
280 fn set_options(&mut self, _options: &[NAOption]) { }
281 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
284 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
285 Box::new(RobotVideoDecoder::new())
288 struct RobotAudioDecoder {
289 info: NACodecInfoRef,
294 impl RobotAudioDecoder {
297 ainfo: NAAudioInfo::new(11025, 1, SND_S16_FORMAT, 1),
298 info: NACodecInfo::new_dummy(),
299 chmap: NAChannelMap::from_str("C").unwrap(),
302 fn pred16(pred: i32, val: u8) -> i32 {
303 if (val & 0x80) != 0 {
304 pred - i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
306 pred + i32::from(SOL_AUD_STEPS16[(val & 0x7F) as usize])
311 impl NADecoder for RobotAudioDecoder {
312 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
313 if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
314 self.info = info.replace_info(NACodecTypeInfo::Audio(self.ainfo));
318 Err(DecoderError::InvalidData)
321 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
322 let src = pkt.get_buffer();
323 validate!(src.len() > 1);
325 let samples = match src[0] {
327 1 => src.len() - 1 - 8,
328 _ => return Err(DecoderError::InvalidData),
331 let abuf = alloc_audio_buffer(self.ainfo, samples / 2, self.chmap.clone())?;
332 let mut adata = abuf.get_abuf_i16().unwrap();
333 let dst = adata.get_data_mut().unwrap();
338 for (dst, &b) in dst.iter_mut().zip(src[1..][..src.len()/2].iter()) {
339 pred = Self::pred16(pred, b);
344 validate!(src.len() > 8);
346 for &b in src[1..9].iter() {
347 pred = Self::pred16(pred, b);
349 for (dst, &b) in dst.iter_mut().zip(src[9..].iter()) {
350 pred = Self::pred16(pred, b);
357 let frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
360 fn flush(&mut self) {
364 impl NAOptionHandler for RobotAudioDecoder {
365 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
366 fn set_options(&mut self, _options: &[NAOption]) { }
367 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
370 pub fn get_decoder_audio() -> Box<dyn NADecoder + Send> {
371 Box::new(RobotAudioDecoder::new())
376 use nihav_core::codecs::RegisteredDecoders;
377 use nihav_core::demuxers::RegisteredDemuxers;
378 use nihav_codec_support::test::dec_video::*;
382 let mut dmx_reg = RegisteredDemuxers::new();
383 game_register_all_demuxers(&mut dmx_reg);
384 let mut dec_reg = RegisteredDecoders::new();
385 game_register_all_decoders(&mut dec_reg);
387 // sample from SWAT demo
388 test_decoding("sierra-rbt", "rbt-video", "assets/Game/sierra/12.rbt",
389 Some(2), &dmx_reg, &dec_reg,
390 ExpectedTestResult::MD5Frames(vec![
391 [0x2a00775d, 0xef8da06a, 0x015b6f06, 0xa22d0158],
392 [0xf2acb558, 0x0d9c5c54, 0x32c43af4, 0xd9776b68],
393 [0x386e02e9, 0x76dbd5a6, 0x4e9da3d7, 0xa47fdca3]]));
397 let mut dmx_reg = RegisteredDemuxers::new();
398 game_register_all_demuxers(&mut dmx_reg);
399 let mut dec_reg = RegisteredDecoders::new();
400 game_register_all_decoders(&mut dec_reg);
402 // sample from Phantasmagora (with scaling)
403 test_decoding("sierra-rbt", "rbt-video", "assets/Game/sierra/162.RBT",
404 None, &dmx_reg, &dec_reg,
405 ExpectedTestResult::MD5([0x4912fa8f, 0xae201d9e, 0x59707ea0, 0xc50bf0e2]));
409 let mut dmx_reg = RegisteredDemuxers::new();
410 game_register_all_demuxers(&mut dmx_reg);
411 let mut dec_reg = RegisteredDecoders::new();
412 game_register_all_decoders(&mut dec_reg);
415 test_decoding("sierra-rbt", "rbt-video", "assets/Game/sierra/7531.RBT",
416 Some(2), &dmx_reg, &dec_reg,
417 ExpectedTestResult::MD5Frames(vec![
418 [0x49db87f3, 0x57881095, 0x676d1600, 0x5ddaa50b],
419 [0xa75ff558, 0xb6815b27, 0x5f9d872f, 0xd7f56470],
420 [0x60bca745, 0xc47d6882, 0xc193fe70, 0x7b8738c9]]));
423 fn test_rbt_audio() {
424 let mut dmx_reg = RegisteredDemuxers::new();
425 game_register_all_demuxers(&mut dmx_reg);
426 let mut dec_reg = RegisteredDecoders::new();
427 game_register_all_decoders(&mut dec_reg);
429 // sample from Space Quest 6
430 test_decoding("sierra-rbt", "rbt-audio", "assets/Game/sierra/410.rbt",
431 Some(2), &dmx_reg, &dec_reg,
432 ExpectedTestResult::MD5([0xdd44e3ca, 0x6cfc1bc1, 0xdcd4214a, 0x443cf5ed]));
436 const SOL_AUD_STEPS16: [i16; 128] = [
437 0x00, 0x08, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
438 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
439 0xF0, 0x100, 0x110, 0x120, 0x130, 0x140, 0x150, 0x160,
440 0x170, 0x180, 0x190, 0x1A0, 0x1B0, 0x1C0, 0x1D0, 0x1E0,
441 0x1F0, 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
442 0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270,
443 0x278, 0x280, 0x288, 0x290, 0x298, 0x2A0, 0x2A8, 0x2B0,
444 0x2B8, 0x2C0, 0x2C8, 0x2D0, 0x2D8, 0x2E0, 0x2E8, 0x2F0,
445 0x2F8, 0x300, 0x308, 0x310, 0x318, 0x320, 0x328, 0x330,
446 0x338, 0x340, 0x348, 0x350, 0x358, 0x360, 0x368, 0x370,
447 0x378, 0x380, 0x388, 0x390, 0x398, 0x3A0, 0x3A8, 0x3B0,
448 0x3B8, 0x3C0, 0x3C8, 0x3D0, 0x3D8, 0x3E0, 0x3E8, 0x3F0,
449 0x3F8, 0x400, 0x440, 0x480, 0x4C0, 0x500, 0x540, 0x580,
450 0x5C0, 0x600, 0x640, 0x680, 0x6C0, 0x700, 0x740, 0x780,
451 0x7C0, 0x800, 0x900, 0xA00, 0xB00, 0xC00, 0xD00, 0xE00,
452 0xF00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000