1 use nihav_core::codecs::*;
2 use nihav_core::io::byteio::*;
4 const VB_FLAG_GMC: u16 = 0x0001;
5 const VB_FLAG_AUDIO: u16 = 0x0004;
6 const VB_FLAG_VIDEO: u16 = 0x0008;
7 const VB_FLAG_PALETTE: u16 = 0x0010;
9 const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
11 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
12 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 1, next_elem: 2 }),
13 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 2, next_elem: 2 }),
15 elem_size: 2, be: false, alpha: false, palette: false };
17 fn check_size(x: usize, row_no: usize, dx: i16, dy: i16, stride: usize, len: usize) -> Option<usize> {
18 let start = (x as i32) + i32::from(dx) + ((row_no * 4) as i32 + i32::from(dy)) * (stride as i32);
20 let start = start as usize;
21 let end = start + 4 + stride * 3;
33 fn decode_video8(br: &mut ByteReader, dst: &mut [u8], prev_frame: &[u8], width: usize, gmv: [i16; 2]) -> DecoderResult<FrameType> {
34 let mut ftype = FrameType::I;
38 for (row_no, strip) in dst.chunks_mut(width * 4).enumerate() {
39 for x in (0..width).step_by(4) {
41 btypes = br.read_byte()?;
46 let t = br.read_byte()?;
47 let mut pattern = VB_PATTERNS[(t & 0x3F) as usize];
52 br.read_buf(&mut clr)?;
53 for dline in strip[x..].chunks_mut(width).take(4) {
54 for el in dline[..4].iter_mut() {
55 *el = clr[(pattern & 1) as usize];
63 let clr = br.read_byte()?;
65 if let Some(start) = check_size(x, row_no, gmv[0], gmv[1], width, prev_frame.len()) {
66 for (dline, sline) in strip[x..].chunks_mut(width).zip(prev_frame[start..].chunks(width)).take(4) {
67 for (dst, &src) in dline[..4].iter_mut().zip(sline.iter()) {
68 *dst = if (pattern & 1) != 0 { clr } else { src };
73 return Err(DecoderError::InvalidData);
80 let clr = br.read_byte()?;
81 for dline in strip[x..].chunks_mut(width).take(4) {
82 for el in dline[..4].iter_mut() {
88 let mv = br.read_byte()?;
90 for dline in strip[x..].chunks_mut(width).take(4) {
91 br.read_buf(&mut dline[..4])?;
94 let mvx = (((mv & 0xF) ^ 8) as i16) - 8;
95 let mvy = (((mv >> 4) ^ 8) as i16) - 8;
96 if let Some(start) = check_size(x, row_no, gmv[0] + mvx, gmv[1] + mvy, width, prev_frame.len()) {
97 for (dline, sline) in strip[x..].chunks_mut(width).zip(prev_frame[start..].chunks(width)).take(4) {
98 dline[..4].copy_from_slice(&sline[..4]);
101 return Err(DecoderError::InvalidData);
103 ftype = FrameType::P;
107 if let Some(start) = check_size(x, row_no, gmv[0], gmv[1], width, prev_frame.len()) {
108 for (dline, sline) in strip[x..].chunks_mut(width).zip(prev_frame[start..].chunks(width)).take(4) {
109 dline[..4].copy_from_slice(&sline[..4]);
112 return Err(DecoderError::InvalidData);
114 ftype = FrameType::P;
135 fn new(w: usize, h: usize, flags: u16) -> Self {
138 prev_frame: vec![0; w * h],
139 cur_frame: vec![0; w * h],
144 fn decode(&mut self, br: &mut ByteReader, vbuf: &mut NAVideoBufferRef<u8>) -> DecoderResult<FrameType> {
145 let asize = br.read_u16le()? as usize;
146 let _smth = br.read_u16le()? as usize;
147 let pal_size = br.read_u16le()? as usize;
149 let pal_start = br.read_u16le()? as usize;
150 validate!(pal_start + pal_size <= 256);
151 br.read_buf(&mut self.pal[pal_start * 3..][..pal_size * 3])?;
153 br.read_skip(asize)?;
155 let (gmv_x, gmv_y) = if (self.flags & 0x2000) != 0 {
156 let mvx = br.read_u16le()? as i16;
157 let mvy = br.read_u16le()? as i16;
163 std::mem::swap(&mut self.cur_frame, &mut self.prev_frame);
165 let ftype = decode_video8(br, &mut self.cur_frame, &self.prev_frame, self.width, [gmv_x, gmv_y])?;
167 let stride = vbuf.get_stride(0);
168 let pal_off = vbuf.get_offset(1);
169 let data = vbuf.get_data_mut().unwrap();
171 for (dline, sline) in data.chunks_mut(stride).zip(self.cur_frame.chunks(self.width)) {
172 dline[..self.width].copy_from_slice(sline);
174 data[pal_off..][..768].copy_from_slice(&self.pal);
188 fn new(w: usize, h: usize) -> Self {
191 prev_frame: vec![0; w * h],
192 cur_frame: vec![0; w * h],
196 fn decode(&mut self, br: &mut ByteReader, vbuf: &mut NAVideoBufferRef<u8>) -> DecoderResult<FrameType> {
197 let flags = br.read_u16le()?;
198 let (gmv_x, gmv_y) = if (flags & VB_FLAG_GMC) != 0 {
199 let mvx = br.read_u16le()? as i16;
200 let mvy = br.read_u16le()? as i16;
205 if (flags & VB_FLAG_AUDIO) != 0 {
206 let asize = br.read_u32le()? as usize;
207 validate!(asize >= 4 && asize <= (br.left() as usize));
208 br.read_skip(asize - 4)?;
210 let mut ftype = FrameType::Skip;
211 if (flags & VB_FLAG_VIDEO) != 0 {
212 std::mem::swap(&mut self.cur_frame, &mut self.prev_frame);
214 let vsize = br.read_u32le()? as u64;
215 validate!(vsize > 4);
216 let end = br.tell() + vsize - 4;
218 ftype = decode_video8(br, &mut self.cur_frame, &self.prev_frame, self.width, [gmv_x, gmv_y])?;
220 validate!(br.tell() == end);
222 if (flags & VB_FLAG_PALETTE) != 0 {
223 let pal_size = br.read_u32le()? as usize;
224 validate!(pal_size > 6);
225 validate!(br.left() as usize >= pal_size - 4);
226 let start = br.read_byte()? as usize;
227 let mut size = br.read_byte()? as usize;
231 validate!(start + size <= 256);
232 validate!(size * 3 + 6 == pal_size);
233 br.read_buf(&mut self.pal[start * 3..][..size * 3])?;
236 let stride = vbuf.get_stride(0);
237 let pal_off = vbuf.get_offset(1);
238 let data = vbuf.get_data_mut().unwrap();
240 for (dline, sline) in data.chunks_mut(stride).zip(self.cur_frame.chunks(self.width)) {
241 dline[..self.width].copy_from_slice(sline);
243 data[pal_off..][..768].copy_from_slice(&self.pal);
250 prev_frame: Vec<u16>,
257 fn new(w: usize, h: usize) -> Self {
259 prev_frame: vec![0; w * h],
260 cur_frame: vec![0; w * h],
265 fn decode(&mut self, br: &mut ByteReader, vbuf: &mut NAVideoBufferRef<u16>) -> DecoderResult<FrameType> {
266 let flags = br.read_u16le()?;
267 let (gmv_x, gmv_y) = if (flags & VB_FLAG_GMC) != 0 {
268 let mvx = br.read_u16le()? as i16;
269 let mvy = br.read_u16le()? as i16;
274 if (flags & VB_FLAG_AUDIO) != 0 {
275 let asize = br.read_u32le()? as usize;
276 validate!(asize <= (br.left() as usize));
277 br.read_skip(asize - 4)?;
279 let mut ftype = FrameType::Skip;
280 if (flags & VB_FLAG_VIDEO) != 0 {
281 let vsize = br.read_u32le()? as u64;
282 validate!(vsize > 4);
283 let end = br.tell() + vsize - 4;
284 let has_pal = (flags & VB_FLAG_PALETTE) != 0;
286 let cur_off = br.tell();
287 br.seek(SeekFrom::Current((vsize - 4) as i64))?;
288 let psize = br.read_u32le()? as usize;
289 validate!(psize > 4 && psize <= 0x204 && (psize & 1) == 0);
290 for el in self.pal[..(psize - 4)/ 2].iter_mut() {
291 *el = br.read_u16le()?;
293 br.seek(SeekFrom::Start(cur_off))?;
296 std::mem::swap(&mut self.cur_frame, &mut self.prev_frame);
300 ftype = FrameType::I;
301 for (row_no, strip) in self.cur_frame.chunks_mut(self.width * 4).enumerate() {
302 for x in (0..self.width).step_by(4) {
304 btypes = br.read_byte()?;
307 match btypes & 0xC0 {
309 let t = br.read_byte()?;
310 let mut pattern = VB_PATTERNS[(t & 0x3F) as usize];
314 let mut clr = [0; 2];
316 clr[0] = self.pal[br.read_byte()? as usize];
317 clr[1] = self.pal[br.read_byte()? as usize];
319 clr[0] = br.read_u16le()?;
320 clr[1] = br.read_u16le()?;
322 for dline in strip[x..].chunks_mut(self.width).take(4) {
323 for el in dline[..4].iter_mut() {
324 *el = clr[(pattern & 1) as usize];
332 let clr = if has_pal {
333 self.pal[br.read_byte()? as usize]
338 if let Some(start) = check_size(x, row_no, gmv_x, gmv_y, self.width, self.prev_frame.len()) {
339 for (dline, sline) in strip[x..].chunks_mut(self.width).zip(self.prev_frame[start..].chunks(self.width)).take(4) {
340 for (dst, &src) in dline[..4].iter_mut().zip(sline.iter()) {
341 *dst = if (pattern & 1) != 0 { clr } else { src };
346 return Err(DecoderError::InvalidData);
348 ftype = FrameType::P;
352 let clr = if has_pal {
353 self.pal[br.read_byte()? as usize]
357 for dline in strip[x..].chunks_mut(self.width).take(4) {
358 for el in dline[..4].iter_mut() {
364 let mv = br.read_byte()?;
367 for dline in strip[x..].chunks_mut(self.width).take(4) {
368 for el in dline[..4].iter_mut() {
369 *el = self.pal[br.read_byte()? as usize];
373 for dline in strip[x..].chunks_mut(self.width).take(4) {
374 for el in dline[..4].iter_mut() {
375 *el = br.read_u16le()?;
380 let mvx = (((mv & 0xF) ^ 8) as i16) - 8;
381 let mvy = (((mv >> 4) ^ 8) as i16) - 8;
382 if let Some(start) = check_size(x, row_no, gmv_x + mvx, gmv_y + mvy, self.width, self.prev_frame.len()) {
383 for (dline, sline) in strip[x..].chunks_mut(self.width).zip(self.prev_frame[start..].chunks(self.width)).take(4) {
384 dline[..4].copy_from_slice(&sline[..4]);
387 return Err(DecoderError::InvalidData);
389 ftype = FrameType::P;
393 if let Some(start) = check_size(x, row_no, gmv_x, gmv_y, self.width, self.prev_frame.len()) {
394 for (dline, sline) in strip[x..].chunks_mut(self.width).zip(self.prev_frame[start..].chunks(self.width)).take(4) {
395 dline[..4].copy_from_slice(&sline[..4]);
398 return Err(DecoderError::InvalidData);
400 ftype = FrameType::P;
408 validate!(br.tell() == end);
410 if (flags & VB_FLAG_PALETTE) != 0 {
411 let psize = br.read_u32le()? as usize;
412 br.read_skip(psize - 4)?;
415 let stride = vbuf.get_stride(0);
416 let data = vbuf.get_data_mut().unwrap();
418 for (dline, sline) in data.chunks_mut(stride).zip(self.cur_frame.chunks(self.width)) {
419 dline[..self.width].copy_from_slice(sline);
433 struct BeamVideoDecoder {
434 info: NACodecInfoRef,
439 impl BeamVideoDecoder {
440 fn new(fcp: bool) -> Self {
442 info: NACodecInfoRef::default(),
443 data: FrameData::None,
449 impl NADecoder for BeamVideoDecoder {
450 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
451 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
452 let width = vinfo.get_width();
453 let height = vinfo.get_height();
454 validate!((width & 3) == 0 && (height & 3) == 0);
455 let fmt = match vinfo.bits {
457 let edata = info.get_extradata();
458 validate!(edata.is_some());
459 let edata = edata.unwrap();
460 validate!(edata.len() >= 2);
461 let flags = read_u16le(&edata)?;
462 self.data = FrameData::Old(OldData::new(width, height, flags));
466 self.data = FrameData::Pal(Data8::new(width, height));
470 self.data = FrameData::New(Data16::new(width, height));
473 _ => return Err(DecoderError::InvalidData),
476 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt));
477 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
481 Err(DecoderError::InvalidData)
484 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
485 let src = pkt.get_buffer();
486 validate!(src.len() > 1);
488 let mut mr = MemoryReader::new_read(&src);
489 let mut br = ByteReader::new(&mut mr);
491 let mut bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
493 let ftype = match (&mut self.data, &mut bufinfo) {
494 (FrameData::Old(ref mut data), NABufferType::Video(ref mut vbuf)) => data.decode(&mut br, vbuf)?,
495 (FrameData::Pal(ref mut data), NABufferType::Video(ref mut vbuf)) => data.decode(&mut br, vbuf)?,
496 (FrameData::New(ref mut data), NABufferType::Video16(ref mut vbuf)) => data.decode(&mut br, vbuf)?,
500 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
501 frm.set_keyframe(ftype == FrameType::I);
502 frm.set_frame_type(ftype);
505 fn flush(&mut self) {
509 impl NAOptionHandler for BeamVideoDecoder {
510 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
511 fn set_options(&mut self, _options: &[NAOption]) { }
512 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
515 pub fn get_decoder_vbv() -> Box<dyn NADecoder + Send> {
516 Box::new(BeamVideoDecoder::new(false))
519 pub fn get_decoder_fcp() -> Box<dyn NADecoder + Send> {
520 Box::new(BeamVideoDecoder::new(true))
525 use nihav_core::codecs::RegisteredDecoders;
526 use nihav_core::demuxers::RegisteredDemuxers;
527 use nihav_codec_support::test::dec_video::*;
528 use crate::game_register_all_decoders;
529 use crate::game_register_all_demuxers;
532 let mut dmx_reg = RegisteredDemuxers::new();
533 game_register_all_demuxers(&mut dmx_reg);
534 let mut dec_reg = RegisteredDecoders::new();
535 game_register_all_decoders(&mut dec_reg);
537 // sample from The Dame was Loaded
538 test_decoding("siff", "beam-fcp", "assets/Game/siff/BEAM.FCP", Some(1000), &dmx_reg, &dec_reg,
539 ExpectedTestResult::MD5Frames(vec![
540 [0xa31342c0, 0x7afe5a76, 0x4111f17a, 0x30ec3a18],
541 [0xa31342c0, 0x7afe5a76, 0x4111f17a, 0x30ec3a18],
542 [0xa31342c0, 0x7afe5a76, 0x4111f17a, 0x30ec3a18],
543 [0xa31342c0, 0x7afe5a76, 0x4111f17a, 0x30ec3a18],
544 [0xa31342c0, 0x7afe5a76, 0x4111f17a, 0x30ec3a18],
545 [0x447870bf, 0x9bb22dab, 0x1f557dae, 0xc41575ad],
546 [0xeb3bd749, 0xc72811d3, 0x23d430b2, 0xc31dbd85],
547 [0x34bb16b4, 0x8e6066fe, 0xf3f6170a, 0xae4ec54e],
548 [0xee12f3ff, 0x4000ed43, 0x446336d7, 0x6cc344bf],
549 [0xfe6ba9e1, 0xcc97f503, 0xf6fc8f14, 0x40c334c0],
550 [0xb4229527, 0x8591ac0b, 0x1ba40ea8, 0x15aa5710]]));
553 fn test_beam_video_8bit() {
554 let mut dmx_reg = RegisteredDemuxers::new();
555 game_register_all_demuxers(&mut dmx_reg);
556 let mut dec_reg = RegisteredDecoders::new();
557 game_register_all_decoders(&mut dec_reg);
559 // sample from Lost Vikings 2
560 test_decoding("siff", "beam-video", "assets/Game/siff/BEAM.VB", Some(1000), &dmx_reg, &dec_reg,
561 ExpectedTestResult::MD5Frames(vec![
562 [0x23604e03, 0x5781ea8a, 0x6b28d338, 0xc32d52d6],
563 [0xba68d1af, 0xacf630b7, 0x3899073d, 0x07135315],
564 [0xb10cd159, 0xd787a566, 0x523123ca, 0x8a757f9e],
565 [0x7f4dfb53, 0x581884ab, 0x71de61c0, 0xfec72a11],
566 [0xc2a40282, 0x729548e1, 0xc63211bf, 0x586158fc],
567 [0xb8bf753c, 0x53686fb2, 0x7d307625, 0xdab70698],
568 [0xa2e90475, 0x076ef58a, 0xe2276941, 0x9c47ca14],
569 [0x80f785df, 0x19e015ab, 0x93beaf9b, 0xff1d0907],
570 [0x957a9a60, 0xc8a8ae09, 0xad5ecf6c, 0x06097f03],
571 [0xdfd331d4, 0x2f6ba92b, 0x5bfcb6f8, 0x85bab2b9],
572 [0xf37d42c1, 0x7f54d6bd, 0xc2dca688, 0x60d64e8c],
573 [0x97a0e18b, 0xce9ea101, 0x56eea57c, 0xeb48e8b3],
574 [0x7043048c, 0x373fdf9d, 0x1b27d5b3, 0x3e4e9c7a]]));
577 fn test_beam_video_16bit() {
578 let mut dmx_reg = RegisteredDemuxers::new();
579 game_register_all_demuxers(&mut dmx_reg);
580 let mut dec_reg = RegisteredDecoders::new();
581 game_register_all_decoders(&mut dec_reg);
583 // sample from Alien Earth
584 test_decoding("siff", "beam-video", "assets/Game/siff/beamlogo.vbc", Some(500), &dmx_reg, &dec_reg,
585 ExpectedTestResult::MD5Frames(vec![
586 [0x90aeded9, 0x922cf894, 0x6ea78586, 0x35493724],
587 [0x90aeded9, 0x922cf894, 0x6ea78586, 0x35493724],
588 [0xa19daf5e, 0xa4858d72, 0x6700fc4d, 0x95c5e5dd],
589 [0x57d556af, 0x95c5c5f4, 0xe943f1e3, 0xb86941e1],
590 [0xa63351ae, 0x12ed21ee, 0x7246d1f4, 0xf3a5a79a],
591 [0x5930e388, 0x4891d37b, 0x619ea7ff, 0xc8dac16d],
592 [0x36eeaf75, 0x767e5e5e, 0x397e0100, 0xfa306811],
593 [0xb4722a6d, 0x61cc8483, 0xe4966f11, 0xa67cd0f4],
594 [0x62be7367, 0xcbeb77b2, 0xcb438480, 0xda39b47a],
595 [0x568b020d, 0x4992bc7f, 0xcbe20b5c, 0x697a35bc],
596 [0x35e5a6a8, 0x903c0d07, 0xbacf7734, 0xd1c54b6d],
597 [0xd3450588, 0xfae0a9ec, 0x72a8fce6, 0x7c57e3c1],
598 [0x90f0cc47, 0xd7e7d3ef, 0x46d81b4d, 0xf4495aa2]]));
602 const VB_PATTERNS: [u16; 64] = [
603 0x0660, 0xFF00, 0xCCCC, 0xF000, 0x8888, 0x000F, 0x1111, 0xFEC8,
604 0x8CEF, 0x137F, 0xF731, 0xC800, 0x008C, 0x0013, 0x3100, 0xCC00,
605 0x00CC, 0x0033, 0x3300, 0x0FF0, 0x6666, 0x00F0, 0x0F00, 0x2222,
606 0x4444, 0xF600, 0x8CC8, 0x006F, 0x1331, 0x318C, 0xC813, 0x33CC,
607 0x6600, 0x0CC0, 0x0066, 0x0330, 0xF900, 0xC88C, 0x009F, 0x3113,
608 0x6000, 0x0880, 0x0006, 0x0110, 0xCC88, 0xFC00, 0x00CF, 0x88CC,
609 0x003F, 0x1133, 0x3311, 0xF300, 0x6FF6, 0x0603, 0x08C6, 0x8C63,
610 0xC631, 0x6310, 0xC060, 0x0136, 0x136C, 0x36C8, 0x6C80, 0x324C