]> git.nihav.org Git - nihav.git/blob - nihav-flash/src/codecs/flashsv.rs
d2214878fffcf75a4c171bcb6b240cf3fa659a23
[nihav.git] / nihav-flash / src / codecs / flashsv.rs
1 use nihav_core::frame::*;
2 use nihav_core::codecs::*;
3 use nihav_core::io::byteio::*;
4 use nihav_core::compr::deflate::*;
5
6 #[derive(Default)]
7 struct FSVShuffler {
8 lastframe: Option<NAVideoBufferRef<u8>>,
9 keyframe: Option<NAVideoBufferRef<u8>>,
10 }
11
12 impl 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
43 struct 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
62 impl 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 dyn ByteIO, 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 dyn ByteIO, 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 br = MemoryReader::new_read(&self.tile[..src_len]);
193 for line in dst.chunks_mut(stride).skip(start).take(height) {
194 for rgb in line.chunks_mut(3).take(cur_w) {
195 let b = br.read_byte()?;
196 if (b & 0x80) == 0 {
197 rgb.copy_from_slice(&self.pal[(b as usize) * 3..][..3]);
198 } else {
199 let c = br.read_byte()?;
200 let clr = (u16::from(b & 0x7F) << 8) | u16::from(c);
201 let r = (clr >> 10) as u8;
202 let g = ((clr >> 5) & 0x1F) as u8;
203 let b = (clr & 0x1F) as u8;
204 rgb[0] = (r << 3) | (r >> 2);
205 rgb[1] = (g << 3) | (g >> 2);
206 rgb[2] = (b << 3) | (b >> 2);
207 }
208 }
209 }
210 },
211 _ => unreachable!(),
212 };
213 } else {
214 is_intra = false;
215 }
216 }
217 }
218 if self.has_ifrm {
219 unimplemented!();
220 }
221 Ok(is_intra)
222 }
223 }
224
225 impl NADecoder for FSVDecoder {
226 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
227 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
228 let w = vinfo.get_width();
229 let h = vinfo.get_height();
230 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, true, BGR24_FORMAT));
231 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
232
233 Ok(())
234 } else {
235 Err(DecoderError::InvalidData)
236 }
237 }
238 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
239 let src = pkt.get_buffer();
240
241 validate!(src.len() > 4);
242 let mut br = MemoryReader::new_read(&src);
243
244 let hdr0 = br.read_u16be()? as usize;
245 let hdr1 = br.read_u16be()? as usize;
246 let w = hdr0 & 0xFFF;
247 let h = hdr1 & 0xFFF;
248 let blk_w = (hdr0 >> 12) * 16 + 16;
249 let blk_h = (hdr1 >> 12) * 16 + 16;
250 validate!(w != 0 && h != 0 && blk_w != 0 && blk_h != 0);
251
252 if !self.ver1 {
253 let flags = br.read_byte()?;
254 self.has_pal = (flags & 1) != 0;
255 self.has_ifrm = (flags & 2) != 0;
256 if self.has_pal {
257 let pal_sz = br.read_u16be()? as usize;
258 br.read_buf(&mut self.cbuf[..pal_sz])?;
259 self.inflate = Inflate::new();
260 if self.inflate.decompress_block(&self.cbuf[..pal_sz], &mut self.pal).is_err() {
261 return Err(DecoderError::InvalidData);
262 }
263 }
264 if pkt.keyframe {
265 self.kdata.clear();
266 self.kdata.extend_from_slice(&src);
267 self.bpos.clear();
268 self.bsize.clear();
269 }
270 }
271 if self.w != w || self.h != h || self.block_w != blk_w || self.block_h != blk_h {
272 self.flush();
273 self.tile.resize(blk_w * blk_h * 3, 0);
274 self.w = w;
275 self.h = h;
276 self.block_w = blk_w;
277 self.block_h = blk_h;
278 }
279
280 let mut buf = if let Some(buffer) = self.shuf.clone_ref() {
281 buffer
282 } else {
283 let vinfo = self.info.get_properties().get_video_info().unwrap();
284 let bufinfo = alloc_video_buffer(vinfo, 0)?;
285 bufinfo.get_vbuf().unwrap()
286 };
287 let stride = buf.get_stride(0);
288 let data = buf.get_data_mut().unwrap();
289 let is_intra = if self.ver1 {
290 self.decode_v1(&mut br, data, stride)?
291 } else {
292 self.decode_v2(&mut br, data, stride, pkt.keyframe)?
293 };
294
295 if !is_intra && !self.shuf.has_last_frame() {
296 return Err(DecoderError::MissingReference);
297 }
298
299 if pkt.is_keyframe() {
300 self.shuf.add_keyframe(buf.clone());
301 }
302 self.shuf.add_frame(buf.clone());
303
304 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::VideoPacked(buf));
305 frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
306 Ok(frm.into_ref())
307 }
308 fn flush(&mut self) {
309 self.shuf.clear();
310 }
311 }
312
313 impl NAOptionHandler for FSVDecoder {
314 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
315 fn set_options(&mut self, _options: &[NAOption]) { }
316 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
317 }
318
319 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
320 Box::new(FSVDecoder::new(true))
321 }
322
323 pub fn get_decoder_v2() -> Box<dyn NADecoder + Send> {
324 Box::new(FSVDecoder::new(false))
325 }
326
327 #[cfg(test)]
328 mod test {
329 use nihav_core::codecs::RegisteredDecoders;
330 use nihav_core::demuxers::RegisteredDemuxers;
331 use nihav_codec_support::test::dec_video::*;
332 use crate::flash_register_all_decoders;
333 use crate::flash_register_all_demuxers;
334 #[test]
335 fn test_flashsv1() {
336 let mut dmx_reg = RegisteredDemuxers::new();
337 flash_register_all_demuxers(&mut dmx_reg);
338 let mut dec_reg = RegisteredDecoders::new();
339 flash_register_all_decoders(&mut dec_reg);
340
341 // sample: https://samples.mplayerhq.hu/FLV/flash_screen/screen.flv
342 test_decoding("flv", "flashsv", "assets/Flash/screen.flv",
343 Some(3000), &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
344 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
345 [0xb45b899e, 0x417b17d5, 0x7bfe898b, 0x026b289f],
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 [0xc04d4d1c, 0xbb1f4b4f, 0xe9f3d85e, 0xa40aff68],
353 [0x172e5bbe, 0xe44caba3, 0x6cb2a263, 0xcb79a89a]]));
354 }
355 #[test]
356 fn test_flashsv2() {
357 let mut dmx_reg = RegisteredDemuxers::new();
358 flash_register_all_demuxers(&mut dmx_reg);
359 let mut dec_reg = RegisteredDecoders::new();
360 flash_register_all_decoders(&mut dec_reg);
361
362 // sample created from https://samples.mplayerhq.hu/FLV/flash_screen/screen.flv by recoding
363 test_decoding("flv", "flashsv2", "assets/Flash/screen2.flv",
364 Some(4700), &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
365 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
366 [0x55522afa, 0x9c7dd794, 0xdd67aa2e, 0x8b8c525e],
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 [0x9809efc2, 0xec5385aa, 0xb5eb9320, 0x4a47188e],
374 [0x40c77877, 0x58183722, 0x5700eb17, 0x27a00e33],
375 [0x802c2c6a, 0x3e08dd62, 0xa6c94df3, 0xc6318a6f],
376 [0x2aa70255, 0x652f0ca4, 0xe79817f9, 0x4f67e7ba],
377 [0x5cf34d91, 0xdfc54992, 0x4368180d, 0xfbe747d4],
378 [0x266d8bc4, 0x2b492ef4, 0xb42401a0, 0x23e530ec],
379 [0xa0e46b1c, 0x47d0620e, 0x0cbcb15b, 0x243e7f13]]));
380 }
381 }
382
383 const DEFAULT_PAL: [u8; 128 * 3] = [
384 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x66, 0x66, 0x66, 0x99, 0x99, 0x99,
385 0xCC, 0xCC, 0xCC, 0xFF, 0xFF, 0xFF, 0x33, 0x00, 0x00, 0x66, 0x00, 0x00,
386 0x99, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x33, 0x00,
387 0x00, 0x66, 0x00, 0x00, 0x99, 0x00, 0x00, 0xCC, 0x00, 0x00, 0xFF, 0x00,
388 0x00, 0x00, 0x33, 0x00, 0x00, 0x66, 0x00, 0x00, 0x99, 0x00, 0x00, 0xCC,
389 0x00, 0x00, 0xFF, 0x33, 0x33, 0x00, 0x66, 0x66, 0x00, 0x99, 0x99, 0x00,
390 0xCC, 0xCC, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x33, 0x33, 0x00, 0x66, 0x66,
391 0x00, 0x99, 0x99, 0x00, 0xCC, 0xCC, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x33,
392 0x66, 0x00, 0x66, 0x99, 0x00, 0x99, 0xCC, 0x00, 0xCC, 0xFF, 0x00, 0xFF,
393 0xFF, 0xFF, 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC,
394 0xFF, 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC, 0xFF,
395 0x33, 0xFF, 0xFF, 0x66, 0xFF, 0xFF, 0x99, 0xFF, 0xFF, 0xCC, 0xFF, 0xFF,
396 0xCC, 0xCC, 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF,
397 0xCC, 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF, 0xCC,
398 0x33, 0xCC, 0xCC, 0x66, 0xCC, 0xCC, 0x99, 0xCC, 0xCC, 0xFF, 0xCC, 0xCC,
399 0x99, 0x99, 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF,
400 0x99, 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF, 0x99,
401 0x33, 0x99, 0x99, 0x66, 0x99, 0x99, 0xCC, 0x99, 0x99, 0xFF, 0x99, 0x99,
402 0x66, 0x66, 0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF,
403 0x66, 0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF, 0x66,
404 0x33, 0x66, 0x66, 0x99, 0x66, 0x66, 0xCC, 0x66, 0x66, 0xFF, 0x66, 0x66,
405 0x33, 0x33, 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF,
406 0x33, 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF, 0x33,
407 0x66, 0x33, 0x33, 0x99, 0x33, 0x33, 0xCC, 0x33, 0x33, 0xFF, 0x33, 0x33,
408 0x00, 0x33, 0x66, 0x33, 0x66, 0x00, 0x66, 0x00, 0x33, 0x00, 0x66, 0x33,
409 0x33, 0x00, 0x66, 0x66, 0x33, 0x00, 0x33, 0x66, 0x99, 0x66, 0x99, 0x33,
410 0x99, 0x33, 0x66, 0x33, 0x99, 0x66, 0x66, 0x33, 0x99, 0x99, 0x66, 0x33,
411 0x66, 0x99, 0xCC, 0x99, 0xCC, 0x66, 0xCC, 0x66, 0x99, 0x66, 0xCC, 0x99,
412 0x99, 0x66, 0xCC, 0xCC, 0x99, 0x66, 0x99, 0xCC, 0xFF, 0xCC, 0xFF, 0x99,
413 0xFF, 0x99, 0xCC, 0x99, 0xFF, 0xCC, 0xCC, 0x99, 0xFF, 0xFF, 0xCC, 0x99,
414 0x11, 0x11, 0x11, 0x22, 0x22, 0x22, 0x44, 0x44, 0x44, 0x55, 0x55, 0x55,
415 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xDD, 0xDD, 0xDD, 0xEE, 0xEE, 0xEE
416 ];
417
418 const BGR24_FORMAT: NAPixelFormaton = NAPixelFormaton {
419 model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
420 comp_info: [
421 Some(NAPixelChromaton{
422 h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 3 }),
423 Some(NAPixelChromaton{
424 h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 3 }),
425 Some(NAPixelChromaton{
426 h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 3 }),
427 None, None],
428 elem_size: 3, be: false, alpha: false, palette: false
429 };