make all codec crates export just register_all functions and document them
[nihav.git] / nihav-game / src / codecs / midivid.rs
CommitLineData
801bba83
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3
4#[derive(Default)]
5struct MidividDecoder {
6 info: NACodecInfoRef,
7 hams: HAMShuffler,
8 lzbuf: Vec<u8>,
9 width: usize,
10 height: usize,
11}
12
13impl MidividDecoder {
14 fn new() -> Self {
15 Self::default()
16 }
17}
18
19fn lz_decompress(src: &[u8], dst: &mut [u8]) -> DecoderResult<()> {
20 let mut spos = 0;
21 let mut dpos = 0;
22 let end = src.len();
23 while spos < end {
24 let oplo = src[spos] as u16;
25 spos += 1;
26 if spos >= end { return Err(DecoderError::ShortData); }
27 let ophi = src[spos] as u16;
28 spos += 1;
29 let mut op = (ophi << 8) | oplo;
30 for _ in 0..16 {
31 if spos >= end { return Ok(()); }
32 let b = src[spos];
33 spos += 1;
34
35 if (op & 1) == 0 {
36 validate!(dpos < dst.len());
37 dst[dpos] = b;
38 dpos += 1;
39 } else {
40 validate!(spos < end);
41 let bb = src[spos];
42 spos += 1;
43
44 let offset = (((b as usize) & 0xF0) << 4) | (bb as usize);
45 let copy_len = ((b & 0xF) as usize) + 3;
46 validate!(offset <= dpos);
47 validate!(offset > 0);
48 validate!(dpos + copy_len <= dst.len());
49 for _ in 0..copy_len {
50 dst[dpos] = dst[dpos - offset];
51 dpos += 1;
52 }
53 }
54 op >>= 1;
55 }
56 }
57 Ok(())
58}
59
60fn decode_frame(frm: &mut NASimpleVideoFrame<u8>, src: &[u8], width: usize, height: usize) -> DecoderResult<bool> {
61 validate!(src.len() > 8);
62 let num_vec = read_u16le(&src[0..])? as usize;
63 validate!(num_vec <= 512);
64 let is_intra = read_u16le(&src[2..])? == 1;
65
66 let (vecs, nblocks, idx_start) = if is_intra {
67 (&src[4..], width / 2 * height / 2, num_vec * 12 + 4)
68 } else {
69 let num_blocks = read_u32le(&src[4..])? as usize;
70 let changeset_size = (width >> 5) * (height >> 2);
71 (&src[8+changeset_size..], num_blocks, num_vec * 12 + 8 + changeset_size)
72 };
73 validate!(src.len() > idx_start);
74
75 let src1 = if num_vec > 256 { &src[idx_start + (nblocks + 7)/8..] } else { &src[idx_start..] };
76 let mut mr = MemoryReader::new_read(src1);
77 let mut idx_br = ByteReader::new(&mut mr);
78 let mut mr = MemoryReader::new_read(&src[idx_start..]);
79 let mut idx9_br = ByteReader::new(&mut mr);
80 let mut hi9 = 0u8;
81 let mut bits = 0u8;
82 for y in (0..height).step_by(2) {
83 for x in (0..width).step_by(2) {
84 if !is_intra {
85 let x4 = x >> 2;
86 let flag_b = src[8 + x4/8 + (y/4) * ((width + 31) >> 5)];
87 if ((flag_b >> (x4 & 7)) & 1) == 0 {
88 continue;
89 }
90 }
91 let idx = if num_vec <= 256 {
92 idx_br.read_byte()? as usize
93 } else {
94 if bits == 0 {
d24468d9 95 hi9 = idx9_br.read_byte()?;
801bba83
KS
96 bits = 8;
97 }
98 bits -= 1;
99 let lo = idx_br.read_byte()? as usize;
100
101 ((((hi9 >> (7 - bits)) & 1) as usize) << 8) | lo
102 };
103 validate!(idx < num_vec);
104 let vec = &vecs[idx * 12..];
105
106 for comp in 0..3 {
107 let dst = &mut frm.data[frm.offset[comp] + x + y * frm.stride[comp]..];
108 dst[0] = vec[0 + comp];
109 dst[1] = vec[3 + comp];
110 dst[frm.stride[comp] + 0] = vec[6 + comp];
111 dst[frm.stride[comp] + 1] = vec[9 + comp];
112 }
113 }
114 }
d24468d9 115
801bba83
KS
116 Ok(is_intra)
117}
118
119impl NADecoder for MidividDecoder {
120 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
121 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
122 let fmt = NAPixelFormaton::new(ColorModel::YUV(YUVSubmodel::YCbCr),
123 Some(NAPixelChromaton::new(0, 0, false, 8, 0, 0, 1)),
124 Some(NAPixelChromaton::new(0, 0, false, 8, 0, 1, 1)),
125 Some(NAPixelChromaton::new(0, 0, false, 8, 0, 2, 1)),
126 None, None, 0, 3);
127 self.width = vinfo.get_width();
128 self.height = vinfo.get_height();
129 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, fmt));
130 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
131 self.lzbuf = vec![0; self.width * self.height * 3];
132
133 Ok(())
134 } else {
135 Err(DecoderError::InvalidData)
136 }
137 }
138 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
139 let src = pkt.get_buffer();
140 validate!(src.len() > 4);
141
142 let size = read_u32le(&src[0..])? as usize;
143 validate!(size + 8 == src.len());
144 let data_ptr;
145 validate!(src.len() > 12);
146 if read_u32le(&src[8..])? == 0 {
147 lz_decompress(&src[12..], self.lzbuf.as_mut_slice())?;
148 data_ptr = self.lzbuf.as_slice();
149 } else {
150 data_ptr = &src[12..];
151 }
152
153 let mut buf;
154 let bufret = self.hams.clone_ref();
155 if let Some(bbuf) = bufret {
156 buf = bbuf;
157 } else {
158 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
159 buf = bufinfo.get_vbuf().unwrap();
160 self.hams.add_frame(buf);
161 buf = self.hams.get_output_frame().unwrap();
162 }
163
164 let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
165 let is_intra = decode_frame(&mut frm, data_ptr, self.width, self.height)?;
166
167 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
168 frm.set_keyframe(is_intra);
169 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
170 Ok(frm.into_ref())
171 }
f9be4e75
KS
172 fn flush(&mut self) {
173 self.hams.clear();
174 }
801bba83
KS
175}
176
177
08a1fab7 178pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
801bba83
KS
179 Box::new(MidividDecoder::new())
180}
181
182#[cfg(test)]
183mod test {
184 use nihav_core::codecs::RegisteredDecoders;
185 use nihav_core::demuxers::RegisteredDemuxers;
186 use nihav_core::test::dec_video::*;
e64739f8
KS
187 use crate::game_register_all_codecs;
188 use nihav_commonfmt::generic_register_all_demuxers;
801bba83
KS
189 #[test]
190 fn test_midivid_video() {
191 let mut dmx_reg = RegisteredDemuxers::new();
192 generic_register_all_demuxers(&mut dmx_reg);
193 let mut dec_reg = RegisteredDecoders::new();
194 game_register_all_codecs(&mut dec_reg);
195
196 let file = "assets/Game/MVDV.avi";
197 //let file = "assets/Game/bbglogo.avi";
198 //let file = "assets/Game/close.avi";
199 //let file = "assets/Game/inland.avi";
200 //let file = "assets/Game/midway.avi";
201 //let file = "assets/Game/midway.1.avi";
202 //let file = "assets/Game/open.avi";
203 test_file_decoding("avi", file, Some(16), true, false, None, &dmx_reg, &dec_reg);
204 }
205}