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>,
41 fn buf_type_to_bpp(buf: &NABufferType) -> u8 {
43 NABufferType::Video(ref vbuf) => {
44 let vinfo = vbuf.get_info();
45 if vinfo.get_format().is_paletted() {
48 vinfo.get_format().get_total_depth()
51 NABufferType::VideoPacked(ref vbuf) => {
52 let vinfo = vbuf.get_info();
53 vinfo.get_format().elem_size * 8
55 NABufferType::Video16(ref vbuf) => {
56 let vinfo = vbuf.get_info();
57 vinfo.get_format().get_total_depth()
63 fn copy_frame(buf: NABufferType, dst: &mut [u8], bpp: u8) -> EncoderResult<()> {
65 NABufferType::Video(ref vbuf) => {
67 return Err(EncoderError::FormatError);
69 let off = vbuf.get_offset(0);
70 let stride = vbuf.get_stride(0);
71 let data = vbuf.get_data();
72 let w = vbuf.get_info().get_width();
73 let h = vbuf.get_info().get_height();
75 for (dline, sline) in dst.chunks_mut(w).zip(data[off..].chunks(stride)).take(h) {
76 dline[..w].copy_from_slice(&sline[..w]);
79 NABufferType::Video16(ref vbuf) => {
80 let off = vbuf.get_offset(0);
81 let stride = vbuf.get_stride(0);
82 let data = vbuf.get_data();
83 let w = vbuf.get_info().get_width();
84 let h = vbuf.get_info().get_height();
86 for (dline, sline) in dst.chunks_mut(w * 2).zip(data[off..].chunks(stride)).take(h) {
87 for (dst, &src) in dline[..w * 2].chunks_exact_mut(2).zip(sline.iter()) {
89 dst[1] = (src >> 8) as u8;
93 NABufferType::VideoPacked(ref vbuf) => {
94 let off = vbuf.get_offset(0);
95 let stride = vbuf.get_stride(0);
96 let data = vbuf.get_data();
97 let w = vbuf.get_info().get_width();
98 let h = vbuf.get_info().get_height();
99 let w = w * (((bpp as usize) + 7) / 8);
101 for (dline, sline) in dst.chunks_mut(w).zip(data[off..].chunks(stride)).take(h) {
102 dline[..w].copy_from_slice(&sline[..w]);
105 _ => return Err(EncoderError::FormatError),
110 fn to_signed(val: usize) -> isize {
114 -((val >> 1) as isize) - 1
132 cmode: DeflateMode::default(),
133 compr: Deflate::new(DeflateMode::default()),
141 fn encode_intra(&mut self, bw: &mut ByteWriter, buf: NABufferType) -> EncoderResult<()> {
142 let bpp = buf_type_to_bpp(&buf);
144 if let NABufferType::None = buf {
146 return Err(EncoderError::FormatError);
148 self.frm1.copy_from_slice(&self.frm2);
151 return Err(EncoderError::FormatError);
155 if let (NABufferType::Video(ref vbuf), true) = (&buf, bpp == 8) {
156 let off = vbuf.get_offset(1);
157 let data = vbuf.get_data();
158 self.pal.copy_from_slice(&data[off..][..768]);
161 copy_frame(buf, &mut self.frm1, self.bpp)?;
164 bw.write_byte(1)?; // intra flag
165 bw.write_byte(0)?; // high version
166 bw.write_byte(1)?; // low version
167 bw.write_byte(if self.cmode == DeflateMode::NoCompr { 0 } else { 1 })?;
168 let fmt = match self.bpp {
177 bw.write_byte(self.tile_w as u8)?;
178 bw.write_byte(self.tile_h as u8)?;
180 let bm = ((bpp as usize) + 7) / 8;
181 if self.cmode == DeflateMode::NoCompr {
183 bw.write_buf(&self.pal)?;
185 bw.write_buf(&self.frm1[..self.width * self.height * bm])?;
187 self.tmp_buf.truncate(0);
189 self.tmp_buf.extend_from_slice(&self.pal);
191 self.tmp_buf.extend_from_slice(&self.frm1[..self.width * self.height * bm]);
192 self.compr = Deflate::new(self.cmode);
194 let mut db = Vec::new();
195 std::mem::swap(&mut db, &mut self.zbuf);
197 let mut wr = DeflateWriter::new(db);
198 self.compr.write_zlib_header(&mut wr);
199 self.compr.compress(&self.tmp_buf, &mut wr);
200 self.compr.compress_flush(&mut wr);
201 let mut db = wr.end();
202 std::mem::swap(&mut db, &mut self.zbuf);
204 bw.write_buf(&self.zbuf)?;
209 fn encode_inter(&mut self, bw: &mut ByteWriter, buf: NABufferType) -> EncoderResult<()> {
210 if let NABufferType::None = buf {
211 self.frm1.copy_from_slice(&self.frm2);
214 self.tmp_buf.truncate(0);
215 let tile_w = (self.width + self.tile_w - 1) / self.tile_w;
216 let tile_h = (self.height + self.tile_h - 1) / self.tile_h;
217 let mv_size = (tile_w * tile_h * 2 + 3) & !3;
218 for _ in 0..mv_size {
219 self.tmp_buf.push(0);
221 if self.cmode == DeflateMode::NoCompr {
222 bw.write_buf(&self.tmp_buf)?;
224 let mut db = Vec::new();
226 std::mem::swap(&mut db, &mut self.zbuf);
228 let mut wr = DeflateWriter::new(db);
229 self.compr.compress(&self.tmp_buf, &mut wr);
230 self.compr.compress_flush(&mut wr);
231 let mut db = wr.end();
232 std::mem::swap(&mut db, &mut self.zbuf);
234 bw.write_buf(&self.zbuf)?;
238 let bpp = buf_type_to_bpp(&buf);
239 if bpp == 0 || bpp != self.bpp {
240 return Err(EncoderError::FormatError);
243 self.tmp_buf.truncate(0);
244 if let (NABufferType::Video(ref vbuf), true) = (&buf, bpp == 8) {
245 let mut npal = [0; 768];
246 let off = vbuf.get_offset(1);
247 let data = vbuf.get_data();
248 npal.copy_from_slice(&data[off..][..768]);
250 for (&a, &b) in self.pal.iter().zip(npal.iter()) {
257 for (&a, &b) in self.pal.iter().zip(npal.iter()) {
258 self.tmp_buf.push(a ^ b);
264 self.sent_pal = false;
271 copy_frame(buf, &mut self.frm1, self.bpp)?;
273 let tile_w = (self.width + self.tile_w - 1) / self.tile_w;
274 let tile_h = (self.height + self.tile_h - 1) / self.tile_h;
275 let mut mv_start = self.tmp_buf.len();
276 let mv_size = (tile_w * tile_h * 2 + 3) & !3;
277 for _ in 0..mv_size {
278 self.tmp_buf.push(0);
281 let bpp = ((self.bpp as usize) + 7) / 8;
282 let stride = self.width * bpp;
284 for y in (0..self.height).step_by(self.tile_h) {
285 let cur_h = (self.height - y).min(self.tile_h);
286 for x in (0..self.width).step_by(self.tile_w) {
287 let cur_w = (self.width - x).min(self.tile_w);
289 let mut best_dist = std::u32::MAX;
293 'search: for yoff in 0..self.range {
294 let ypos = (y as isize) + to_signed(yoff);
298 let ypos = ypos as usize;
299 if ypos + cur_h > self.height {
302 for xoff in 0..self.range {
303 let xpos = (x as isize) + to_signed(xoff);
307 let xpos = xpos as usize;
308 if xpos + cur_w > self.width {
313 let roff = xpos * bpp + ypos * stride;
314 for (line0, line1) in self.frm1[off..].chunks(stride).take(cur_h).zip(self.frm2[roff..].chunks(stride)) {
315 for (&a, &b) in line0[..cur_w * bpp].iter().zip(line1[..cur_w * bpp].iter()) {
316 diff += u32::from(a ^ b);
320 if best_dist > diff {
331 let has_delta = best_dist != 0;
332 self.tmp_buf[mv_start] = (best_x.wrapping_sub(x) << 1) as u8;
334 self.tmp_buf[mv_start] |= 1;
336 self.tmp_buf[mv_start + 1] = (best_y.wrapping_sub(y) << 1) as u8;
339 let rpos = best_x * bpp + best_y * stride;
340 for (line0, line1) in self.frm1[off..].chunks(stride).take(cur_h).zip(self.frm2[rpos..].chunks(stride)) {
341 for (&a, &b) in line0[..cur_w * bpp].iter().zip(line1[..cur_w * bpp].iter()) {
342 self.tmp_buf.push(a ^ b);
347 off += self.tile_w * bpp;
349 off -= tile_w * self.tile_w * bpp;
350 off += stride * self.tile_h;
353 if self.cmode == DeflateMode::NoCompr {
354 bw.write_buf(&self.tmp_buf)?;
356 let mut db = Vec::new();
358 std::mem::swap(&mut db, &mut self.zbuf);
360 let mut wr = DeflateWriter::new(db);
361 self.compr.compress(&self.tmp_buf, &mut wr);
362 self.compr.compress_flush(&mut wr);
363 let mut db = wr.end();
364 std::mem::swap(&mut db, &mut self.zbuf);
366 bw.write_buf(&self.zbuf)?;
373 impl NAEncoder for ZMBVEncoder {
374 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
375 match encinfo.format {
376 NACodecTypeInfo::None => {
377 let mut ofmt = EncodeParameters::default();
378 ofmt.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, true, YUV420_FORMAT));
381 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
382 NACodecTypeInfo::Video(vinfo) => {
383 let depth = vinfo.format.get_total_depth();
384 let pix_fmt = if vinfo.format.is_paletted() {
386 } else if !vinfo.format.model.is_rgb() || depth > 16 {
388 } else if depth < 16 {
393 let outinfo = NAVideoInfo::new(vinfo.width, vinfo.height, false, pix_fmt);
394 let mut ofmt = *encinfo;
395 ofmt.format = NACodecTypeInfo::Video(outinfo);
400 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
401 match encinfo.format {
402 NACodecTypeInfo::None => Err(EncoderError::FormatError),
403 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
404 NACodecTypeInfo::Video(vinfo) => {
405 self.width = vinfo.width;
406 self.height = vinfo.height;
408 let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, false, vinfo.format);
409 let info = NACodecInfo::new("zmbv", NACodecTypeInfo::Video(out_info), None);
410 let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
411 stream.set_num(stream_id as usize);
412 let stream = stream.into_ref();
414 self.stream = Some(stream.clone());
416 self.frm1 = vec![0; vinfo.width * vinfo.height * 4];
417 self.frm2 = vec![0; vinfo.width * vinfo.height * 4];
423 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
424 let buf = frm.get_buffer();
425 let mut dbuf = Vec::with_capacity(4);
426 let mut gw = GrowableMemoryWriter::new_write(&mut dbuf);
427 let mut bw = ByteWriter::new(&mut gw);
428 let is_intra = if self.frmcount == 0 {
429 self.encode_intra(&mut bw, buf)?;
432 self.encode_inter(&mut bw, buf)?;
435 self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf));
436 if self.bpp == 8 && !self.sent_pal {
437 if let NABufferType::Video(ref buf) = frm.get_buffer() {
438 let paloff = buf.get_offset(1);
439 let data = buf.get_data();
440 let mut pal = [0; 1024];
441 let srcpal = &data[paloff..][..768];
442 for (dclr, sclr) in pal.chunks_exact_mut(4).zip(srcpal.chunks_exact(3)) {
443 dclr[..3].copy_from_slice(sclr);
445 if let Some(ref mut pkt) = &mut self.pkt {
446 pkt.side_data.push(NASideData::Palette(true, Arc::new(pal)));
449 self.sent_pal = true;
452 if self.frmcount == self.key_int {
455 std::mem::swap(&mut self.frm1, &mut self.frm2);
458 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
460 std::mem::swap(&mut self.pkt, &mut npkt);
463 fn flush(&mut self) -> EncoderResult<()> {
469 const ENCODER_OPTS: &[NAOptionDefinition] = &[
471 name: KEYFRAME_OPTION, description: KEYFRAME_OPTION_DESC,
472 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
474 name: "range", description: "Block search range (0-128)",
475 opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) },
477 name: "tile_width", description: "Block width (1-255)",
478 opt_type: NAOptionDefinitionType::Int(Some(1), Some(255)) },
480 name: "tile_height", description: "Block width (1-255)",
481 opt_type: NAOptionDefinitionType::Int(Some(1), Some(255)) },
483 name: "compr_level", description: "Compression level",
484 opt_type: DEFLATE_OPTION_VALUES },
487 impl NAOptionHandler for ZMBVEncoder {
488 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
489 fn set_options(&mut self, options: &[NAOption]) {
490 for option in options.iter() {
491 for opt_def in ENCODER_OPTS.iter() {
492 if opt_def.check(option).is_ok() {
495 if let NAValue::String(ref s) = option.value {
496 if let Ok(val) = s.parse::<DeflateMode>() {
502 if let NAValue::Int(intval) = option.value {
503 self.key_int = intval as u8;
507 if let NAValue::Int(intval) = option.value {
508 self.range = intval as usize;
512 if let NAValue::Int(intval) = option.value {
513 self.tile_w = intval as usize;
517 if let NAValue::Int(intval) = option.value {
518 self.tile_h = intval as usize;
527 fn query_option_value(&self, name: &str) -> Option<NAValue> {
529 "compr_level" => Some(NAValue::String(self.cmode.to_string())),
530 KEYFRAME_OPTION => Some(NAValue::Int(i64::from(self.key_int))),
531 "range" => Some(NAValue::Int(self.range as i64)),
532 "tile_width" => Some(NAValue::Int(self.tile_w as i64)),
533 "tile_height" => Some(NAValue::Int(self.tile_h as i64)),
539 pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
540 Box::new(ZMBVEncoder::new())
545 use nihav_core::codecs::*;
546 use nihav_core::demuxers::*;
547 use nihav_core::muxers::*;
549 use nihav_codec_support::test::enc_video::*;
550 use super::{RGB555_FORMAT, RGB24_0_FORMAT};
553 fn test_zmbv_encoder_8bit() {
554 let mut dmx_reg = RegisteredDemuxers::new();
555 generic_register_all_demuxers(&mut dmx_reg);
556 let mut dec_reg = RegisteredDecoders::new();
557 generic_register_all_decoders(&mut dec_reg);
558 let mut mux_reg = RegisteredMuxers::new();
559 generic_register_all_muxers(&mut mux_reg);
560 let mut enc_reg = RegisteredEncoders::new();
561 generic_register_all_encoders(&mut enc_reg);
563 let dec_config = DecoderTestParams {
565 in_name: "assets/Misc/td3_000.avi",
566 stream_type: StreamType::Video,
570 let enc_config = EncoderTestParams {
573 out_name: "zmbv8.avi",
576 let dst_vinfo = NAVideoInfo {
583 let enc_params = EncodeParameters {
584 format: NACodecTypeInfo::Video(dst_vinfo),
591 //test_encoding_to_file(&dec_config, &enc_config, enc_params);
592 test_encoding_md5(&dec_config, &enc_config, enc_params,
593 &[0x50df10e2, 0x606f3268, 0xdd4bc2ff, 0x844e7d87]);
597 fn test_zmbv_encoder_15bit() {
598 let mut dmx_reg = RegisteredDemuxers::new();
599 generic_register_all_demuxers(&mut dmx_reg);
600 let mut dec_reg = RegisteredDecoders::new();
601 generic_register_all_decoders(&mut dec_reg);
602 let mut mux_reg = RegisteredMuxers::new();
603 generic_register_all_muxers(&mut mux_reg);
604 let mut enc_reg = RegisteredEncoders::new();
605 generic_register_all_encoders(&mut enc_reg);
607 let dec_config = DecoderTestParams {
609 in_name: "assets/Misc/zmbv_15bit.avi",
610 stream_type: StreamType::Video,
614 let enc_config = EncoderTestParams {
617 out_name: "zmbv15.avi",
620 let dst_vinfo = NAVideoInfo {
623 format: RGB555_FORMAT,
627 let enc_params = EncodeParameters {
628 format: NACodecTypeInfo::Video(dst_vinfo),
635 //test_encoding_to_file(&dec_config, &enc_config, enc_params);
636 test_encoding_md5(&dec_config, &enc_config, enc_params,
637 &[0x0b4cb528, 0x66c91f6c, 0x1c2187a5, 0x2723a08d]);
641 fn test_zmbv_encoder_16bit() {
642 let mut dmx_reg = RegisteredDemuxers::new();
643 generic_register_all_demuxers(&mut dmx_reg);
644 let mut dec_reg = RegisteredDecoders::new();
645 generic_register_all_decoders(&mut dec_reg);
646 let mut mux_reg = RegisteredMuxers::new();
647 generic_register_all_muxers(&mut mux_reg);
648 let mut enc_reg = RegisteredEncoders::new();
649 generic_register_all_encoders(&mut enc_reg);
651 let dec_config = DecoderTestParams {
653 in_name: "assets/Misc/zmbv_16bit.avi",
654 stream_type: StreamType::Video,
658 let enc_config = EncoderTestParams {
661 out_name: "zmbv16.avi",
664 let dst_vinfo = NAVideoInfo {
667 format: RGB565_FORMAT,
671 let enc_params = EncodeParameters {
672 format: NACodecTypeInfo::Video(dst_vinfo),
679 //test_encoding_to_file(&dec_config, &enc_config, enc_params);
680 test_encoding_md5(&dec_config, &enc_config, enc_params,
681 &[0x1a522743, 0x6c320a6e, 0xd08539e1, 0x03fc17ea]);
685 fn test_zmbv_encoder_32bit() {
686 let mut dmx_reg = RegisteredDemuxers::new();
687 generic_register_all_demuxers(&mut dmx_reg);
688 let mut dec_reg = RegisteredDecoders::new();
689 generic_register_all_decoders(&mut dec_reg);
690 let mut mux_reg = RegisteredMuxers::new();
691 generic_register_all_muxers(&mut mux_reg);
692 let mut enc_reg = RegisteredEncoders::new();
693 generic_register_all_encoders(&mut enc_reg);
695 let dec_config = DecoderTestParams {
697 in_name: "assets/Misc/zmbv_32bit.avi",
698 stream_type: StreamType::Video,
702 let enc_config = EncoderTestParams {
705 out_name: "zmbv32.avi",
708 let dst_vinfo = NAVideoInfo {
711 format: RGB24_0_FORMAT,
715 let enc_params = EncodeParameters {
716 format: NACodecTypeInfo::Video(dst_vinfo),
723 //test_encoding_to_file(&dec_config, &enc_config, enc_params);
724 test_encoding_md5(&dec_config, &enc_config, enc_params,
725 &[0x3880e045, 0xe6c88dc7, 0x21066058, 0xc789f1e9]);