]>
Commit | Line | Data |
---|---|---|
722b2933 KS |
1 | use nihav_core::codecs::*; |
2 | use nihav_core::io::byteio::*; | |
3 | use nihav_core::io::bitreader::*; | |
4 | ||
5 | use super::RGB555_FORMAT; | |
6 | use super::yuvtab::YUV2RGB; | |
7 | ||
8 | const YUV422_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel:: | |
9 | YUV(YUVSubmodel::YUVJ), components: 3, | |
10 | comp_info: [ | |
11 | Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: false, depth: 8, shift: 0, comp_offs: 0, next_elem: 1}), | |
12 | Some(NAPixelChromaton{ h_ss: 1, v_ss: 0, packed: false, depth: 8, shift: 0, comp_offs: 1, next_elem: 1}), | |
13 | Some(NAPixelChromaton{ h_ss: 1, v_ss: 0, packed: false, depth: 8, shift: 0, comp_offs: 2, next_elem: 1}), | |
14 | None, None], | |
15 | elem_size: 0, be: false, alpha: false, palette: false }; | |
16 | ||
17 | ||
18 | trait ReadYUV5 { | |
19 | fn read_y(&mut self) -> DecoderResult<u8>; | |
20 | fn read_uv(&mut self) -> DecoderResult<u8>; | |
21 | } | |
22 | ||
23 | impl<'a> ReadYUV5 for BitReader<'a> { | |
24 | fn read_y(&mut self) -> DecoderResult<u8> { | |
25 | let v = self.read(5)? as u8; | |
26 | Ok((v << 3) | (v >> 2)) | |
27 | } | |
28 | fn read_uv(&mut self) -> DecoderResult<u8> { | |
29 | const EXPAND: [u8; 16] = [ | |
30 | 0x00, 0x08, 0x11, 0x19, 0x22, 0x2A, 0x33, 0x3B, 0x44, 0x4C, 0x55, 0x5D, 0x66, 0x6E, 0x77, 0x7F]; | |
31 | let v = self.read(5)? as u8; | |
32 | if v < 16 { | |
33 | Ok(EXPAND[v as usize] | 0x80) | |
34 | } else { | |
35 | Ok(EXPAND[(v & 0xF) as usize]) | |
36 | } | |
37 | } | |
38 | } | |
39 | ||
40 | #[derive(Default)] | |
41 | struct RawDecoder { | |
42 | info: NACodecInfoRef, | |
43 | width: usize, | |
44 | height: usize, | |
45 | is_yuv: bool, | |
46 | codec_id: u16, | |
47 | } | |
48 | ||
49 | impl RawDecoder { | |
50 | fn new() -> Self { Self::default() } | |
51 | } | |
52 | ||
53 | impl NADecoder for RawDecoder { | |
54 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
55 | if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { | |
56 | self.width = vinfo.get_width(); | |
57 | self.height = vinfo.get_height(); | |
58 | validate!(info.get_extradata().is_some()); | |
59 | ||
60 | if let Some(edata) = info.get_extradata() { | |
61 | validate!(edata.len() > 1); | |
62 | self.codec_id = u16::from(edata[0]) + 256 * u16::from(edata[1]); | |
63 | ||
64 | for triplet in edata.windows(3) { | |
65 | if triplet == b"YUV" { | |
66 | self.is_yuv = true; | |
67 | break; | |
68 | } | |
69 | } | |
70 | } else { | |
71 | return Err(DecoderError::InvalidData); | |
72 | } | |
73 | ||
74 | let fmt = match self.codec_id { | |
75 | 2 => RGB555_FORMAT, | |
76 | 3 if self.is_yuv => { | |
77 | validate!((self.width & 1) == 0); | |
78 | YUV422_FORMAT | |
79 | }, | |
80 | 5 if self.is_yuv => { | |
81 | validate!((self.width & 1) == 0); | |
82 | validate!((self.height & 1) == 0); | |
83 | YUV420_FORMAT | |
84 | }, | |
85 | _ => return Err(DecoderError::NotImplemented), | |
86 | }; | |
87 | ||
88 | let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt)); | |
89 | self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); | |
90 | ||
91 | Ok(()) | |
92 | } else { | |
93 | Err(DecoderError::InvalidData) | |
94 | } | |
95 | } | |
96 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
97 | let src = pkt.get_buffer(); | |
98 | validate!(src.len() > 1); | |
99 | ||
100 | let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?; | |
101 | match self.codec_id { | |
102 | 2 => { | |
103 | let mut mr = MemoryReader::new_read(&src); | |
104 | let mut br = ByteReader::new(&mut mr); | |
105 | ||
106 | let mut buf = bufinfo.get_vbuf16().unwrap(); | |
107 | let stride = buf.get_stride(0); | |
108 | let data = buf.get_data_mut().unwrap(); | |
109 | ||
110 | for dline in data.chunks_exact_mut(stride).take(self.height) { | |
111 | for el in dline[..self.width].iter_mut().take(self.width) { | |
112 | *el = br.read_u16le()?; | |
113 | if self.is_yuv { | |
114 | *el = YUV2RGB[(*el as usize) & 0x7FFF]; | |
115 | } | |
116 | } | |
117 | } | |
118 | }, | |
119 | 3 => { | |
120 | let mut br = BitReader::new(&src, BitReaderMode::LE); | |
121 | let mut buf = bufinfo.get_vbuf().unwrap(); | |
122 | let dst = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); | |
123 | ||
124 | let mut yoff = dst.offset[0]; | |
125 | let mut uoff = dst.offset[1]; | |
126 | let mut voff = dst.offset[2]; | |
127 | for _y in 0..self.height { | |
128 | for x in (0..self.width).step_by(2) { | |
129 | dst.data[yoff + x] = br.read_y()?; | |
130 | dst.data[yoff + x + 1] = br.read_y()?; | |
131 | dst.data[uoff + x / 2] = br.read_uv()?; | |
132 | dst.data[voff + x / 2] = br.read_uv()?; | |
133 | } | |
134 | yoff += dst.stride[0]; | |
135 | uoff += dst.stride[1]; | |
136 | voff += dst.stride[2]; | |
137 | } | |
138 | }, | |
139 | 5 => { | |
140 | let mut br = BitReader::new(&src, BitReaderMode::LE); | |
141 | let mut buf = bufinfo.get_vbuf().unwrap(); | |
142 | let dst = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); | |
143 | ||
144 | let mut yoff = dst.offset[0]; | |
145 | let mut uoff = dst.offset[1]; | |
146 | let mut voff = dst.offset[2]; | |
147 | for _y in (0..self.height).step_by(2) { | |
148 | for x in (0..self.width).step_by(2) { | |
149 | dst.data[yoff + x] = br.read_y()?; | |
150 | dst.data[yoff + x + 1] = br.read_y()?; | |
151 | dst.data[yoff + x + dst.stride[0]] = br.read_y()?; | |
152 | dst.data[yoff + x + dst.stride[0] + 1] = br.read_y()?; | |
153 | dst.data[uoff + x / 2] = br.read_uv()?; | |
154 | dst.data[voff + x / 2] = br.read_uv()?; | |
155 | br.skip(2)?; | |
156 | } | |
157 | yoff += dst.stride[0] * 2; | |
158 | uoff += dst.stride[1]; | |
159 | voff += dst.stride[2]; | |
160 | } | |
161 | }, | |
162 | _ => unreachable!(), | |
163 | } | |
164 | ||
165 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); | |
166 | frm.set_keyframe(true); | |
167 | frm.set_frame_type(FrameType::I); | |
168 | Ok(frm.into_ref()) | |
169 | } | |
170 | fn flush(&mut self) {} | |
171 | } | |
172 | ||
173 | impl NAOptionHandler for RawDecoder { | |
174 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
175 | fn set_options(&mut self, _options: &[NAOption]) { } | |
176 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
177 | } | |
178 | ||
179 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
180 | Box::new(RawDecoder::new()) | |
181 | } | |
182 | ||
183 | #[derive(Default)] | |
184 | struct RawPacketiser { | |
185 | stream: Option<NAStreamRef>, | |
186 | buf: Vec<u8>, | |
187 | frameno: u32, | |
188 | size: usize, | |
189 | } | |
190 | ||
191 | impl RawPacketiser { | |
192 | fn new() -> Self { Self::default() } | |
193 | } | |
194 | ||
195 | impl NAPacketiser for RawPacketiser { | |
196 | fn attach_stream(&mut self, stream: NAStreamRef) { | |
197 | let vinfo = stream.get_info().get_properties().get_video_info().unwrap(); | |
198 | let width = vinfo.width; | |
199 | let height = vinfo.height; | |
200 | if let Some(edata) = stream.get_info().get_extradata() { | |
201 | if edata.len() > 1 { | |
202 | let codec_id = u16::from(edata[0]) + 256 * u16::from(edata[1]); | |
203 | /*let mut is_yuv = false; | |
204 | for triplet in edata.windows(3) { | |
205 | if triplet == b"YUV" { | |
206 | is_yuv = true; | |
207 | break; | |
208 | } | |
209 | }*/ | |
210 | self.size = match codec_id { | |
211 | 2 => width * height * 2, | |
212 | 3 => width * height * 10 / 8, | |
213 | 5 => width * height, | |
214 | _ => unimplemented!(), | |
215 | }; | |
722b2933 KS |
216 | } |
217 | } | |
218 | self.stream = Some(stream); | |
219 | } | |
220 | fn add_data(&mut self, src: &[u8]) -> bool { | |
221 | self.buf.extend_from_slice(src); | |
222 | self.buf.len() < (1 << 10) | |
223 | } | |
224 | fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> { | |
225 | if let Some(ref stream) = self.stream { | |
226 | let mut stream = NAStream::clone(stream); | |
227 | stream.id = id; | |
228 | Ok(stream.into_ref()) | |
229 | } else { | |
230 | Err(DecoderError::MissingReference) | |
231 | } | |
232 | } | |
233 | fn skip_junk(&mut self) -> DecoderResult<usize> { | |
234 | Err(DecoderError::NotImplemented) | |
235 | } | |
236 | fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> { | |
237 | if self.size == 0 { | |
238 | return Err(DecoderError::MissingReference); | |
239 | } | |
240 | if self.buf.len() < self.size { | |
241 | return Ok(None); | |
242 | } | |
243 | ||
244 | let mut data = Vec::with_capacity(self.size); | |
245 | data.extend_from_slice(&self.buf[..self.size]); | |
246 | self.buf.drain(..self.size); | |
247 | ||
248 | let ts = NATimeInfo::new(Some(u64::from(self.frameno)), None, None, stream.tb_num, stream.tb_den); | |
249 | self.frameno += 1; | |
250 | ||
251 | Ok(Some(NAPacket::new(stream, ts, true, data))) | |
252 | } | |
253 | fn reset(&mut self) { | |
254 | self.buf.clear(); | |
255 | } | |
256 | fn bytes_left(&self) -> usize { self.buf.len() } | |
257 | } | |
258 | ||
259 | pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> { | |
260 | Box::new(RawPacketiser::new()) | |
261 | } | |
262 | ||
263 | #[cfg(test)] | |
264 | mod test { | |
265 | use nihav_core::codecs::{RegisteredDecoders, RegisteredPacketisers}; | |
266 | use nihav_core::demuxers::RegisteredRawDemuxers; | |
267 | use nihav_codec_support::test::dec_video::*; | |
268 | use crate::*; | |
269 | ||
270 | #[test] | |
271 | fn test_format2() { | |
272 | let mut dmx_reg = RegisteredRawDemuxers::new(); | |
273 | acorn_register_all_raw_demuxers(&mut dmx_reg); | |
274 | let mut pkt_reg = RegisteredPacketisers::new(); | |
275 | acorn_register_all_packetisers(&mut pkt_reg); | |
276 | let mut dec_reg = RegisteredDecoders::new(); | |
277 | acorn_register_all_decoders(&mut dec_reg); | |
278 | ||
279 | // a sample from Acorn Replay Demonstration Disc 2 | |
280 | test_decoding_raw("armovie", "arm_rawvideo", "assets/Acorn/ROBIN2", Some(1), | |
281 | &dmx_reg, &pkt_reg, &dec_reg, | |
282 | ExpectedTestResult::MD5Frames(vec![ | |
283 | [0x9a452976, 0x5fa64428, 0x71172412, 0x6db21372], | |
284 | [0xabc70d88, 0x2431a96b, 0xfc8d58a6, 0xef1bb1c9]])); | |
285 | } | |
286 | ||
287 | #[test] | |
288 | fn test_format3() { | |
289 | let mut dmx_reg = RegisteredRawDemuxers::new(); | |
290 | acorn_register_all_raw_demuxers(&mut dmx_reg); | |
291 | let mut pkt_reg = RegisteredPacketisers::new(); | |
292 | acorn_register_all_packetisers(&mut pkt_reg); | |
293 | let mut dec_reg = RegisteredDecoders::new(); | |
294 | acorn_register_all_decoders(&mut dec_reg); | |
295 | ||
296 | // a sample from Cine Clips by Oregan Software Developments | |
297 | test_decoding_raw("armovie", "arm_rawvideo", "assets/Acorn/TROPICLSUN", Some(1), | |
298 | &dmx_reg, &pkt_reg, &dec_reg, | |
299 | ExpectedTestResult::MD5Frames(vec![ | |
300 | [0xcd5fe3d0, 0x60454448, 0x9f91180a, 0x8e73370d], | |
301 | [0x148b07bb, 0xbf647ddd, 0x2bf8c9e5, 0x4b37122a]])); | |
302 | } | |
303 | ||
304 | #[test] | |
305 | fn test_format5() { | |
306 | let mut dmx_reg = RegisteredRawDemuxers::new(); | |
307 | acorn_register_all_raw_demuxers(&mut dmx_reg); | |
308 | let mut pkt_reg = RegisteredPacketisers::new(); | |
309 | acorn_register_all_packetisers(&mut pkt_reg); | |
310 | let mut dec_reg = RegisteredDecoders::new(); | |
311 | acorn_register_all_decoders(&mut dec_reg); | |
312 | ||
313 | // a sample from Empire video editor demo | |
314 | test_decoding_raw("armovie", "arm_rawvideo", "assets/Acorn/CLIP3", Some(1), | |
315 | &dmx_reg, &pkt_reg, &dec_reg, | |
316 | ExpectedTestResult::MD5Frames(vec![ | |
317 | [0x816ccb08, 0x5e86539c, 0x1bb51e98, 0x849936c4], | |
318 | [0xa42cf122, 0x296f3825, 0xedb7f0fc, 0x25a7825e]])); | |
319 | } | |
320 | } |