]> git.nihav.org Git - nihav.git/blame_incremental - nihav-flash/src/codecs/flashsv.rs
switch some TableCodebookDescReader use cases to closures
[nihav.git] / nihav-flash / src / codecs / flashsv.rs
... / ...
CommitLineData
1use nihav_core::frame::*;
2use nihav_core::codecs::*;
3use nihav_core::io::byteio::*;
4use nihav_core::compr::deflate::*;
5
6#[derive(Default)]
7struct FSVShuffler {
8 lastframe: Option<NAVideoBufferRef<u8>>,
9 keyframe: Option<NAVideoBufferRef<u8>>,
10}
11
12impl FSVShuffler {
13 fn new() -> Self { Self::default() }
14 fn clear(&mut self) {
15 self.keyframe = None;
16 self.lastframe = None;
17 }
18 fn add_frame(&mut self, buf: NAVideoBufferRef<u8>) {
19 self.lastframe = Some(buf);
20 }
21 fn add_keyframe(&mut self, buf: NAVideoBufferRef<u8>) {
22 self.keyframe = Some(buf);
23 }
24 fn clone_ref(&mut self) -> Option<NAVideoBufferRef<u8>> {
25 if let Some(ref mut frm) = self.lastframe {
26 let newfrm = frm.copy_buffer();
27 *frm = newfrm.clone().into_ref();
28 Some(newfrm.into_ref())
29 } else {
30 None
31 }
32 }
33 fn has_last_frame(&self) -> bool { self.lastframe.is_some() }
34 fn get_key_frame(&mut self) -> Option<NAVideoBufferRef<u8>> {
35 self.keyframe.as_ref().cloned()
36 }
37 /*fn get_last_frame(&mut self) -> Option<NAVideoBufferRef<u8>> {
38 self.lastframe.as_ref().cloned()
39 }*/
40}
41
42
43struct FSVDecoder {
44 info: NACodecInfoRef,
45 shuf: FSVShuffler,
46 w: usize,
47 h: usize,
48 block_w: usize,
49 block_h: usize,
50 ver1: bool,
51 has_pal: bool,
52 has_ifrm: bool,
53 tile: Vec<u8>,
54 cbuf: [u8; 65536],
55 pal: [u8; 128 * 3],
56 inflate: Inflate,
57 kdata: Vec<u8>,
58 bpos: Vec<usize>,
59 bsize: Vec<usize>,
60}
61
62impl FSVDecoder {
63 fn new(ver1: bool) -> Self {
64 Self {
65 info: NACodecInfo::new_dummy(),
66 shuf: FSVShuffler::new(),
67 w: 0,
68 h: 0,
69 block_w: 0,
70 block_h: 0,
71 ver1,
72 has_pal: false,
73 has_ifrm: false,
74 tile: Vec::new(),
75 cbuf: [0; 65536],
76 pal: DEFAULT_PAL,
77 inflate: Inflate::new(),
78 kdata: Vec::new(),
79 bpos: Vec::new(),
80 bsize: Vec::new(),
81 }
82 }
83 fn decode_v1(&mut self, br: &mut ByteReader, data: &mut [u8], stride: usize) -> DecoderResult<bool> {
84 let mut is_intra = true;
85 for (yy, row) in data.chunks_mut(stride * self.block_h).enumerate() {
86 let cur_h = (self.h - yy * self.block_h).min(self.block_h);
87 for x in (0..self.w).step_by(self.block_w) {
88 let cur_w = (self.w - x).min(self.block_w);
89
90 let data_size = br.read_u16be()? as usize;
91 if data_size > 0 {
92 br.read_buf(&mut self.cbuf[..data_size])?;
93 self.inflate = Inflate::new();
94 if self.inflate.decompress_block(&self.cbuf[..data_size], &mut self.tile[..cur_w * cur_h * 3]).is_err() {
95 return Err(DecoderError::InvalidData);
96 }
97 for (dst, src) in row[x * 3..].chunks_mut(stride).zip(self.tile.chunks(cur_w * 3)) {
98 dst[..cur_w * 3].copy_from_slice(src);
99 }
100 } else {
101 is_intra = false;
102 }
103 }
104 }
105 Ok(is_intra)
106 }
107 fn decode_v2(&mut self, br: &mut ByteReader, data: &mut [u8], stride: usize, keyframe: bool) -> DecoderResult<bool> {
108 let mut is_intra = !self.has_ifrm;
109 let bstride = (self.w + self.block_w - 1) / self.block_w;
110 for y in (0..self.h).step_by(self.block_h) {
111 let cur_h = (self.h - y).min(self.block_h);
112 for x in (0..self.w).step_by(self.block_w) {
113 let cur_w = (self.w - x).min(self.block_w);
114
115 let mut data_size = br.read_u16be()? as usize;
116 validate!(!keyframe || data_size > 0);
117 if data_size == 0 {
118 is_intra = false;
119 continue;
120 }
121 let blk_start = br.tell();
122 let flags = br.read_byte()?;
123 let depth = (flags >> 3) & 3;
124 validate!(depth == 0 || depth == 2);
125 let has_diff = (flags & 4) != 0;
126 let cpriming = (flags & 2) != 0;
127 let ppriming = (flags & 1) != 0;
128 let (start, height) = if has_diff {
129 let start = br.read_byte()? as usize;
130 let height = br.read_byte()? as usize;
131 validate!(start + height <= cur_h);
132 (start, height)
133 } else {
134 (0, cur_h)
135 };
136 if has_diff {
137 let ret = self.shuf.get_key_frame();
138 if ret.is_none() {
139 return Err(DecoderError::MissingReference);
140 }
141 let src = ret.unwrap();
142 let src = src.get_data();
143 for (dst, src) in data[x * 3 + y * stride..].chunks_mut(stride).take(cur_h).zip(src[x * 3 + y * stride..].chunks(stride)) {
144 dst[..cur_w * 3].copy_from_slice(&src[..cur_w * 3]);
145 }
146 }
147 if height != cur_h {
148 is_intra = false;
149 }
150 let ppos = if cpriming {
151 let xpos = br.read_byte()? as usize;
152 let ypos = br.read_byte()? as usize;
153 xpos + ypos * bstride
154 } else {
155 x / self.block_w + y / self.block_h * bstride
156 };
157 data_size -= (br.tell() - blk_start) as usize;
158 if keyframe {
159 self.bpos.push(br.tell() as usize);
160 self.bsize.push(data_size);
161 }
162 if data_size > 0 {
163 br.read_buf(&mut self.cbuf[..data_size])?;
164 self.inflate = Inflate::new();
165 if cpriming || ppriming {
166 if self.bpos.is_empty() {
167 return Err(DecoderError::MissingReference);
168 }
169 let ret = self.inflate.decompress_block(&self.kdata[self.bpos[ppos]..][..self.bsize[ppos]], &mut self.tile);
170 if ret.is_err() {
171 return Err(DecoderError::InvalidData);
172 }
173 let ssize = ret.unwrap();
174 self.inflate = Inflate::new();
175 self.inflate.set_dict(&self.tile[..ssize]);
176 }
177 let ret = self.inflate.decompress_block(&self.cbuf[..data_size], &mut self.tile[..cur_w * height * 3]);
178 if ret.is_err() {
179 return Err(DecoderError::InvalidData);
180 }
181 let src_len = ret.unwrap();
182
183 let dst = &mut data[x * 3 + y * stride..];
184 match depth {
185 0 => {
186 validate!(src_len == cur_w * cur_h * 3);
187 for (dst, src) in dst.chunks_mut(stride).skip(start).take(height).zip(self.tile.chunks(cur_w * 3)) {
188 dst[..cur_w * 3].copy_from_slice(src);
189 }
190 },
191 2 => {
192 let mut mr = MemoryReader::new_read(&self.tile[..src_len]);
193 let mut br = ByteReader::new(&mut mr);
194 for line in dst.chunks_mut(stride).skip(start).take(height) {
195 for rgb in line.chunks_mut(3).take(cur_w) {
196 let b = br.read_byte()?;
197 if (b & 0x80) == 0 {
198 rgb.copy_from_slice(&self.pal[(b as usize) * 3..][..3]);
199 } else {
200 let c = br.read_byte()?;
201 let clr = (u16::from(b & 0x7F) << 8) | u16::from(c);
202 let r = (clr >> 10) as u8;
203 let g = ((clr >> 5) & 0x1F) as u8;
204 let b = (clr & 0x1F) as u8;
205 rgb[0] = (r << 3) | (r >> 2);
206 rgb[1] = (g << 3) | (g >> 2);
207 rgb[2] = (b << 3) | (b >> 2);
208 }
209 }
210 }
211 },
212 _ => unreachable!(),
213 };
214 } else {
215 is_intra = false;
216 }
217 }
218 }
219 if self.has_ifrm {
220unimplemented!();
221 }
222 Ok(is_intra)
223 }
224}
225
226impl NADecoder for FSVDecoder {
227 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
228 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
229 let w = vinfo.get_width();
230 let h = vinfo.get_height();
231 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, true, BGR24_FORMAT));
232 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
233
234 Ok(())
235 } else {
236 Err(DecoderError::InvalidData)
237 }
238 }
239 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
240 let src = pkt.get_buffer();
241
242 validate!(src.len() > 4);
243 let mut mr = MemoryReader::new_read(&src);
244 let mut br = ByteReader::new(&mut mr);
245
246 let hdr0 = br.read_u16be()? as usize;
247 let hdr1 = br.read_u16be()? as usize;
248 let w = hdr0 & 0xFFF;
249 let h = hdr1 & 0xFFF;
250 let blk_w = (hdr0 >> 12) * 16 + 16;
251 let blk_h = (hdr1 >> 12) * 16 + 16;
252 validate!(w != 0 && h != 0 && blk_w != 0 && blk_h != 0);
253
254 if !self.ver1 {
255 let flags = br.read_byte()?;
256 self.has_pal = (flags & 1) != 0;
257 self.has_ifrm = (flags & 2) != 0;
258 if self.has_pal {
259 let pal_sz = br.read_u16be()? as usize;
260 br.read_buf(&mut self.cbuf[..pal_sz])?;
261 self.inflate = Inflate::new();
262 if self.inflate.decompress_block(&self.cbuf[..pal_sz], &mut self.pal).is_err() {
263 return Err(DecoderError::InvalidData);
264 }
265 }
266 if pkt.keyframe {
267 self.kdata.clear();
268 self.kdata.extend_from_slice(&src);
269 self.bpos.clear();
270 self.bsize.clear();
271 }
272 }
273 if self.w != w || self.h != h || self.block_w != blk_w || self.block_h != blk_h {
274 self.flush();
275 self.tile.resize(blk_w * blk_h * 3, 0);
276 self.w = w;
277 self.h = h;
278 self.block_w = blk_w;
279 self.block_h = blk_h;
280 }
281
282 let mut buf = if let Some(buffer) = self.shuf.clone_ref() {
283 buffer
284 } else {
285 let vinfo = self.info.get_properties().get_video_info().unwrap();
286 let bufinfo = alloc_video_buffer(vinfo, 0)?;
287 bufinfo.get_vbuf().unwrap()
288 };
289 let stride = buf.get_stride(0);
290 let data = buf.get_data_mut().unwrap();
291 let is_intra = if self.ver1 {
292 self.decode_v1(&mut br, data, stride)?
293 } else {
294 self.decode_v2(&mut br, data, stride, pkt.keyframe)?
295 };
296
297 if !is_intra && !self.shuf.has_last_frame() {
298 return Err(DecoderError::MissingReference);
299 }
300
301 if pkt.is_keyframe() {
302 self.shuf.add_keyframe(buf.clone());
303 }
304 self.shuf.add_frame(buf.clone());
305
306 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::VideoPacked(buf));
307 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
308 Ok(frm.into_ref())
309 }
310 fn flush(&mut self) {
311 self.shuf.clear();
312 }
313}
314
315impl NAOptionHandler for FSVDecoder {
316 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
317 fn set_options(&mut self, _options: &[NAOption]) { }
318 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
319}
320
321pub fn get_decoder() -> Box<dyn NADecoder + Send> {
322 Box::new(FSVDecoder::new(true))
323}
324
325pub fn get_decoder_v2() -> Box<dyn NADecoder + Send> {
326 Box::new(FSVDecoder::new(false))
327}
328
329#[cfg(test)]
330mod test {
331 use nihav_core::codecs::RegisteredDecoders;
332 use nihav_core::demuxers::RegisteredDemuxers;
333 use nihav_codec_support::test::dec_video::*;
334 use crate::flash_register_all_decoders;
335 use crate::flash_register_all_demuxers;
336 #[test]
337 fn test_flashsv1() {
338 let mut dmx_reg = RegisteredDemuxers::new();
339 flash_register_all_demuxers(&mut dmx_reg);
340 let mut dec_reg = RegisteredDecoders::new();
341 flash_register_all_decoders(&mut dec_reg);
342
343 // sample: https://samples.mplayerhq.hu/FLV/flash_screen/screen.flv
344 test_decoding("flv", "flashsv", "assets/Flash/screen.flv",
345 Some(3000), &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
346 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
347 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
348 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
349 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
350 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
351 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
352 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
353 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
354 [0xc04d4d1c, 0xbb1f4b4f, 0xe9f3d85e, 0xa40aff68],
355 [0x172e5bbe, 0xe44caba3, 0x6cb2a263, 0xcb79a89a]]));
356 }
357 #[test]
358 fn test_flashsv2() {
359 let mut dmx_reg = RegisteredDemuxers::new();
360 flash_register_all_demuxers(&mut dmx_reg);
361 let mut dec_reg = RegisteredDecoders::new();
362 flash_register_all_decoders(&mut dec_reg);
363
364 // sample created from https://samples.mplayerhq.hu/FLV/flash_screen/screen.flv by recoding
365 test_decoding("flv", "flashsv2", "assets/Flash/screen2.flv",
366 Some(4700), &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
367 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
368 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
369 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
370 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
371 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
372 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
373 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
374 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
375 [0x9809efc2, 0xec5385aa, 0xb5eb9320, 0x4a47188e],
376 [0x40c77877, 0x58183722, 0x5700eb17, 0x27a00e33],
377 [0x802c2c6a, 0x3e08dd62, 0xa6c94df3, 0xc6318a6f],
378 [0x2aa70255, 0x652f0ca4, 0xe79817f9, 0x4f67e7ba],
379 [0x5cf34d91, 0xdfc54992, 0x4368180d, 0xfbe747d4],
380 [0x266d8bc4, 0x2b492ef4, 0xb42401a0, 0x23e530ec],
381 [0xa0e46b1c, 0x47d0620e, 0x0cbcb15b, 0x243e7f13]]));
382 }
383}
384
385const DEFAULT_PAL: [u8; 128 * 3] = [
386 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x99, 0x99, 0x99,
387 0xCC, 0xCC, 0xCC, 0xFF, 0xFF, 0xFF, 0x33, 0x00, 0x00, 0x66, 0x00, 0x00,
388 0x99, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x33, 0x00,
389 0x00, 0x66, 0x00, 0x00, 0x99, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xFF, 0x00,
390 0x00, 0x00, 0x33, 0x00, 0x00, 0x66, 0x00, 0x00, 0x99, 0x00, 0x00, 0xCC,
391 0x00, 0x00, 0xFF, 0x33, 0x33, 0x00, 0x66, 0x66, 0x00, 0x99, 0x99, 0x00,
392 0xCC, 0xCC, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x33, 0x33, 0x00, 0x66, 0x66,
393 0x00, 0x99, 0x99, 0x00, 0xCC, 0xCC, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x33,
394 0x66, 0x00, 0x66, 0x99, 0x00, 0x99, 0xCC, 0x00, 0xCC, 0xFF, 0x00, 0xFF,
395 0xFF, 0xFF, 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC,
396 0xFF, 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC, 0xFF,
397 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC, 0xFF, 0xFF,
398 0xCC, 0xCC, 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF,
399 0xCC, 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF, 0xCC,
400 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF, 0xCC, 0xCC,
401 0x99, 0x99, 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF,
402 0x99, 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF, 0x99,
403 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF, 0x99, 0x99,
404 0x66, 0x66, 0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF,
405 0x66, 0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF, 0x66,
406 0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF, 0x66, 0x66,
407 0x33, 0x33, 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF,
408 0x33, 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF, 0x33,
409 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF, 0x33, 0x33,
410 0x00, 0x33, 0x66, 0x33, 0x66, 0x00, 0x66, 0x00, 0x33, 0x00, 0x66, 0x33,
411 0x33, 0x00, 0x66, 0x66, 0x33, 0x00, 0x33, 0x66, 0x99, 0x66, 0x99, 0x33,
412 0x99, 0x33, 0x66, 0x33, 0x99, 0x66, 0x66, 0x33, 0x99, 0x99, 0x66, 0x33,
413 0x66, 0x99, 0xCC, 0x99, 0xCC, 0x66, 0xCC, 0x66, 0x99, 0x66, 0xCC, 0x99,
414 0x99, 0x66, 0xCC, 0xCC, 0x99, 0x66, 0x99, 0xCC, 0xFF, 0xCC, 0xFF, 0x99,
415 0xFF, 0x99, 0xCC, 0x99, 0xFF, 0xCC, 0xCC, 0x99, 0xFF, 0xFF, 0xCC, 0x99,
416 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x55, 0x55, 0x55,
417 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xDD, 0xDD, 0xDD, 0xEE, 0xEE, 0xEE
418];
419
420const BGR24_FORMAT: NAPixelFormaton = NAPixelFormaton {
421 model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
422 comp_info: [
423 Some(NAPixelChromaton{
424 h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 3 }),
425 Some(NAPixelChromaton{
426 h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 3 }),
427 Some(NAPixelChromaton{
428 h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 3 }),
429 None, None],
430 elem_size: 3, be: false, alpha: false, palette: false
431};