]> git.nihav.org Git - nihav.git/blame - nihav-game/src/codecs/midivid.rs
mov: support segmented files
[nihav.git] / nihav-game / src / codecs / midivid.rs
CommitLineData
801bba83
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
b4d5b851 3use nihav_codec_support::codecs::HAMShuffler;
801bba83
KS
4
5#[derive(Default)]
6struct MidividDecoder {
7 info: NACodecInfoRef,
8d7a1c5c 8 hams: HAMShuffler<u8>,
801bba83
KS
9 lzbuf: Vec<u8>,
10 width: usize,
11 height: usize,
12}
13
14impl MidividDecoder {
15 fn new() -> Self {
16 Self::default()
17 }
18}
19
20fn lz_decompress(src: &[u8], dst: &mut [u8]) -> DecoderResult<()> {
21 let mut spos = 0;
22 let mut dpos = 0;
23 let end = src.len();
24 while spos < end {
7450554d 25 let oplo = u16::from(src[spos]);
801bba83
KS
26 spos += 1;
27 if spos >= end { return Err(DecoderError::ShortData); }
7450554d 28 let ophi = u16::from(src[spos]);
801bba83
KS
29 spos += 1;
30 let mut op = (ophi << 8) | oplo;
31 for _ in 0..16 {
32 if spos >= end { return Ok(()); }
33 let b = src[spos];
34 spos += 1;
35
36 if (op & 1) == 0 {
37 validate!(dpos < dst.len());
38 dst[dpos] = b;
39 dpos += 1;
40 } else {
41 validate!(spos < end);
42 let bb = src[spos];
43 spos += 1;
44
45 let offset = (((b as usize) & 0xF0) << 4) | (bb as usize);
46 let copy_len = ((b & 0xF) as usize) + 3;
47 validate!(offset <= dpos);
48 validate!(offset > 0);
49 validate!(dpos + copy_len <= dst.len());
50 for _ in 0..copy_len {
51 dst[dpos] = dst[dpos - offset];
52 dpos += 1;
53 }
54 }
55 op >>= 1;
56 }
57 }
58 Ok(())
59}
60
7450554d 61#[allow(clippy::identity_op)]
801bba83
KS
62fn decode_frame(frm: &mut NASimpleVideoFrame<u8>, src: &[u8], width: usize, height: usize) -> DecoderResult<bool> {
63 validate!(src.len() > 8);
64 let num_vec = read_u16le(&src[0..])? as usize;
65 validate!(num_vec <= 512);
66 let is_intra = read_u16le(&src[2..])? == 1;
67
68 let (vecs, nblocks, idx_start) = if is_intra {
69 (&src[4..], width / 2 * height / 2, num_vec * 12 + 4)
70 } else {
71 let num_blocks = read_u32le(&src[4..])? as usize;
72 let changeset_size = (width >> 5) * (height >> 2);
73 (&src[8+changeset_size..], num_blocks, num_vec * 12 + 8 + changeset_size)
74 };
75 validate!(src.len() > idx_start);
76
77 let src1 = if num_vec > 256 { &src[idx_start + (nblocks + 7)/8..] } else { &src[idx_start..] };
78 let mut mr = MemoryReader::new_read(src1);
79 let mut idx_br = ByteReader::new(&mut mr);
80 let mut mr = MemoryReader::new_read(&src[idx_start..]);
81 let mut idx9_br = ByteReader::new(&mut mr);
82 let mut hi9 = 0u8;
83 let mut bits = 0u8;
84 for y in (0..height).step_by(2) {
85 for x in (0..width).step_by(2) {
86 if !is_intra {
87 let x4 = x >> 2;
88 let flag_b = src[8 + x4/8 + (y/4) * ((width + 31) >> 5)];
89 if ((flag_b >> (x4 & 7)) & 1) == 0 {
90 continue;
91 }
92 }
93 let idx = if num_vec <= 256 {
94 idx_br.read_byte()? as usize
95 } else {
96 if bits == 0 {
d24468d9 97 hi9 = idx9_br.read_byte()?;
801bba83
KS
98 bits = 8;
99 }
100 bits -= 1;
101 let lo = idx_br.read_byte()? as usize;
102
103 ((((hi9 >> (7 - bits)) & 1) as usize) << 8) | lo
104 };
105 validate!(idx < num_vec);
106 let vec = &vecs[idx * 12..];
107
108 for comp in 0..3 {
109 let dst = &mut frm.data[frm.offset[comp] + x + y * frm.stride[comp]..];
110 dst[0] = vec[0 + comp];
111 dst[1] = vec[3 + comp];
112 dst[frm.stride[comp] + 0] = vec[6 + comp];
113 dst[frm.stride[comp] + 1] = vec[9 + comp];
114 }
115 }
116 }
d24468d9 117
801bba83
KS
118 Ok(is_intra)
119}
120
121impl NADecoder for MidividDecoder {
122 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
123 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
124 let fmt = NAPixelFormaton::new(ColorModel::YUV(YUVSubmodel::YCbCr),
125 Some(NAPixelChromaton::new(0, 0, false, 8, 0, 0, 1)),
126 Some(NAPixelChromaton::new(0, 0, false, 8, 0, 1, 1)),
127 Some(NAPixelChromaton::new(0, 0, false, 8, 0, 2, 1)),
128 None, None, 0, 3);
129 self.width = vinfo.get_width();
130 self.height = vinfo.get_height();
131 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, true, fmt));
132 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
133 self.lzbuf = vec![0; self.width * self.height * 3];
134
135 Ok(())
136 } else {
137 Err(DecoderError::InvalidData)
138 }
139 }
140 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
141 let src = pkt.get_buffer();
142 validate!(src.len() > 4);
143
144 let size = read_u32le(&src[0..])? as usize;
145 validate!(size + 8 == src.len());
146 let data_ptr;
147 validate!(src.len() > 12);
148 if read_u32le(&src[8..])? == 0 {
149 lz_decompress(&src[12..], self.lzbuf.as_mut_slice())?;
150 data_ptr = self.lzbuf.as_slice();
151 } else {
152 data_ptr = &src[12..];
153 }
154
155 let mut buf;
156 let bufret = self.hams.clone_ref();
157 if let Some(bbuf) = bufret {
158 buf = bbuf;
159 } else {
160 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
161 buf = bufinfo.get_vbuf().unwrap();
162 self.hams.add_frame(buf);
163 buf = self.hams.get_output_frame().unwrap();
164 }
165
166 let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
167 let is_intra = decode_frame(&mut frm, data_ptr, self.width, self.height)?;
168
169 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
170 frm.set_keyframe(is_intra);
171 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
172 Ok(frm.into_ref())
173 }
f9be4e75
KS
174 fn flush(&mut self) {
175 self.hams.clear();
176 }
801bba83
KS
177}
178
7d57ae2f
KS
179impl NAOptionHandler for MidividDecoder {
180 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
181 fn set_options(&mut self, _options: &[NAOption]) { }
182 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
183}
184
801bba83 185
08a1fab7 186pub fn get_decoder_video() -> Box<dyn NADecoder + Send> {
801bba83
KS
187 Box::new(MidividDecoder::new())
188}
189
190#[cfg(test)]
191mod test {
192 use nihav_core::codecs::RegisteredDecoders;
193 use nihav_core::demuxers::RegisteredDemuxers;
ce742854 194 use nihav_codec_support::test::dec_video::*;
78fb6560 195 use crate::game_register_all_decoders;
e64739f8 196 use nihav_commonfmt::generic_register_all_demuxers;
801bba83
KS
197 #[test]
198 fn test_midivid_video() {
199 let mut dmx_reg = RegisteredDemuxers::new();
200 generic_register_all_demuxers(&mut dmx_reg);
201 let mut dec_reg = RegisteredDecoders::new();
78fb6560 202 game_register_all_decoders(&mut dec_reg);
801bba83 203
bb07b685
KS
204 test_decoding("avi", "midivid", "assets/Game/MVDV.avi", Some(16), &dmx_reg, &dec_reg,
205 ExpectedTestResult::MD5Frames(vec![
206 [0x383e1995, 0x32bf000d, 0x2067aa2e, 0x54425bd4],
207 [0x91d0bff6, 0x5106cb75, 0x463ba358, 0xdc17d126],
208 [0x4ce54833, 0xb4fd3e35, 0x639d3830, 0xb47f871b],
209 [0x7c0c5604, 0x3c89e3ff, 0x05ae09f5, 0x7b725143],
210 [0xc561ddd9, 0xa3515c8e, 0x6119b31a, 0xb1608e77],
211 [0xa49bb9aa, 0xaf57e55b, 0xf351d4b0, 0x6289cd91],
212 [0xc7add756, 0x45574231, 0x5f1d651b, 0x2ae29e0d],
213 [0x7dd57d54, 0x4ec83f80, 0xef2e870b, 0x6cc310fe],
214 [0xe9c5fed6, 0xa4a4bab2, 0x70f84ed6, 0xc9d8a010],
215 [0x586ba118, 0x623fd7b9, 0x480fe7ab, 0xa1a5ad6f]]));
801bba83
KS
216 }
217}