]>
Commit | Line | Data |
---|---|---|
e981a888 KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
3 | ||
4 | use super::RGB555_FORMAT; | |
5 | use super::yuvtab::YUV2RGB; | |
6 | ||
7 | const END_CODE: u16 = 0x7300; | |
8 | ||
9 | #[derive(Default)] | |
10 | struct MLDecoder { | |
11 | info: NACodecInfoRef, | |
12 | cur_frm: Vec<u16>, | |
13 | prev_frm: Vec<u16>, | |
14 | width: usize, | |
15 | is_yuv: bool, | |
16 | } | |
17 | ||
18 | impl MLDecoder { | |
19 | fn new() -> Self { Self::default() } | |
20 | } | |
21 | ||
22 | impl NADecoder for MLDecoder { | |
23 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
24 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
25 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, RGB555_FORMAT)); | |
26 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
27 | self.cur_frm = vec![0; vinfo.get_width() * vinfo.get_height()]; | |
28 | self.prev_frm = vec![0; vinfo.get_width() * vinfo.get_height()]; | |
29 | self.width = vinfo.get_width(); | |
30 | if let Some(edata) = info.get_extradata() { | |
31 | for triplet in edata.windows(3) { | |
32 | if triplet == b"YUV" { | |
33 | self.is_yuv = true; | |
34 | break; | |
35 | } | |
36 | } | |
37 | } | |
38 | Ok(()) | |
39 | } else { | |
40 | Err(DecoderError::InvalidData) | |
41 | } | |
42 | } | |
43 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
44 | let src = pkt.get_buffer(); | |
45 | validate!(src.len() > 2 && (src.len() & 1) == 0); | |
46 | let mut mr = MemoryReader::new_read(&src); | |
47 | let mut br = ByteReader::new(&mut mr); | |
48 | ||
49 | let mut is_intra = true; | |
50 | let mut dpos = 0; | |
51 | while dpos < self.cur_frm.len() { | |
52 | let op = br.read_u16le()?; | |
53 | let raw_flag = (op & 1) == 0; | |
54 | let val = op >> 1; | |
55 | if raw_flag { | |
56 | self.cur_frm[dpos] = val; | |
57 | dpos += 1; | |
58 | } else { | |
59 | match val { | |
60 | 0..=0x47FF => { // copy prev | |
61 | let len = ((val & 0x3F) + 2) as usize; | |
62 | validate!(dpos + len <= self.cur_frm.len()); | |
63 | ||
64 | let mut idx = (val >> 6) as isize; | |
65 | if idx >= 144 { // skip (0,0) | |
66 | idx += 1; | |
67 | } | |
68 | let dy = idx / 17 - 8; | |
69 | let dx = idx % 17 - 8; | |
70 | let spos = dpos as isize + dx + dy * (self.width as isize); | |
71 | validate!(spos >= 0); | |
72 | let mut spos = spos as usize; | |
73 | validate!(spos + len <= self.prev_frm.len()); | |
74 | ||
75 | for _ in 0..len { | |
76 | self.cur_frm[dpos] = self.prev_frm[spos]; | |
77 | dpos += 1; | |
78 | spos += 1; | |
79 | } | |
80 | ||
81 | is_intra = false; | |
82 | }, | |
83 | 0x4800..=0x72FF => { // copy cur | |
84 | let len = ((val & 0x3F) + 2) as usize; | |
85 | validate!(dpos + len <= self.cur_frm.len()); | |
86 | ||
87 | let idx = ((val >> 6) as usize) - 0x120; | |
88 | let dx = idx % 19; | |
89 | let dy = 9 - (idx / 19); | |
90 | validate!(dpos + dx >= dy * self.width + 9); | |
91 | let mut spos = dpos + dx - 9 - dy * self.width; | |
92 | ||
93 | for _ in 0..len { | |
94 | self.cur_frm[dpos] = self.cur_frm[spos]; | |
95 | dpos += 1; | |
96 | spos += 1; | |
97 | } | |
98 | }, | |
99 | END_CODE => break, // end of frame | |
100 | 0x7301..=0x77FF => { // run | |
101 | let len = ((val & 0x3F) + 2) as usize; | |
102 | let pix = br.read_u16le()?; | |
103 | validate!(dpos + len <= self.cur_frm.len()); | |
104 | for _ in 0..len { | |
105 | self.cur_frm[dpos] = pix; | |
106 | dpos += 1; | |
107 | } | |
108 | }, | |
109 | 0x7800..=0x7BFF => { // skip | |
110 | let len = ((val & 0x3FF) + 1) as usize; | |
111 | validate!(dpos + len <= self.cur_frm.len()); | |
112 | for _ in 0..len { | |
113 | self.cur_frm[dpos] = self.prev_frm[dpos]; | |
114 | dpos += 1; | |
115 | } | |
116 | is_intra = false; | |
117 | }, | |
118 | 0x7C00.. => { // raw | |
119 | let len = ((val & 0x3FF) + 1) as usize; | |
120 | validate!(dpos + len <= self.cur_frm.len()); | |
121 | let mut bitbuf = u32::from(br.read_u16le()?); | |
122 | let mut bits = 16; | |
123 | for _ in 0..len { | |
124 | if bits < 15 { | |
125 | bitbuf |= u32::from(br.read_u16le()?) << bits; | |
126 | bits += 16; | |
127 | } | |
128 | self.cur_frm[dpos] = (bitbuf & 0x7FFF) as u16; | |
129 | bitbuf >>= 15; | |
130 | bits -= 15; | |
131 | dpos += 1; | |
132 | } | |
133 | }, | |
134 | } | |
135 | } | |
136 | } | |
137 | validate!(br.left() == 2 && br.read_u16le()? == (END_CODE * 2 + 1)); | |
138 | ||
139 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?; | |
140 | let mut buf = bufinfo.get_vbuf16().unwrap(); | |
141 | let stride = buf.get_stride(0); | |
142 | let data = buf.get_data_mut().unwrap(); | |
143 | ||
144 | for (dline, sline) in data.chunks_exact_mut(stride) | |
145 | .zip(self.cur_frm.chunks_exact(self.width)) { | |
146 | dline[..self.width].copy_from_slice(sline); | |
147 | } | |
148 | if self.is_yuv { | |
149 | for el in data.iter_mut() { | |
150 | *el = YUV2RGB[(*el as usize) & 0x7FFF]; | |
151 | } | |
152 | } | |
153 | ||
154 | std::mem::swap(&mut self.cur_frm, &mut self.prev_frm); | |
155 | ||
156 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
157 | frm.set_keyframe(is_intra); | |
158 | frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); | |
159 | Ok(frm.into_ref()) | |
160 | } | |
161 | fn flush(&mut self) { | |
162 | for el in self.cur_frm.iter_mut() { | |
163 | *el = 0; | |
164 | } | |
165 | for el in self.prev_frm.iter_mut() { | |
166 | *el = 0; | |
167 | } | |
168 | } | |
169 | } | |
170 | ||
171 | impl NAOptionHandler for MLDecoder { | |
172 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
173 | fn set_options(&mut self, _options: &[NAOption]) { } | |
174 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
175 | } | |
176 | ||
177 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
178 | Box::new(MLDecoder::new()) | |
179 | } | |
180 | ||
181 | #[derive(Default)] | |
182 | struct MLPacketiser { | |
183 | stream: Option<NAStreamRef>, | |
184 | buf: Vec<u8>, | |
185 | end: usize, | |
186 | frameno: u32, | |
187 | intra: bool, | |
188 | } | |
189 | ||
190 | impl MLPacketiser { | |
191 | fn new() -> Self { Self::default() } | |
192 | } | |
193 | ||
194 | impl NAPacketiser for MLPacketiser { | |
195 | fn attach_stream(&mut self, stream: NAStreamRef) { | |
196 | self.stream = Some(stream); | |
197 | } | |
198 | fn add_data(&mut self, src: &[u8]) -> bool { | |
199 | self.buf.extend_from_slice(src); | |
200 | self.buf.len() < (1 << 10) | |
201 | } | |
202 | fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> { | |
203 | if let Some(ref stream) = self.stream { | |
204 | let mut stream = NAStream::clone(stream); | |
205 | stream.id = id; | |
206 | Ok(stream.into_ref()) | |
207 | } else { | |
208 | Err(DecoderError::MissingReference) | |
209 | } | |
210 | } | |
211 | fn skip_junk(&mut self) -> DecoderResult<usize> { | |
212 | Err(DecoderError::NotImplemented) | |
213 | } | |
214 | fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> { | |
215 | if self.buf.len() < self.end { | |
216 | return Ok(None); | |
217 | } | |
218 | ||
219 | if self.end == 0 { | |
220 | self.intra = true; | |
221 | } | |
222 | ||
223 | let mut found = false; | |
224 | while self.end + 2 <= self.buf.len() { | |
225 | let op = u16::from(self.buf[self.end + 1]) * 256 + u16::from(self.buf[self.end]); | |
226 | self.end += 2; | |
227 | ||
228 | if op == (END_CODE * 2 + 1) { | |
229 | found = true; | |
230 | break; | |
231 | } | |
232 | // run | |
233 | if ((op & 1) == 1) && (0xE603..=0xEFFF).contains(&op) { | |
234 | self.end += 2; | |
235 | } | |
236 | // raw data | |
237 | if ((op & 1) == 1) && (op > 0xF800) { | |
238 | let raw_size = (((op >> 1) & 0x3FF) + 1) as usize; | |
239 | self.end += ((raw_size * 15 + 15) & !15) >> 3; | |
240 | } | |
241 | // copy from previous frame | |
242 | if ((op & 1) == 1) && ((op < 0x9000) || (0xF001..=0xF7FF).contains(&op)) { | |
243 | self.intra = false; | |
244 | } | |
245 | } | |
246 | ||
247 | if found { | |
248 | let mut data = Vec::with_capacity(self.end); | |
249 | data.extend_from_slice(&self.buf[..self.end]); | |
250 | self.buf.drain(..self.end); | |
251 | let ts = NATimeInfo::new(Some(u64::from(self.frameno)), None, None, stream.tb_num, stream.tb_den); | |
252 | self.end = 0; | |
253 | self.frameno += 1; | |
254 | ||
255 | return Ok(Some(NAPacket::new(stream, ts, self.intra, data))); | |
256 | } | |
257 | ||
258 | Ok(None) | |
259 | } | |
260 | fn reset(&mut self) { | |
261 | self.buf.clear(); | |
262 | self.end = 0; | |
263 | } | |
264 | fn bytes_left(&self) -> usize { self.buf.len() } | |
265 | } | |
266 | ||
267 | pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> { | |
268 | Box::new(MLPacketiser::new()) | |
269 | } | |
270 | ||
271 | #[cfg(test)] | |
272 | mod test { | |
273 | use nihav_core::codecs::{RegisteredDecoders, RegisteredPacketisers}; | |
274 | use nihav_core::demuxers::RegisteredRawDemuxers; | |
275 | use nihav_codec_support::test::dec_video::*; | |
276 | use crate::*; | |
277 | #[test] | |
278 | fn test_movinglines() { | |
279 | let mut dmx_reg = RegisteredRawDemuxers::new(); | |
280 | acorn_register_all_raw_demuxers(&mut dmx_reg); | |
281 | let mut pkt_reg = RegisteredPacketisers::new(); | |
282 | acorn_register_all_packetisers(&mut pkt_reg); | |
283 | let mut dec_reg = RegisteredDecoders::new(); | |
284 | acorn_register_all_decoders(&mut dec_reg); | |
285 | ||
286 | // a sample from Acorn Replay Demonstration Disc 2 | |
287 | test_decoding_raw("armovie", "movinglines", "assets/Acorn/CHEMSET2", Some(3), | |
288 | &dmx_reg, &pkt_reg, &dec_reg, | |
289 | ExpectedTestResult::MD5Frames(vec![ | |
7f570da3 KS |
290 | [0x991f08b9, 0x5a1a8718, 0x2b52edd5, 0x446ba3aa], |
291 | [0x3721a673, 0x96e1cf7d, 0x4ea1f8b4, 0xfb2f0483], | |
292 | [0xe83f7fd1, 0xe80290be, 0x2eb5723e, 0x74a767cb], | |
293 | [0x3a69b78b, 0xc53c1356, 0xa4bf9f96, 0xaec1a38c]])); | |
e981a888 KS |
294 | } |
295 | } |