]>
Commit | Line | Data |
---|---|---|
1 | use nihav_core::codecs::*; | |
2 | ||
3 | struct RawDecoder { | |
4 | info: NACodecInfoRef, | |
5 | pal: [u8; 768], | |
6 | } | |
7 | ||
8 | impl RawDecoder { | |
9 | fn new() -> Self { | |
10 | Self { | |
11 | info: NACodecInfo::new_dummy(), | |
12 | pal: [0; 768], | |
13 | } | |
14 | } | |
15 | } | |
16 | ||
17 | impl NADecoder for RawDecoder { | |
18 | fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { | |
19 | if let NACodecTypeInfo::Video(_vinfo) = info.get_properties() { | |
20 | self.info = info.clone(); | |
21 | Ok(()) | |
22 | } else { | |
23 | Err(DecoderError::InvalidData) | |
24 | } | |
25 | } | |
26 | fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> { | |
27 | if let NACodecTypeInfo::Video(ref vinfo) = self.info.get_properties() { | |
28 | let src = pkt.get_buffer(); | |
29 | let width = vinfo.width; | |
30 | let height = vinfo.height; | |
31 | if !vinfo.format.model.is_rgb() { | |
32 | return Err(DecoderError::InvalidData); | |
33 | } | |
34 | let depth = if vinfo.format.is_paletted() { 8 } else { vinfo.format.get_total_depth() } as usize; | |
35 | let buf = match depth { | |
36 | 8 => { | |
37 | for sd in pkt.side_data.iter() { | |
38 | match *sd { | |
39 | NASideData::Palette(_, ref pal) => { | |
40 | for (dst, src) in self.pal.chunks_mut(3).zip(pal.chunks(4)) { | |
41 | dst[0] = src[0]; | |
42 | dst[1] = src[1]; | |
43 | dst[2] = src[2]; | |
44 | } | |
45 | break; | |
46 | }, | |
47 | _ => {}, | |
48 | }; | |
49 | } | |
50 | ||
51 | let sstride = (vinfo.width + 3) & !3; | |
52 | ||
53 | let buf = alloc_video_buffer(*vinfo, 0)?; | |
54 | ||
55 | let mut frm = buf.get_vbuf().unwrap(); | |
56 | let dstride = frm.get_stride(0); | |
57 | let paloff = frm.get_offset(1); | |
58 | let dst = frm.get_data_mut().unwrap(); | |
59 | for (drow, srow) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(height) { | |
60 | drow[..width].copy_from_slice(&srow[..width]); | |
61 | } | |
62 | dst[paloff..][..768].copy_from_slice(&self.pal); | |
63 | ||
64 | buf | |
65 | }, | |
66 | 15 | 16 => { | |
67 | let sstride = (vinfo.width * 2 + 3) & !3; | |
68 | ||
69 | let buf = alloc_video_buffer(*vinfo, 0)?; | |
70 | ||
71 | let mut frm = buf.get_vbuf16().unwrap(); | |
72 | let dstride = frm.get_stride(0); | |
73 | let dst = frm.get_data_mut().unwrap(); | |
74 | ||
75 | for (drow, srow) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(height) { | |
76 | for (dp, sp) in drow.iter_mut().zip(srow.chunks_exact(2)).take(width) { | |
77 | *dp = u16::from(sp[0]) | (u16::from(sp[1]) << 8); | |
78 | } | |
79 | } | |
80 | ||
81 | buf | |
82 | }, | |
83 | 24 | 32 => { | |
84 | let ncomp = vinfo.format.components as usize; | |
85 | let sstride = (width * (depth / 8) + 3) & !3; | |
86 | let offs = vec![0; ncomp]; | |
87 | let mut strides = vec![0; ncomp]; | |
88 | strides[0] = sstride; | |
89 | NABufferType::VideoPacked(NAVideoBuffer::from_raw_parts(*vinfo, src, offs, strides).into_ref()) | |
90 | }, | |
91 | _ => return Err(DecoderError::NotImplemented), | |
92 | }; | |
93 | ||
94 | let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buf); | |
95 | frm.set_keyframe(true); | |
96 | frm.set_frame_type(FrameType::I); | |
97 | Ok(frm.into_ref()) | |
98 | } else { | |
99 | Err(DecoderError::Bug) | |
100 | } | |
101 | } | |
102 | fn flush(&mut self) {} | |
103 | } | |
104 | ||
105 | ||
106 | impl NAOptionHandler for RawDecoder { | |
107 | fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } | |
108 | fn set_options(&mut self, _options: &[NAOption]) { } | |
109 | fn query_option_value(&self, _name: &str) -> Option<NAValue> { None } | |
110 | } | |
111 | ||
112 | pub fn get_decoder() -> Box<dyn NADecoder + Send> { | |
113 | Box::new(RawDecoder::new()) | |
114 | } | |
115 | ||
116 | #[cfg(test)] | |
117 | mod test { | |
118 | use nihav_core::codecs::RegisteredDecoders; | |
119 | use nihav_core::demuxers::RegisteredDemuxers; | |
120 | use nihav_codec_support::test::dec_video::*; | |
121 | use crate::generic_register_all_decoders; | |
122 | use crate::generic_register_all_demuxers; | |
123 | #[test] | |
124 | fn test_rawvideo_ms_8() { | |
125 | let mut dmx_reg = RegisteredDemuxers::new(); | |
126 | generic_register_all_demuxers(&mut dmx_reg); | |
127 | let mut dec_reg = RegisteredDecoders::new(); | |
128 | generic_register_all_decoders(&mut dec_reg); | |
129 | // sample: https://samples.mplayerhq.hu/V-codecs/Uncompressed/8bpp.avi | |
130 | test_decoding("avi", "rawvideo-ms", "assets/Misc/8bpp.avi", Some(0), &dmx_reg, | |
131 | &dec_reg, ExpectedTestResult::MD5([0xb6629439, 0x6ea482e9, 0x42c84d7c, 0x46c94431])); | |
132 | } | |
133 | #[test] | |
134 | fn test_rawvideo_ms_16() { | |
135 | let mut dmx_reg = RegisteredDemuxers::new(); | |
136 | generic_register_all_demuxers(&mut dmx_reg); | |
137 | let mut dec_reg = RegisteredDecoders::new(); | |
138 | generic_register_all_decoders(&mut dec_reg); | |
139 | // sample: https://samples.mplayerhq.hu/V-codecs/Uncompressed/16bpp.avi | |
140 | test_decoding("avi", "rawvideo-ms", "assets/Misc/16bpp.avi", Some(0), &dmx_reg, | |
141 | &dec_reg, ExpectedTestResult::MD5([0xe80e16a1, 0x2d50659e, 0x413d24af, 0xea3bee05])); | |
142 | } | |
143 | #[test] | |
144 | fn test_rawvideo_ms_24() { | |
145 | let mut dmx_reg = RegisteredDemuxers::new(); | |
146 | generic_register_all_demuxers(&mut dmx_reg); | |
147 | let mut dec_reg = RegisteredDecoders::new(); | |
148 | generic_register_all_decoders(&mut dec_reg); | |
149 | // sample:https://samples.mplayerhq.hu/V-codecs/Uncompressed/keve.avi | |
150 | test_decoding("avi", "rawvideo-ms", "assets/Misc/keve.avi", Some(0), &dmx_reg, | |
151 | &dec_reg, ExpectedTestResult::MD5([0x9514ac1f, 0x4512cc62, 0x069485ba, 0x084a1e63])); | |
152 | } | |
153 | #[test] | |
154 | fn test_rawvideo_ms_32() { | |
155 | let mut dmx_reg = RegisteredDemuxers::new(); | |
156 | generic_register_all_demuxers(&mut dmx_reg); | |
157 | let mut dec_reg = RegisteredDecoders::new(); | |
158 | generic_register_all_decoders(&mut dec_reg); | |
159 | // sample: https://samples.mplayerhq.hu/V-codecs/Uncompressed/Logo-Uncompressed.zip | |
160 | test_decoding("avi", "rawvideo-ms", "assets/Misc/VRMLuncompressed.avi", Some(0), &dmx_reg, | |
161 | &dec_reg, ExpectedTestResult::MD5([0xf4c9d468, 0x8f42c576, 0xc8eb522a, 0x75f654b1])); | |
162 | } | |
163 | } |