1 use nihav_core::codecs::*;
2 use nihav_core::compr::deflate::{Deflate, DeflateMode, DeflateWriter};
3 use nihav_core::io::byteio::*;
5 const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
7 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
8 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }),
9 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }),
11 elem_size: 2, be: false, alpha: false, palette: false };
12 const RGB24_0_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
14 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 4 }),
15 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 4 }),
16 Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 4 }),
18 elem_size: 4, be: false, alpha: false, palette: false };
21 stream: Option<NAStreamRef>,
27 pkt: Option<NAPacket>,
42 fn buf_type_to_bpp(buf: &NABufferType) -> u8 {
44 NABufferType::Video(ref vbuf) => {
45 let vinfo = vbuf.get_info();
46 if vinfo.get_format().is_paletted() {
49 vinfo.get_format().get_total_depth()
52 NABufferType::VideoPacked(ref vbuf) => {
53 let vinfo = vbuf.get_info();
54 vinfo.get_format().elem_size * 8
56 NABufferType::Video16(ref vbuf) => {
57 let vinfo = vbuf.get_info();
58 vinfo.get_format().get_total_depth()
64 fn copy_frame(buf: NABufferType, dst: &mut [u8], bpp: u8) -> EncoderResult<()> {
66 NABufferType::Video(ref vbuf) => {
68 return Err(EncoderError::FormatError);
70 let off = vbuf.get_offset(0);
71 let stride = vbuf.get_stride(0);
72 let data = vbuf.get_data();
73 let w = vbuf.get_info().get_width();
74 let h = vbuf.get_info().get_height();
76 for (dline, sline) in dst.chunks_mut(w).zip(data[off..].chunks(stride)).take(h) {
77 dline[..w].copy_from_slice(&sline[..w]);
80 NABufferType::Video16(ref vbuf) => {
81 let off = vbuf.get_offset(0);
82 let stride = vbuf.get_stride(0);
83 let data = vbuf.get_data();
84 let w = vbuf.get_info().get_width();
85 let h = vbuf.get_info().get_height();
87 for (dline, sline) in dst.chunks_mut(w * 2).zip(data[off..].chunks(stride)).take(h) {
88 for (dst, &src) in dline[..w * 2].chunks_exact_mut(2).zip(sline.iter()) {
90 dst[1] = (src >> 8) as u8;
94 NABufferType::VideoPacked(ref vbuf) => {
95 let off = vbuf.get_offset(0);
96 let stride = vbuf.get_stride(0);
97 let data = vbuf.get_data();
98 let w = vbuf.get_info().get_width();
99 let h = vbuf.get_info().get_height();
100 let w = w * (((bpp as usize) + 7) / 8);
102 for (dline, sline) in dst.chunks_mut(w).zip(data[off..].chunks(stride)).take(h) {
103 dline[..w].copy_from_slice(&sline[..w]);
106 _ => return Err(EncoderError::FormatError),
111 fn to_signed(val: usize) -> isize {
115 -((val >> 1) as isize) - 1
133 cmode: DeflateMode::default(),
134 compr: Deflate::new(DeflateMode::default()),
143 fn encode_intra(&mut self, bw: &mut ByteWriter, buf: NABufferType) -> EncoderResult<()> {
144 let mut bpp = buf_type_to_bpp(&buf);
146 if let NABufferType::None = buf {
148 println!("First frame is skip frame, pretending it's a black frame and hoping for the best");
149 if let Some(ref stream) = self.stream {
150 if let Some(vinfo) = stream.get_info().get_properties().get_video_info() {
151 let in_bpp = if vinfo.format.is_paletted() {
153 } else { vinfo.format.get_total_depth() };
154 if !matches!(in_bpp, 8 | 15 | 16 | 24) {
155 return Err(EncoderError::FormatError);
161 return Err(EncoderError::FormatError);
164 self.frm1.copy_from_slice(&self.frm2);
168 return Err(EncoderError::FormatError);
172 if let (NABufferType::Video(ref vbuf), true) = (&buf, bpp == 8) {
173 let off = vbuf.get_offset(1);
174 let data = vbuf.get_data();
175 self.pal.copy_from_slice(&data[off..][..768]);
178 copy_frame(buf, &mut self.frm1, self.bpp)?;
181 bw.write_byte(1)?; // intra flag
182 bw.write_byte(0)?; // high version
183 bw.write_byte(1)?; // low version
184 bw.write_byte(if self.cmode == DeflateMode::NoCompr { 0 } else { 1 })?;
185 let fmt = match self.bpp {
194 bw.write_byte(self.tile_w as u8)?;
195 bw.write_byte(self.tile_h as u8)?;
197 let bm = ((bpp as usize) + 7) / 8;
198 if self.cmode == DeflateMode::NoCompr {
200 bw.write_buf(&self.pal)?;
202 bw.write_buf(&self.frm1[..self.width * self.height * bm])?;
204 self.tmp_buf.clear();
206 self.tmp_buf.extend_from_slice(&self.pal);
208 self.tmp_buf.extend_from_slice(&self.frm1[..self.width * self.height * bm]);
209 self.compr = Deflate::new(self.cmode);
211 let mut db = Vec::new();
212 std::mem::swap(&mut db, &mut self.zbuf);
214 let mut wr = DeflateWriter::new(db);
215 self.compr.write_zlib_header(&mut wr);
216 self.compr.compress(&self.tmp_buf, &mut wr);
217 self.compr.compress_flush(&mut wr);
218 let mut db = wr.end();
219 std::mem::swap(&mut db, &mut self.zbuf);
221 bw.write_buf(&self.zbuf)?;
226 fn encode_inter(&mut self, bw: &mut ByteWriter, buf: NABufferType) -> EncoderResult<()> {
227 if let NABufferType::None = buf {
228 self.frm1.copy_from_slice(&self.frm2);
231 self.tmp_buf.clear();
232 let tile_w = (self.width + self.tile_w - 1) / self.tile_w;
233 let tile_h = (self.height + self.tile_h - 1) / self.tile_h;
234 let mv_size = (tile_w * tile_h * 2 + 3) & !3;
235 for _ in 0..mv_size {
236 self.tmp_buf.push(0);
238 if self.cmode == DeflateMode::NoCompr {
239 bw.write_buf(&self.tmp_buf)?;
241 let mut db = Vec::new();
243 std::mem::swap(&mut db, &mut self.zbuf);
245 let mut wr = DeflateWriter::new(db);
246 self.compr.compress(&self.tmp_buf, &mut wr);
247 self.compr.compress_flush(&mut wr);
248 let mut db = wr.end();
249 std::mem::swap(&mut db, &mut self.zbuf);
251 bw.write_buf(&self.zbuf)?;
255 let bpp = buf_type_to_bpp(&buf);
256 if bpp == 0 || bpp != self.bpp {
257 return Err(EncoderError::FormatError);
260 self.tmp_buf.clear();
261 if let (NABufferType::Video(ref vbuf), true) = (&buf, bpp == 8) {
262 let mut npal = [0; 768];
263 let off = vbuf.get_offset(1);
264 let data = vbuf.get_data();
265 npal.copy_from_slice(&data[off..][..768]);
267 for (&a, &b) in self.pal.iter().zip(npal.iter()) {
274 for (&a, &b) in self.pal.iter().zip(npal.iter()) {
275 self.tmp_buf.push(a ^ b);
281 self.sent_pal = false;
288 copy_frame(buf, &mut self.frm1, self.bpp)?;
290 let tile_w = (self.width + self.tile_w - 1) / self.tile_w;
291 let tile_h = (self.height + self.tile_h - 1) / self.tile_h;
292 let mut mv_start = self.tmp_buf.len();
293 let mv_size = (tile_w * tile_h * 2 + 3) & !3;
294 for _ in 0..mv_size {
295 self.tmp_buf.push(0);
298 let bpp = ((self.bpp as usize) + 7) / 8;
299 let stride = self.width * bpp;
301 for y in (0..self.height).step_by(self.tile_h) {
302 let cur_h = (self.height - y).min(self.tile_h);
303 for x in (0..self.width).step_by(self.tile_w) {
304 let cur_w = (self.width - x).min(self.tile_w);
306 let (best_x, best_y, best_dist) = self.motion_search(&self.frm1[off..], x, y, cur_w, cur_h, bpp);
307 let has_delta = best_dist != 0;
308 self.tmp_buf[mv_start] = (best_x.wrapping_sub(x) << 1) as u8;
310 self.tmp_buf[mv_start] |= 1;
312 self.tmp_buf[mv_start + 1] = (best_y.wrapping_sub(y) << 1) as u8;
315 let rpos = best_x * bpp + best_y * stride;
316 for (line0, line1) in self.frm1[off..].chunks(stride).take(cur_h).zip(self.frm2[rpos..].chunks(stride)) {
317 for (&a, &b) in line0[..cur_w * bpp].iter().zip(line1[..cur_w * bpp].iter()) {
318 self.tmp_buf.push(a ^ b);
323 off += self.tile_w * bpp;
325 off -= tile_w * self.tile_w * bpp;
326 off += stride * self.tile_h;
329 if self.cmode == DeflateMode::NoCompr {
330 bw.write_buf(&self.tmp_buf)?;
332 let mut db = Vec::new();
334 std::mem::swap(&mut db, &mut self.zbuf);
336 let mut wr = DeflateWriter::new(db);
337 self.compr.compress(&self.tmp_buf, &mut wr);
338 self.compr.compress_flush(&mut wr);
339 let mut db = wr.end();
340 std::mem::swap(&mut db, &mut self.zbuf);
342 bw.write_buf(&self.zbuf)?;
347 fn calc_dist(&self, cur_frm: &[u8], xpos: usize, ypos: usize, cur_w: usize, cur_h: usize, bpp: usize) -> u32 {
348 let stride = self.width * bpp;
350 let roff = xpos * bpp + ypos * stride;
351 for (line0, line1) in cur_frm.chunks(stride).take(cur_h).zip(self.frm2[roff..].chunks(stride)) {
352 for (&a, &b) in line0[..cur_w * bpp].iter().zip(line1[..cur_w * bpp].iter()) {
353 diff += u32::from(a ^ b);
358 fn motion_search(&self, cur_frm: &[u8], x: usize, y: usize, cur_w: usize, cur_h: usize, bpp: usize) -> (usize, usize, u32) {
359 let mut best_dist = self.calc_dist(cur_frm, x, y, cur_w, cur_h, bpp);
367 let mut cur_range = self.range.min(64);
369 while cur_range > 1 {
370 let x1 = best_x.saturating_sub(cur_range);
371 let x2 = (best_x + cur_range).min(self.width - cur_w);
372 let y1 = best_y.saturating_sub(cur_range);
373 let y2 = (best_y + cur_range).min(self.height - cur_h);
374 let points = [(best_x, y1),
383 for &(pt_x, pt_y) in points.iter() {
384 if ((x as isize) - (pt_x as isize)).abs() >= 64 {
387 if ((y as isize) - (pt_y as isize)).abs() >= 64 {
390 let dist = self.calc_dist(cur_frm, pt_x, pt_y, cur_w, cur_h, bpp);
391 if dist < best_dist {
397 cur_range = (cur_range + 1) >> 1;
400 for yoff in 0..self.range {
401 let ypos = (y as isize) + to_signed(yoff);
405 let ypos = ypos as usize;
406 if ypos + cur_h > self.height {
409 for xoff in 0..self.range {
410 let xpos = (x as isize) + to_signed(xoff);
414 let xpos = xpos as usize;
415 if xpos + cur_w > self.width {
419 let diff = self.calc_dist(cur_frm, xpos, ypos, cur_w, cur_h, bpp);
421 if best_dist > diff {
426 return (best_x, best_y, 0);
432 (best_x, best_y, best_dist)
436 impl NAEncoder for ZMBVEncoder {
437 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
438 match encinfo.format {
439 NACodecTypeInfo::None => {
440 Ok(EncodeParameters {
441 format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, true, YUV420_FORMAT)),
445 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
446 NACodecTypeInfo::Video(vinfo) => {
447 let depth = vinfo.format.get_total_depth();
448 let pix_fmt = if vinfo.format.is_paletted() {
450 } else if !vinfo.format.model.is_rgb() || depth > 16 {
452 } else if depth < 16 {
457 let outinfo = NAVideoInfo::new(vinfo.width, vinfo.height, false, pix_fmt);
458 let mut ofmt = *encinfo;
459 ofmt.format = NACodecTypeInfo::Video(outinfo);
464 fn get_capabilities(&self) -> u64 { ENC_CAPS_SKIPFRAME }
465 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
466 match encinfo.format {
467 NACodecTypeInfo::None => Err(EncoderError::FormatError),
468 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
469 NACodecTypeInfo::Video(vinfo) => {
470 self.width = vinfo.width;
471 self.height = vinfo.height;
473 let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, false, vinfo.format);
474 let info = NACodecInfo::new("zmbv", NACodecTypeInfo::Video(out_info), None);
475 let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
476 stream.set_num(stream_id as usize);
477 let stream = stream.into_ref();
479 self.stream = Some(stream.clone());
481 self.frm1 = vec![0; vinfo.width * vinfo.height * 4];
482 self.frm2 = vec![0; vinfo.width * vinfo.height * 4];
488 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
489 let buf = frm.get_buffer();
490 let mut dbuf = Vec::with_capacity(4);
491 let mut gw = GrowableMemoryWriter::new_write(&mut dbuf);
492 let mut bw = ByteWriter::new(&mut gw);
493 let is_intra = if self.frmcount == 0 {
494 self.encode_intra(&mut bw, buf)?;
497 self.encode_inter(&mut bw, buf)?;
500 self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf));
501 if self.bpp == 8 && !self.sent_pal {
502 if let NABufferType::Video(ref buf) = frm.get_buffer() {
503 let paloff = buf.get_offset(1);
504 let data = buf.get_data();
505 let mut pal = [0; 1024];
506 let srcpal = &data[paloff..][..768];
507 for (dclr, sclr) in pal.chunks_exact_mut(4).zip(srcpal.chunks_exact(3)) {
508 dclr[..3].copy_from_slice(sclr);
510 if let Some(ref mut pkt) = &mut self.pkt {
511 pkt.side_data.push(NASideData::Palette(true, Arc::new(pal)));
514 self.sent_pal = true;
517 if self.frmcount == self.key_int {
520 std::mem::swap(&mut self.frm1, &mut self.frm2);
523 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
525 std::mem::swap(&mut self.pkt, &mut npkt);
528 fn flush(&mut self) -> EncoderResult<()> {
534 const ENCODER_OPTS: &[NAOptionDefinition] = &[
536 name: KEYFRAME_OPTION, description: KEYFRAME_OPTION_DESC,
537 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
539 name: "range", description: "Block search range (0-128)",
540 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
542 name: "full_me", description: "Brute force search",
543 opt_type: NAOptionDefinitionType::Bool },
545 name: "tile_width", description: "Block width (1-255)",
546 opt_type: NAOptionDefinitionType::Int(Some(1), Some(255)) },
548 name: "tile_height", description: "Block width (1-255)",
549 opt_type: NAOptionDefinitionType::Int(Some(1), Some(255)) },
551 name: "compr_level", description: "Compression level",
552 opt_type: DEFLATE_OPTION_VALUES },
555 impl NAOptionHandler for ZMBVEncoder {
556 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
557 fn set_options(&mut self, options: &[NAOption]) {
558 for option in options.iter() {
559 for opt_def in ENCODER_OPTS.iter() {
560 if opt_def.check(option).is_ok() {
563 if let NAValue::String(ref s) = option.value {
564 if let Ok(val) = s.parse::<DeflateMode>() {
570 if let NAValue::Int(intval) = option.value {
571 self.key_int = intval as u8;
575 if let NAValue::Int(intval) = option.value {
576 self.range = intval as usize;
580 if let NAValue::Bool(bval) = option.value {
585 if let NAValue::Int(intval) = option.value {
586 self.tile_w = intval as usize;
590 if let NAValue::Int(intval) = option.value {
591 self.tile_h = intval as usize;
600 fn query_option_value(&self, name: &str) -> Option<NAValue> {
602 "compr_level" => Some(NAValue::String(self.cmode.to_string())),
603 KEYFRAME_OPTION => Some(NAValue::Int(i64::from(self.key_int))),
604 "range" => Some(NAValue::Int(self.range as i64)),
605 "full_me" => Some(NAValue::Bool(self.full_me)),
606 "tile_width" => Some(NAValue::Int(self.tile_w as i64)),
607 "tile_height" => Some(NAValue::Int(self.tile_h as i64)),
613 pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
614 Box::new(ZMBVEncoder::new())
619 use nihav_core::codecs::*;
620 use nihav_core::demuxers::*;
621 use nihav_core::muxers::*;
623 use nihav_codec_support::test::enc_video::*;
624 use super::{RGB555_FORMAT, RGB24_0_FORMAT};
626 // samples are from https://samples.mplayerhq.hu/V-codecs/ZMBV/
628 fn test_zmbv_encoder_8bit() {
629 let mut dmx_reg = RegisteredDemuxers::new();
630 generic_register_all_demuxers(&mut dmx_reg);
631 let mut dec_reg = RegisteredDecoders::new();
632 generic_register_all_decoders(&mut dec_reg);
633 let mut mux_reg = RegisteredMuxers::new();
634 generic_register_all_muxers(&mut mux_reg);
635 let mut enc_reg = RegisteredEncoders::new();
636 generic_register_all_encoders(&mut enc_reg);
638 let dec_config = DecoderTestParams {
640 in_name: "assets/Misc/td3_000.avi",
641 stream_type: StreamType::Video,
645 let enc_config = EncoderTestParams {
648 out_name: "zmbv8.avi",
651 let dst_vinfo = NAVideoInfo {
658 let enc_params = EncodeParameters {
659 format: NACodecTypeInfo::Video(dst_vinfo),
667 NAOption { name: "range", value: NAValue::Int(16) },
668 NAOption { name: "full_me", value: NAValue::Bool(true) },
670 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
671 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
672 &[0x18bd3754, 0x97007f81, 0xff2bcd07, 0x739c48dc]);
676 fn test_zmbv_encoder_15bit() {
677 let mut dmx_reg = RegisteredDemuxers::new();
678 generic_register_all_demuxers(&mut dmx_reg);
679 let mut dec_reg = RegisteredDecoders::new();
680 generic_register_all_decoders(&mut dec_reg);
681 let mut mux_reg = RegisteredMuxers::new();
682 generic_register_all_muxers(&mut mux_reg);
683 let mut enc_reg = RegisteredEncoders::new();
684 generic_register_all_encoders(&mut enc_reg);
686 let dec_config = DecoderTestParams {
688 in_name: "assets/Misc/zmbv_15bit.avi",
689 stream_type: StreamType::Video,
693 let enc_config = EncoderTestParams {
696 out_name: "zmbv15.avi",
699 let dst_vinfo = NAVideoInfo {
702 format: RGB555_FORMAT,
706 let enc_params = EncodeParameters {
707 format: NACodecTypeInfo::Video(dst_vinfo),
715 NAOption { name: "range", value: NAValue::Int(16) },
716 NAOption { name: "full_me", value: NAValue::Bool(true) },
718 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
719 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
720 &[0x00311257, 0xd26a0e9e, 0xfd4b003f, 0x7c962d7b]);
724 fn test_zmbv_encoder_16bit() {
725 let mut dmx_reg = RegisteredDemuxers::new();
726 generic_register_all_demuxers(&mut dmx_reg);
727 let mut dec_reg = RegisteredDecoders::new();
728 generic_register_all_decoders(&mut dec_reg);
729 let mut mux_reg = RegisteredMuxers::new();
730 generic_register_all_muxers(&mut mux_reg);
731 let mut enc_reg = RegisteredEncoders::new();
732 generic_register_all_encoders(&mut enc_reg);
734 let dec_config = DecoderTestParams {
736 in_name: "assets/Misc/zmbv_16bit.avi",
737 stream_type: StreamType::Video,
741 let enc_config = EncoderTestParams {
744 out_name: "zmbv16.avi",
747 let dst_vinfo = NAVideoInfo {
750 format: RGB565_FORMAT,
754 let enc_params = EncodeParameters {
755 format: NACodecTypeInfo::Video(dst_vinfo),
763 NAOption { name: "range", value: NAValue::Int(16) },
764 NAOption { name: "full_me", value: NAValue::Bool(true) },
766 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
767 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
768 &[0x4eea104f, 0x2ebe544b, 0x54deb0f9, 0xe5ca88f4]);
772 fn test_zmbv_encoder_32bit() {
773 let mut dmx_reg = RegisteredDemuxers::new();
774 generic_register_all_demuxers(&mut dmx_reg);
775 let mut dec_reg = RegisteredDecoders::new();
776 generic_register_all_decoders(&mut dec_reg);
777 let mut mux_reg = RegisteredMuxers::new();
778 generic_register_all_muxers(&mut mux_reg);
779 let mut enc_reg = RegisteredEncoders::new();
780 generic_register_all_encoders(&mut enc_reg);
782 let dec_config = DecoderTestParams {
784 in_name: "assets/Misc/zmbv_32bit.avi",
785 stream_type: StreamType::Video,
789 let enc_config = EncoderTestParams {
792 out_name: "zmbv32.avi",
795 let dst_vinfo = NAVideoInfo {
798 format: RGB24_0_FORMAT,
802 let enc_params = EncodeParameters {
803 format: NACodecTypeInfo::Video(dst_vinfo),
811 NAOption { name: "range", value: NAValue::Int(16) },
812 NAOption { name: "full_me", value: NAValue::Bool(true) },
814 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
815 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
816 &[0xffceb4bd, 0xb1beccd9, 0x4983e7f6, 0xf46e33ba]);