From 3c406629cabc3b77f9198646b0f93fc7e486e277 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Fri, 5 Jun 2020 16:00:38 +0200 Subject: [PATCH] cinepakenc: introduce several encoding options --- nihav-commonfmt/src/codecs/cinepakenc.rs | 115 +++++++++++++++++++---- 1 file changed, 99 insertions(+), 16 deletions(-) diff --git a/nihav-commonfmt/src/codecs/cinepakenc.rs b/nihav-commonfmt/src/codecs/cinepakenc.rs index 10e0a36..645bd83 100644 --- a/nihav-commonfmt/src/codecs/cinepakenc.rs +++ b/nihav-commonfmt/src/codecs/cinepakenc.rs @@ -211,11 +211,30 @@ impl MaskWriter { } } +#[derive(Clone,Copy,PartialEq)] +enum QuantMode { + ELBG, + Hybrid, + MedianCut, +} + +impl QuantMode { + fn to_string(&self) -> String { + match *self { + QuantMode::ELBG => "elbg".to_string(), + QuantMode::Hybrid => "hybrid".to_string(), + QuantMode::MedianCut => "mediancut".to_string(), + } + } +} + struct CinepakEncoder { stream: Option, lastfrm: Option>, pkt: Option, frmcount: u8, + key_int: u8, + qmode: QuantMode, quality: u8, nstrips: usize, v1_entries: Vec, @@ -251,6 +270,8 @@ impl CinepakEncoder { pkt: None, lastfrm: None, frmcount: 0, + qmode: QuantMode::ELBG, + key_int: 25, quality: 0, nstrips: 2, v1_entries: Vec::new(), @@ -574,6 +595,28 @@ impl CinepakEncoder { unreachable!(); } } + fn quant_vectors(&mut self) { + match self.qmode { + QuantMode::ELBG => { + let mut elbg_v1: ELBG = ELBG::new(&self.v1_cb); + let mut elbg_v4: ELBG = ELBG::new(&self.v4_cb); + elbg_v1.quantise(&self.v1_entries, &mut self.v1_cur_cb); + elbg_v4.quantise(&self.v4_entries, &mut self.v4_cur_cb); + }, + QuantMode::Hybrid => { + quantise_median_cut::(&self.v1_entries, &mut self.v1_cur_cb); + quantise_median_cut::(&self.v4_entries, &mut self.v4_cur_cb); + let mut elbg_v1: ELBG = ELBG::new(&self.v1_cur_cb); + let mut elbg_v4: ELBG = ELBG::new(&self.v4_cur_cb); + elbg_v1.quantise(&self.v1_entries, &mut self.v1_cur_cb); + elbg_v4.quantise(&self.v4_entries, &mut self.v4_cur_cb); + }, + QuantMode::MedianCut => { + quantise_median_cut::(&self.v1_entries, &mut self.v1_cur_cb); + quantise_median_cut::(&self.v4_entries, &mut self.v4_cur_cb); + }, + }; + } fn encode_intra(&mut self, bw: &mut ByteWriter, in_frm: &NAVideoBuffer) -> EncoderResult { let (width, height) = in_frm.get_dimensions(0); let mut strip_h = (height / self.nstrips + 3) & !3; @@ -600,12 +643,7 @@ impl CinepakEncoder { while start_line < height { self.read_strip(in_frm, start_line, end_line); -// let mut elbg_v1: ELBG = ELBG::new(&self.v1_cb); -// let mut elbg_v4: ELBG = ELBG::new(&self.v4_cb); -// elbg_v1.quantise(&self.v1_entries, &mut self.v1_cur_cb); -// elbg_v4.quantise(&self.v4_entries, &mut self.v4_cur_cb); -quantise_median_cut::(&self.v1_entries, &mut self.v1_cur_cb); -quantise_median_cut::(&self.v4_entries, &mut self.v4_cur_cb); + self.quant_vectors(); if self.grayscale { for cw in self.v1_cur_cb.iter_mut() { cw.u = 128; @@ -735,12 +773,7 @@ quantise_median_cut::(&self.v4_entries, &mut self.v4_cur_cb self.read_strip(in_frm, start_line, end_line); self.calc_skip_dist(in_frm, start_line, end_line); -// let mut elbg_v1: ELBG = ELBG::new(&self.v1_cb); -// let mut elbg_v4: ELBG = ELBG::new(&self.v4_cb); -// elbg_v1.quantise(&self.v1_entries, &mut self.v1_cur_cb); -// elbg_v4.quantise(&self.v4_entries, &mut self.v4_cur_cb); -quantise_median_cut::(&self.v1_entries, &mut self.v1_cur_cb); -quantise_median_cut::(&self.v4_entries, &mut self.v4_cur_cb); + self.quant_vectors(); if self.grayscale { for cw in self.v1_cur_cb.iter_mut() { cw.u = 128; @@ -928,7 +961,7 @@ impl NAEncoder for CinepakEncoder { }; self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf)); self.frmcount += 1; - if self.frmcount == 25 { + if self.frmcount == self.key_int { self.frmcount = 0; } Ok(()) @@ -947,10 +980,60 @@ impl NAEncoder for CinepakEncoder { } } +const ENCODER_OPTS: &[NAOptionDefinition] = &[ + NAOptionDefinition { + name: "key_int", description: "Keyframe interval (0 - automatic)", + opt_type: NAOptionDefinitionType::Int(Some(0), Some(128)) }, + NAOptionDefinition { + name: "nstrips", description: "Number of strips per frame (0 - automatic)", + opt_type: NAOptionDefinitionType::Int(Some(0), Some(16)) }, + NAOptionDefinition { + name: "quant_mode", description: "Quantisation mode", + opt_type: NAOptionDefinitionType::String(Some(&["elbg", "hybrid", "mediancut"])) }, +]; + impl NAOptionHandler for CinepakEncoder { - fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } - fn set_options(&mut self, _options: &[NAOption]) { } - fn query_option_value(&self, _name: &str) -> Option { None } + fn get_supported_options(&self) -> &[NAOptionDefinition] { ENCODER_OPTS } + fn set_options(&mut self, options: &[NAOption]) { + for option in options.iter() { +println!("option {}", option.name); + for opt_def in ENCODER_OPTS.iter() { + if opt_def.check(option).is_ok() { + match option.name { + "key_int" => { + if let NAValue::Int(intval) = option.value { + self.key_int = intval as u8; + } + }, + "nstrips" => { + if let NAValue::Int(intval) = option.value { + self.nstrips = intval as usize; + } + }, + "quant_mode" => { + if let NAValue::String(ref str) = option.value { + match str.as_str() { + "elbg" => self.qmode = QuantMode::ELBG, + "hybrid" => self.qmode = QuantMode::Hybrid, + "mediancut" => self.qmode = QuantMode::MedianCut, + _ => {}, + }; + } + }, + _ => {}, + }; + } + } + } + } + fn query_option_value(&self, name: &str) -> Option { + match name { + "key_int" => Some(NAValue::Int(i64::from(self.key_int))), + "nstrips" => Some(NAValue::Int(self.nstrips as i64)), + "quant_mode" => Some(NAValue::String(self.qmode.to_string())), + _ => None, + } + } } pub fn get_encoder() -> Box { -- 2.30.2