1 use std::collections::VecDeque;
4 use nihav_core::codecs::*;
5 use nihav_core::io::byteio::*;
6 use nihav_core::io::bitwriter::*;
12 use dsp::loop_filter_frame;
25 pub use ratectl::RateDistMetric;
30 const DEBUG_BIT_FRAMENO: u8 = 0;
31 const DEBUG_BIT_SLICE_SIZE: u8 = 1;
32 const DEBUG_BIT_PSNR: u8 = 2;
33 const DEBUG_BIT_RATECTL: u8 = 3;
34 const DEBUG_FLAG_BITS: &[(&str, u8)] = &[
35 ("frameno", DEBUG_BIT_FRAMENO),
36 ("slicesize", DEBUG_BIT_SLICE_SIZE),
37 ("psnr", DEBUG_BIT_PSNR),
38 ("rc", DEBUG_BIT_RATECTL),
41 #[derive(Clone,Copy,Default)]
47 fn new() -> Self { Self::default() }
48 fn is_set(self, bit: u8) -> bool { (self.flags & (1 << bit)) != 0 }
49 fn parse(&mut self, args: &str) {
51 for arg in args.split('+') {
52 for &(name, bit) in DEBUG_FLAG_BITS.iter() {
54 self.flags += 1 << bit;
61 impl std::fmt::Display for DebugFlags {
62 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
63 let mut flags = String::new();
65 for &(name, bit) in DEBUG_FLAG_BITS.iter() {
74 write!(f, "{}", flags)
78 struct StaticFrameOrder {
79 groups: Vec<(FrameType, usize)>,
85 impl StaticFrameOrder {
88 groups: vec![(FrameType::I, 0)],
94 fn get_max_grp_len(&self) -> usize {
96 for &(_, num_b) in self.groups.iter() {
97 g_len = g_len.max(1 + num_b);
101 fn peek_next_frame(&self) -> (FrameType, usize) {
103 let grp = &self.groups[self.cur_grp];
104 if self.cur_frm == 0 {
113 fn next_frame(&mut self) -> FrameType {
115 let grp = &self.groups[self.cur_grp];
116 let frm_type = if self.cur_frm == 0 {
122 if self.cur_frm > grp.1 {
125 if self.cur_grp >= self.groups.len() {
132 self.cur_grp = if self.groups.len() > 1 { 1 } else { 0 };
139 impl std::fmt::Display for StaticFrameOrder {
140 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
141 let mut seq = String::with_capacity(self.groups.len() * 2);
142 for &(ftype, brun) in self.groups.iter() {
143 seq.push(match ftype {
155 struct DynamicFrameOrder {
161 const NUM_GOP_KF: usize = 8;
163 impl DynamicFrameOrder {
166 cur_ft: FrameType::I,
167 next_ft: FrameType::Other,
171 fn peek_next_frame(&self) -> (FrameType, usize) {
172 (self.cur_ft, if self.cur_ft == FrameType::Other || self.next_ft == FrameType::B { 1 } else { 0 })
174 fn next_frame(&mut self) -> FrameType {
175 if self.cur_ft == FrameType::P {
177 if self.p_count >= NUM_GOP_KF {
178 self.cur_ft = FrameType::I;
182 let next = self.cur_ft;
183 self.cur_ft = self.next_ft;
184 self.next_ft = if self.cur_ft != FrameType::B { FrameType::Other } else { FrameType::P };
187 fn update(&mut self, ftype: FrameType) {
188 if self.cur_ft == FrameType::Other {
190 if self.cur_ft == FrameType::B {
191 self.cur_ft = FrameType::P;
192 self.next_ft = FrameType::B;
194 self.next_ft = FrameType::Other;
200 impl std::fmt::Display for DynamicFrameOrder {
201 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
207 Static(StaticFrameOrder),
208 Dynamic(DynamicFrameOrder),
213 FrameOrder::Dynamic(DynamicFrameOrder::new())
215 fn get_max_grp_len(&self) -> usize {
217 FrameOrder::Static(ref order) => order.get_max_grp_len(),
218 FrameOrder::Dynamic(ref _order) => 2,
221 fn peek_next_frame(&self) -> (FrameType, usize) {
223 FrameOrder::Static(ref order) => order.peek_next_frame(),
224 FrameOrder::Dynamic(ref order) => order.peek_next_frame(),
227 fn next_frame(&mut self) -> FrameType {
229 FrameOrder::Static(ref mut order) => order.next_frame(),
230 FrameOrder::Dynamic(ref mut order) => order.next_frame(),
233 fn update(&mut self, ftype: FrameType) {
234 if let FrameOrder::Dynamic(ref mut order) = self {
238 fn is_dynamic(&self) -> bool { matches!(self, FrameOrder::Dynamic(_)) }
241 impl std::fmt::Display for FrameOrder {
242 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
244 FrameOrder::Static(ref order) => order.fmt(f),
245 FrameOrder::Dynamic(ref order) => order.fmt(f),
250 #[derive(Clone,Copy,Debug)]
258 impl FromStr for FrameOrder {
259 type Err = ParseError;
260 fn from_str(s: &str) -> Result<Self, Self::Err> {
262 return Ok(FrameOrder::Dynamic(DynamicFrameOrder::new()));
264 let mut ftypes = Vec::new();
265 for ch in s.bytes() {
267 b'I' | b'i' => ftypes.push(FrameType::I),
268 b'P' | b'p' => ftypes.push(FrameType::P),
269 b'B' | b'b' => ftypes.push(FrameType::B),
271 _ => return Err(ParseError::InvalidValue),
273 if ftypes.len() > 16 {
274 return Err(ParseError::TooLong);
277 if ftypes.is_empty() {
278 return Err(ParseError::TooShort);
280 if ftypes[0] != FrameType::I {
281 return Err(ParseError::InvalidCombination);
284 let mut groups = Vec::new();
285 let mut cur_ftype = ftypes[0];
287 for &ft in ftypes[1..].iter() {
289 FrameType::I | FrameType::P => {
290 groups.push((cur_ftype, cur_run));
297 return Err(ParseError::InvalidCombination);
302 groups.push((cur_ftype, cur_run));
304 Ok(FrameOrder::Static(StaticFrameOrder{
314 stream: Option<NAStreamRef>,
323 force_set: Option<usize>,
325 fce: FrameComplexityEstimate,
326 mbd: MacroblockDecider,
336 mbs: VecDeque<Macroblock>,
337 dblk: Vec<DeblockInfo>,
339 qframes: Vec<NAFrame>,
340 frm_pool: NAVideoBufferPool<u8>,
341 ref_p: NAVideoBufferRef<u8>,
342 ref_n: NAVideoBufferRef<u8>,
343 pkts: VecDeque<NAPacket>,
353 debug_log: DebugFlags,
361 let vinfo = NAVideoInfo::new(24, 24, false, YUV420_FORMAT);
362 let vt = alloc_video_buffer(vinfo, 4).unwrap();
363 let ref_p = vt.get_vbuf().unwrap();
364 let vt = alloc_video_buffer(vinfo, 4).unwrap();
365 let ref_n = vt.get_vbuf().unwrap();
378 fce: FrameComplexityEstimate::new(),
379 mbd: MacroblockDecider::new(),
380 order: FrameOrder::new(),
381 brc: BitRateControl::new(),
382 rdm: RateDistMetric::new(),
383 be: BitsEstimator::new(),
384 me: MotionEstimator::new(),
385 cset: CodeSets::new(),
387 sstate: SliceState::new(),
388 mbstate: MBState::new(),
389 mbs: VecDeque::new(),
393 frm_pool: NAVideoBufferPool::new(0),
394 pkts: VecDeque::new(),
405 debug_log: DebugFlags::new(),
411 fn encode_frame(&mut self, frm: NAFrame, frameno: usize) -> EncoderResult<NAPacket> {
412 let ftype = self.order.next_frame();
413 let buf = frm.get_buffer();
415 let tinfo = frm.get_time_information();
416 let pts = NATimeInfo::ts_to_time(tinfo.pts.unwrap_or(0), 1000, tinfo.tb_num, tinfo.tb_den);
417 let fpts = (pts & 0x1FFF) as u32;
419 let ts_diff = if ftype == FrameType::B {
420 pts.saturating_sub(self.last_k_ts.min(self.last_b_ts)) as u32
422 let diff = pts.saturating_sub(self.last_k_ts) as u32;
423 diff / ((frameno + 1) as u32)
426 if self.debug_log.is_set(DEBUG_BIT_FRAMENO) {
427 println!("encode frame type {} pts {}", ftype, pts);
429 let is_ref_frame = matches!(ftype, FrameType::I | FrameType::P);
431 let tr_d = (self.n_pts - self.p_pts) as u32;
432 let tr_b = (pts - self.p_pts) as u32;
434 self.mbd.set_b_distance(tr_b, tr_d);
437 let mut rvbuf = if let Some(nfrm) = self.frm_pool.get_free() {
440 return Err(EncoderError::AllocError);
442 let mut recon_frm = NASimpleVideoFrame::from_video_buf(&mut rvbuf).unwrap();
444 self.be.set_frame_type(ftype);
445 if let Some(ref vbuf) = buf.get_vbuf() {
446 let src = vbuf.get_data();
448 if self.brc.rate_ctl_in_use() || self.order.is_dynamic() {
449 self.fce.set_current(vbuf);
452 let complexity = if self.brc.rate_ctl_in_use() {
453 self.fce.get_complexity(ftype)
456 self.mbd.q = self.brc.get_quant(ftype, complexity);
457 self.brc.init_metric(ftype, &mut self.rdm);
458 self.be.set_quant(self.mbd.q);
459 if self.debug_log.is_set(DEBUG_BIT_RATECTL) {
460 println!(" expected frame size {}", self.brc.get_target_size(ftype));
461 println!(" target quantiser {} lambda {} thresholds {} / {}", self.brc.get_last_quant(ftype), self.rdm.lambda, self.rdm.good_enough, self.rdm.p_split_thr);
465 let mut dvec = Vec::new();
467 let mut slice_starts = Vec::new();
468 let num_mbs = self.mb_w * self.mb_h;
469 while mb_idx < num_mbs {
470 slice_starts.push(dvec.len());
471 let mut bw = BitWriter::new(dvec, BitWriterMode::BE);
472 let slice_start_mb = mb_idx;
474 self.mbstate.reset();
476 let mut est_bits = 0;
477 while est_bits < self.slice_bits && mb_idx < num_mbs {
478 let mb_x = mb_idx % self.mb_w;
479 let mb_y = mb_idx / self.mb_w;
480 self.sstate.has_t = mb_idx >= slice_start_mb + self.mb_w;
481 self.sstate.has_l = (mb_idx > slice_start_mb) && (mb_x > 0);
482 self.sstate.has_tl = (mb_idx > slice_start_mb + self.mb_w) && (mb_x > 0);
483 self.sstate.has_tr = (mb_idx >= slice_start_mb + self.mb_w - 1) && (mb_x + 1 < self.mb_w);
484 self.sstate.mb_x = mb_x;
485 self.sstate.mb_y = mb_y;
488 vbuf.get_offset(0) + mb_x * 16 + mb_y * 16 * vbuf.get_stride(0),
489 vbuf.get_offset(1) + mb_x * 8 + mb_y * 8 * vbuf.get_stride(1),
490 vbuf.get_offset(2) + mb_x * 8 + mb_y * 8 * vbuf.get_stride(2),
492 let strides = [vbuf.get_stride(0), vbuf.get_stride(1), vbuf.get_stride(2)];
493 self.mbd.load_mb(src, offsets, strides, &self.sstate);
495 self.be.set_pred_mb_type(self.mbstate.get_pred_mbtype(&self.sstate, ftype == FrameType::B));
496 if ftype == FrameType::B {
497 self.mbd.try_b_coding(&self.ref_p, &self.ref_n, &mut self.be, &mut self.me, &self.rdm, &self.mbstate, self.refine_b);
499 if ftype == FrameType::P {
500 self.mbd.try_p_coding(&self.ref_n, &mut self.be, &mut self.me, &self.rdm, &self.mbstate);
502 self.mbd.try_intra_16_pred(&mut self.be, &self.rdm);
503 if ftype != FrameType::B || self.i4_in_b {
504 self.mbd.try_intra_4x4_pred(&mut self.be, &self.rdm, &mut self.mbstate);
507 let mb = self.mbd.get_macroblock();
508 est_bits += self.mbd.get_est_bits();
509 self.mbd.recon_mb(&mut recon_frm);
510 self.mbstate.update(&mb.mb_type, mb_x, mb_y);
513 self.dblk[mb_idx].q = self.mbd.q as u8;
514 if ftype == FrameType::I {
515 self.dblk[mb_idx].is_strong = true;
516 self.dblk[mb_idx].cbp_y = 0xFFFF;
517 self.dblk[mb_idx].cbp_c = 0xFF;
519 self.dblk[mb_idx].is_strong = mb.mb_type.is_intra() || mb.mb_type.is_16();
522 for blk in mb.coeffs[..16].iter() {
528 self.dblk[mb_idx].cbp_y = cbp;
531 for blk in mb.coeffs[16..24].iter() {
537 self.dblk[mb_idx].cbp_c = cbp;
539 self.mbstate.fill_deblock(&mut self.dblk[mb_idx], &self.sstate);
542 self.mbs.push_back(mb);
547 let set_idx = if let Some(idx) = self.force_set {
550 let mut hist = [0usize; 17];
551 for mb in self.mbs.iter() {
552 let blocks = if mb.mb_type.is_16() { &mb.coeffs } else { &mb.coeffs[..24] };
554 for blk in blocks.iter() {
555 let nz = blk.count_nz();
556 for el in hist[nz..].iter_mut() {
561 BitsEstimator::decide_set(&hist)
564 let start_bits = bw.tell();
565 write_slice_header(&mut bw, ftype, self.mbd.q, set_idx, self.deblock, fpts);
566 if ftype == FrameType::I {
567 write_slice_dimensions(&mut bw, self.width, self.height);
569 bw.write1(); // keep dimensions flag
571 write_slice_mb_idx(&mut bw, slice_start_mb, num_mbs);
573 mb_idx = slice_start_mb;
574 let mut skip_count = 0;
575 self.cset.init(self.mbd.q, set_idx);
576 while let Some(mb) = self.mbs.pop_front() {
577 if bw.tell() > start_bits + (self.slice_bits as usize) {
580 let mb_x = mb_idx % self.mb_w;
581 let mb_y = mb_idx / self.mb_w;
582 self.sstate.has_t = mb_idx >= slice_start_mb + self.mb_w;
583 self.sstate.has_l = (mb_idx > slice_start_mb) && (mb_x > 0);
584 self.sstate.has_tl = (mb_idx > slice_start_mb + self.mb_w) && (mb_x > 0);
585 self.sstate.has_tr = (mb_idx >= slice_start_mb + self.mb_w - 1) && (mb_x + 1 < self.mb_w);
586 self.sstate.mb_x = mb_x;
587 self.sstate.mb_y = mb_y;
588 if mb.mb_type.is_skip() {
592 write_skip_count(&mut bw, skip_count);
594 } else if ftype != FrameType::I {
595 bw.write1(); // zero skip count
598 write_mb_header(&mut bw, ftype, &self.sstate, &self.mbstate);
599 self.cset.set_params(&mb.mb_type);
600 self.cset.write_coeffs(&mut bw, &mb.coeffs);
606 write_skip_count(&mut bw, skip_count);
608 while (bw.tell() & 7) != 0 {
611 if self.debug_log.is_set(DEBUG_BIT_SLICE_SIZE) {
612 println!(" slice {}..{} wrote {} bits / estimated {} bits", slice_start_mb, mb_idx, bw.tell(), est_bits);
617 for _ in 0..(nslices * 8 + 1) {
620 dvec[0] = (nslices - 1) as u8;
621 for (i, &off) in slice_starts.iter().enumerate() {
623 write_u32be(&mut dvec[i * 8 + 5..], off as u32)?;
625 if self.debug_log.is_set(DEBUG_BIT_RATECTL) {
626 println!(" got frame size {}", dvec.len());
629 if is_ref_frame && self.deblock {
630 loop_filter_frame(&mut recon_frm, &self.dblk, self.mb_w, self.mb_h);
633 if self.debug_log.is_set(DEBUG_BIT_PSNR) {
634 let psnr = calc_psnr(&vbuf, &rvbuf);
635 println!(" encoded frame PSNR {} size {}", psnr, dvec.len());
639 std::mem::swap(&mut self.ref_p, &mut self.ref_n);
642 self.p_pts = self.n_pts;
645 self.mbstate.swap_mvs();
649 if self.last_k_ts > self.last_b_ts {
650 self.last_b_ts = self.last_k_ts;
652 self.last_k_ts = pts;
653 self.fce.update_ref();
655 self.last_b_ts = pts;
658 self.brc.update_stats(ftype, dvec.len(), ts_diff);
660 Ok(NAPacket::new(self.stream.clone().unwrap(), frm.ts, ftype == FrameType::I, dvec))
662 Err(EncoderError::InvalidParameters)
667 fn calc_psnr(pic1: &NAVideoBuffer<u8>, pic2: &NAVideoBuffer<u8>) -> f64 {
668 let data1 = pic1.get_data();
669 let data2 = pic2.get_data();
673 let (w, h) = pic1.get_dimensions(comp);
675 for (line1, line2) in data1[pic1.get_offset(comp)..].chunks(pic1.get_stride(comp)).zip(
676 data2[pic2.get_offset(comp)..].chunks(pic2.get_stride(comp))).take(h) {
677 for (&pix1, &pix2) in line1[..w].iter().zip(line2.iter()) {
678 let diff = (i32::from(pix1) - i32::from(pix2)).abs() as u32;
679 sum += u64::from(diff * diff);
684 48.13080360867910341240 - 10.0 * ((sum as f64) / (size as f64)).log10()
690 impl NAEncoder for RV40Encoder {
691 fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
692 match encinfo.format {
693 NACodecTypeInfo::None => {
694 Ok(EncodeParameters {
695 format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)),
696 ..Default::default() })
698 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
699 NACodecTypeInfo::Video(vinfo) => {
700 let outinfo = NAVideoInfo::new((vinfo.width + 15) & !15, (vinfo.height + 15) & !15, false, YUV420_FORMAT);
701 let mut ofmt = *encinfo;
702 ofmt.format = NACodecTypeInfo::Video(outinfo);
707 fn get_capabilities(&self) -> u64 { 0 }
708 fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
709 match encinfo.format {
710 NACodecTypeInfo::None => Err(EncoderError::FormatError),
711 NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
712 NACodecTypeInfo::Video(vinfo) => {
713 if vinfo.format != YUV420_FORMAT {
714 return Err(EncoderError::FormatError);
716 if ((vinfo.width | vinfo.height) & 15) != 0 {
717 return Err(EncoderError::FormatError);
719 if (vinfo.width | vinfo.height) >= (1 << 12) {
720 return Err(EncoderError::FormatError);
723 // 32-bit flags (VBR, bframes, slices, something else) and 32-bit version
724 let edata = vec![0x01, 0x08, 0x10, 0x20, 0x40, 0x00, 0x80, 0x00];
725 let out_info = NAVideoInfo::new(vinfo.width, vinfo.height, false, vinfo.format);
726 let info = NACodecInfo::new("realvideo4", NACodecTypeInfo::Video(out_info), Some(edata));
727 let mut stream = NAStream::new(StreamType::Video, stream_id, info, encinfo.tb_num, encinfo.tb_den, 0);
728 stream.set_num(stream_id as usize);
729 let stream = stream.into_ref();
731 self.stream = Some(stream.clone());
733 self.width = vinfo.width;
734 self.height = vinfo.height;
735 self.mb_w = (vinfo.width + 15) >> 4;
736 self.mb_h = (vinfo.height + 15) >> 4;
738 if self.mb_w * self.mb_h > 9216 {
739 return Err(EncoderError::FormatError);
742 if (1..=100u8).contains(&encinfo.quality) {
743 self.brc.set_force_quality(Some(encinfo.quality));
745 self.brc.set_force_quality(None);
747 self.brc.set_bitrate(encinfo.bitrate);
749 self.vinfo = out_info;
750 let max_frames = self.order.get_max_grp_len();
751 self.frm_pool.set_dec_bufs(max_frames + 3);
752 self.max_grp_bufs = max_frames;
753 self.needs_alloc = true;
755 self.fce.resize(self.width, self.height);
756 self.mbstate.resize(self.mb_w, self.mb_h);
757 self.mbd.resize(self.mb_w);
758 self.dblk.resize(self.mb_w * self.mb_h, DeblockInfo::default());
764 fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
765 if self.needs_alloc {
766 self.frm_pool.prealloc_video(self.vinfo, 4)?;
767 self.ref_n = self.frm_pool.get_free().unwrap();
768 self.ref_p = self.frm_pool.get_free().unwrap();
769 self.needs_alloc = false;
771 if let Some(ref vbuf) = frm.get_buffer().get_vbuf() {
772 if let Some(dbuf) = self.frm_pool.get_copy(vbuf) {
773 let newfrm = NAFrame::new(frm.ts, frm.frame_type, frm.key, frm.get_info(), NABufferType::Video(dbuf));
774 self.qframes.push(newfrm);
777 let (mut ftype, mut frame_pos) = self.order.peek_next_frame();
778 if frame_pos >= self.qframes.len() {
782 if ftype == FrameType::Other {
783 if self.qframes.len() < 2 {
784 return Err(EncoderError::Bug);
786 if let (Some(ref frm1), Some(ref frm2)) = (self.qframes[0].get_buffer().get_vbuf(), self.qframes[1].get_buffer().get_vbuf()) {
787 let is_b = self.fce.decide_b_frame(frm1, frm2);
796 return Err(EncoderError::Bug);
798 self.order.update(ftype);
801 let frm = self.qframes.remove(frame_pos);
802 let pkt = self.encode_frame(frm, frame_pos)?;
803 self.pkts.push_back(pkt);
807 Err(EncoderError::AllocError)
810 Err(EncoderError::FormatError)
813 fn get_packet(&mut self) -> EncoderResult<Option<NAPacket>> {
814 Ok(self.pkts.pop_front())
816 fn flush(&mut self) -> EncoderResult<()> {
821 const DEBUG_LOG_OPTION: &str = "debug";
822 const SLICE_SIZE_OPTION: &str = "slice_size";
823 const FRAME_ORDER_OPTION: &str = "frame_order";
824 const DEBLOCK_OPTION: &str = "loop_filt";
825 const QUANT_OPTION: &str = "quant";
826 const QUALITY_OPTION: &str = "quality";
827 const SET_OPTION: &str = "coding_set";
828 const SEARCH_MODE_OPTION: &str = "me_mode";
829 const SEARCH_RANGE_OPTION: &str = "me_range";
830 const SEARCH_THR_OPTION: &str = "me_thr";
831 const B_REFINE_OPTION: &str = "refine_b";
832 const I4_IN_B_OPTION: &str = "i4_in_b";
833 const B_OFFSET_OPTION: &str = "b_offset";
835 const ENCODER_OPTS: &[NAOptionDefinition] = &[
837 name: DEBUG_LOG_OPTION, description: "debug flags",
838 opt_type: NAOptionDefinitionType::String(None) },
840 name: SLICE_SIZE_OPTION, description: "soft slice size limit in bits",
841 opt_type: NAOptionDefinitionType::Int(Some(4096), Some(100000)) },
843 name: FRAME_ORDER_OPTION, description: "frame order (e.g. IBBPBB)",
844 opt_type: NAOptionDefinitionType::String(None) },
846 name: DEBLOCK_OPTION, description: "in-loop filter",
847 opt_type: NAOptionDefinitionType::Bool },
849 name: QUANT_OPTION, description: "force quantiser (-1 = none)",
850 opt_type: NAOptionDefinitionType::Int(Some(-1), Some(31)) },
852 name: QUALITY_OPTION, description: "force quality (-1 = none)",
853 opt_type: NAOptionDefinitionType::Int(Some(-1), Some(100)) },
855 name: SET_OPTION, description: "force coding set (-1 = none)",
856 opt_type: NAOptionDefinitionType::Int(Some(-1), Some(3)) },
858 name: SEARCH_MODE_OPTION, description: "motion search mode",
859 opt_type: NAOptionDefinitionType::String(Some(MVSearchMode::get_possible_modes())) },
861 name: SEARCH_RANGE_OPTION, description: "motion search range",
862 opt_type: NAOptionDefinitionType::Int(Some(0), Some(256)) },
864 name: SEARCH_THR_OPTION, description: "motion search cut-off threshold",
865 opt_type: NAOptionDefinitionType::Int(Some(0), Some(1048576)) },
867 name: B_REFINE_OPTION, description: "better ME for B-frames",
868 opt_type: NAOptionDefinitionType::Bool },
870 name: I4_IN_B_OPTION, description: "allow intra 4x4 coding in B-frames",
871 opt_type: NAOptionDefinitionType::Bool },
873 name: B_OFFSET_OPTION, description: "B-frame quantiser offset",
874 opt_type: NAOptionDefinitionType::Int(Some(0), Some(16)) },
877 impl NAOptionHandler for RV40Encoder {
878 fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS }
879 fn set_options(&mut self, options: &[NAOption]) {
880 for option in options.iter() {
881 for opt_def in ENCODER_OPTS.iter() {
882 if opt_def.check(option).is_ok() {
884 DEBUG_LOG_OPTION => {
885 if let NAValue::String(ref strval) = option.value {
886 self.debug_log.parse(strval);
889 SLICE_SIZE_OPTION => {
890 if let NAValue::Int(intval) = option.value {
891 self.slice_bits = intval as u32;
894 FRAME_ORDER_OPTION => {
895 if let NAValue::String(ref strval) = option.value {
896 if let Ok(norder) = strval.parse::<FrameOrder>() {
898 let max_frames = self.order.get_max_grp_len();
899 if max_frames > self.max_grp_bufs {
900 self.frm_pool.set_dec_bufs(max_frames + 3);
901 self.needs_alloc = true;
902 self.max_grp_bufs = max_frames;
905 println!("Invalid order sequence");
910 if let NAValue::Bool(val) = option.value {
915 if let NAValue::Int(val) = option.value {
917 self.brc.set_force_quant(Some(val as usize));
919 self.brc.set_force_quant(None);
924 if let NAValue::Int(val) = option.value {
926 self.brc.set_force_quality(Some(val as u8));
928 self.brc.set_force_quality(None);
933 if let NAValue::Int(val) = option.value {
934 self.force_set = if val != -1 { Some(val as usize) } else { None };
937 SEARCH_MODE_OPTION => {
938 if let NAValue::String(ref strval) = option.value {
939 if let Ok(mmode) = strval.parse::<MVSearchMode>() {
940 self.me.set_mode(mmode);
942 println!("Invalid mode");
946 SEARCH_RANGE_OPTION => {
947 if let NAValue::Int(val) = option.value {
948 self.me.range = val as i16;
951 SEARCH_THR_OPTION => {
952 if let NAValue::Int(val) = option.value {
953 self.me.thresh = val as u32;
957 if let NAValue::Bool(val) = option.value {
962 if let NAValue::Bool(val) = option.value {
967 if let NAValue::Int(val) = option.value {
968 self.brc.b_offset = val as usize;
977 fn query_option_value(&self, name: &str) -> Option<NAValue> {
979 DEBUG_LOG_OPTION => Some(NAValue::String(self.debug_log.to_string())),
980 SLICE_SIZE_OPTION => Some(NAValue::Int(self.slice_bits as i64)),
981 FRAME_ORDER_OPTION => Some(NAValue::String(self.order.to_string())),
982 DEBLOCK_OPTION => Some(NAValue::Bool(self.deblock)),
983 QUANT_OPTION => Some(NAValue::Int(self.brc.get_force_quant().into())),
984 QUALITY_OPTION => Some(NAValue::Int(self.brc.get_force_quality().into())),
985 SET_OPTION => Some(NAValue::Int(if let Some(set) = self.force_set { set as i64 } else { -1 })),
986 SEARCH_MODE_OPTION => Some(NAValue::String(self.me.get_mode().to_string())),
987 SEARCH_THR_OPTION => Some(NAValue::Int(self.me.thresh.into())),
988 SEARCH_RANGE_OPTION => Some(NAValue::Int(self.me.range.into())),
989 B_REFINE_OPTION => Some(NAValue::Bool(self.refine_b)),
990 I4_IN_B_OPTION => Some(NAValue::Bool(self.i4_in_b)),
991 B_OFFSET_OPTION => Some(NAValue::Int(self.brc.b_offset as i64)),
997 pub fn get_encoder() -> Box<dyn NAEncoder + Send> {
998 Box::new(RV40Encoder::new())
1003 use nihav_core::codecs::*;
1004 use nihav_core::demuxers::*;
1005 use nihav_core::muxers::*;
1007 use nihav_codec_support::test::enc_video::*;
1008 use nihav_commonfmt::*;
1010 #[allow(unused_variables)]
1011 fn encode_test(out_name: &'static str, enc_options: &[NAOption], limit: Option<u64>, hash: &[u32; 4]) {
1012 let mut dmx_reg = RegisteredDemuxers::new();
1013 generic_register_all_demuxers(&mut dmx_reg);
1014 let mut dec_reg = RegisteredDecoders::new();
1015 generic_register_all_decoders(&mut dec_reg);
1016 let mut mux_reg = RegisteredMuxers::new();
1017 realmedia_register_all_muxers(&mut mux_reg);
1018 let mut enc_reg = RegisteredEncoders::new();
1019 realmedia_register_all_encoders(&mut enc_reg);
1021 // sample from private collection
1022 let dec_config = DecoderTestParams {
1023 demuxer: "yuv4mpeg",
1024 in_name: "assets/day3b.y4m",
1025 stream_type: StreamType::Video,
1029 let enc_config = EncoderTestParams {
1031 enc_name: "realvideo4",
1035 let dst_vinfo = NAVideoInfo {
1038 format: YUV420_FORMAT,
1042 let enc_params = EncodeParameters {
1043 format: NACodecTypeInfo::Video(dst_vinfo),
1050 //test_encoding_to_file(&dec_config, &enc_config, enc_params, enc_options);
1051 test_encoding_md5(&dec_config, &enc_config, enc_params, enc_options,
1055 fn test_rv40_encoder_simple() {
1056 let enc_options = &[
1057 NAOption { name: super::FRAME_ORDER_OPTION, value: NAValue::String("I".to_owned()) },
1058 NAOption { name: super::DEBLOCK_OPTION, value: NAValue::Bool(false) },
1059 NAOption { name: super::QUANT_OPTION, value: NAValue::Int(17) },
1060 NAOption { name: super::SEARCH_MODE_OPTION, value: NAValue::String("diamond".to_owned()) },
1062 encode_test("rv40simple.rmvb", enc_options, Some(10), &[0x03b0d743, 0x36c20dbb, 0x18fa1c9e, 0x4b2b7324]);
1065 fn test_rv40_encoder_ipb() {
1066 let enc_options = &[
1067 NAOption { name: super::FRAME_ORDER_OPTION, value: NAValue::String("IBPB".to_owned()) },
1068 NAOption { name: super::DEBLOCK_OPTION, value: NAValue::Bool(true) },
1069 NAOption { name: super::QUANT_OPTION, value: NAValue::Int(17) },
1070 NAOption { name: super::SEARCH_MODE_OPTION, value: NAValue::String("hexagon".to_owned()) },
1072 encode_test("rv40ipb.rmvb", enc_options, Some(8), &[0xc382ab0b, 0xbcfbb02a, 0xf12a064f, 0xe6a5c2c3]);
1075 fn test_rv40_encoder_advanced() {
1076 let enc_options = &[
1077 NAOption { name: super::FRAME_ORDER_OPTION, value: NAValue::String("dynamic".to_owned()) },
1078 NAOption { name: super::DEBLOCK_OPTION, value: NAValue::Bool(true) },
1079 NAOption { name: super::SEARCH_MODE_OPTION, value: NAValue::String("umh".to_owned()) },
1081 encode_test("rv40adv.rmvb", enc_options, Some(8), &[0xc4395f49, 0x0536d5f0, 0x32406834, 0xb7b634be]);