support raw video in ARMovie
[nihav.git] / nihav-acorn / src / codecs / rawvideo.rs
CommitLineData
722b2933
KS
1use nihav_core::codecs::*;
2use nihav_core::io::byteio::*;
3use nihav_core::io::bitreader::*;
4
5use super::RGB555_FORMAT;
6use super::yuvtab::YUV2RGB;
7
8const YUV422_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::
9YUV(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
18trait ReadYUV5 {
19 fn read_y(&mut self) -> DecoderResult<u8>;
20 fn read_uv(&mut self) -> DecoderResult<u8>;
21}
22
23impl<'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)]
41struct RawDecoder {
42 info: NACodecInfoRef,
43 width: usize,
44 height: usize,
45 is_yuv: bool,
46 codec_id: u16,
47}
48
49impl RawDecoder {
50 fn new() -> Self { Self::default() }
51}
52
53impl 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
173impl 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
179pub fn get_decoder() -> Box<dyn NADecoder + Send> {
180 Box::new(RawDecoder::new())
181}
182
183#[derive(Default)]
184struct RawPacketiser {
185 stream: Option<NAStreamRef>,
186 buf: Vec<u8>,
187 frameno: u32,
188 size: usize,
189}
190
191impl RawPacketiser {
192 fn new() -> Self { Self::default() }
193}
194
195impl 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 };
216println!(" raw frame size {}", self.size);
217 }
218 }
219 self.stream = Some(stream);
220 }
221 fn add_data(&mut self, src: &[u8]) -> bool {
222 self.buf.extend_from_slice(src);
223 self.buf.len() < (1 << 10)
224 }
225 fn parse_stream(&mut self, id: u32) -> DecoderResult<NAStreamRef> {
226 if let Some(ref stream) = self.stream {
227 let mut stream = NAStream::clone(stream);
228 stream.id = id;
229 Ok(stream.into_ref())
230 } else {
231 Err(DecoderError::MissingReference)
232 }
233 }
234 fn skip_junk(&mut self) -> DecoderResult<usize> {
235 Err(DecoderError::NotImplemented)
236 }
237 fn get_packet(&mut self, stream: NAStreamRef) -> DecoderResult<Option<NAPacket>> {
238 if self.size == 0 {
239 return Err(DecoderError::MissingReference);
240 }
241 if self.buf.len() < self.size {
242 return Ok(None);
243 }
244
245 let mut data = Vec::with_capacity(self.size);
246 data.extend_from_slice(&self.buf[..self.size]);
247 self.buf.drain(..self.size);
248
249 let ts = NATimeInfo::new(Some(u64::from(self.frameno)), None, None, stream.tb_num, stream.tb_den);
250 self.frameno += 1;
251
252 Ok(Some(NAPacket::new(stream, ts, true, data)))
253 }
254 fn reset(&mut self) {
255 self.buf.clear();
256 }
257 fn bytes_left(&self) -> usize { self.buf.len() }
258}
259
260pub fn get_packetiser() -> Box<dyn NAPacketiser + Send> {
261 Box::new(RawPacketiser::new())
262}
263
264#[cfg(test)]
265mod test {
266 use nihav_core::codecs::{RegisteredDecoders, RegisteredPacketisers};
267 use nihav_core::demuxers::RegisteredRawDemuxers;
268 use nihav_codec_support::test::dec_video::*;
269 use crate::*;
270
271 #[test]
272 fn test_format2() {
273 let mut dmx_reg = RegisteredRawDemuxers::new();
274 acorn_register_all_raw_demuxers(&mut dmx_reg);
275 let mut pkt_reg = RegisteredPacketisers::new();
276 acorn_register_all_packetisers(&mut pkt_reg);
277 let mut dec_reg = RegisteredDecoders::new();
278 acorn_register_all_decoders(&mut dec_reg);
279
280 // a sample from Acorn Replay Demonstration Disc 2
281 test_decoding_raw("armovie", "arm_rawvideo", "assets/Acorn/ROBIN2", Some(1),
282 &dmx_reg, &pkt_reg, &dec_reg,
283 ExpectedTestResult::MD5Frames(vec![
284 [0x9a452976, 0x5fa64428, 0x71172412, 0x6db21372],
285 [0xabc70d88, 0x2431a96b, 0xfc8d58a6, 0xef1bb1c9]]));
286 }
287
288 #[test]
289 fn test_format3() {
290 let mut dmx_reg = RegisteredRawDemuxers::new();
291 acorn_register_all_raw_demuxers(&mut dmx_reg);
292 let mut pkt_reg = RegisteredPacketisers::new();
293 acorn_register_all_packetisers(&mut pkt_reg);
294 let mut dec_reg = RegisteredDecoders::new();
295 acorn_register_all_decoders(&mut dec_reg);
296
297 // a sample from Cine Clips by Oregan Software Developments
298 test_decoding_raw("armovie", "arm_rawvideo", "assets/Acorn/TROPICLSUN", Some(1),
299 &dmx_reg, &pkt_reg, &dec_reg,
300 ExpectedTestResult::MD5Frames(vec![
301 [0xcd5fe3d0, 0x60454448, 0x9f91180a, 0x8e73370d],
302 [0x148b07bb, 0xbf647ddd, 0x2bf8c9e5, 0x4b37122a]]));
303 }
304
305 #[test]
306 fn test_format5() {
307 let mut dmx_reg = RegisteredRawDemuxers::new();
308 acorn_register_all_raw_demuxers(&mut dmx_reg);
309 let mut pkt_reg = RegisteredPacketisers::new();
310 acorn_register_all_packetisers(&mut pkt_reg);
311 let mut dec_reg = RegisteredDecoders::new();
312 acorn_register_all_decoders(&mut dec_reg);
313
314 // a sample from Empire video editor demo
315 test_decoding_raw("armovie", "arm_rawvideo", "assets/Acorn/CLIP3", Some(1),
316 &dmx_reg, &pkt_reg, &dec_reg,
317 ExpectedTestResult::MD5Frames(vec![
318 [0x816ccb08, 0x5e86539c, 0x1bb51e98, 0x849936c4],
319 [0xa42cf122, 0x296f3825, 0xedb7f0fc, 0x25a7825e]]));
320 }
321}