introduce a way for encoder to manifest its capabilities
[nihav.git] / nihav-commonfmt / src / codecs / cinepakenc.rs
index 5ce22eec7bede9c298393c97aed26480894b5dc0..f4ac9b24fd375c52b4f5717fcb4aac1fbd3e2e42 100644 (file)
@@ -237,6 +237,7 @@ struct CinepakEncoder {
     qmode:      QuantMode,
     quality:    u8,
     nstrips:    usize,
+    force_v1:   bool,
     cur_strip:  usize,
     v1_entries: Vec<YUVCode>,
     v4_entries: Vec<YUVCode>,
@@ -277,6 +278,7 @@ impl CinepakEncoder {
             key_int:    25,
             quality:    0,
             nstrips:    2,
+            force_v1:   false,
             cur_strip:  0,
             v1_entries: Vec::new(),
             v4_entries: Vec::new(),
@@ -615,19 +617,35 @@ impl CinepakEncoder {
                 }
 
                 self.v1_len = elbg_v1.quantise(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]);
-                self.v4_len = elbg_v4.quantise(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]);
+                self.v4_len = if !self.force_v1 { elbg_v4.quantise(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]) } else { 0 };
             },
             QuantMode::Hybrid => {
-                quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]);
-                quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]);
-                let mut elbg_v1: ELBG<YUVCode, YUVCodeSum> = ELBG::new(&self.v1_cur_cb[self.cur_strip]);
-                let mut elbg_v4: ELBG<YUVCode, YUVCodeSum> = ELBG::new(&self.v4_cur_cb[self.cur_strip]);
-                self.v1_len = elbg_v1.quantise(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]);
-                self.v4_len = elbg_v4.quantise(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]);
+                let v1_len = quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]);
+                let v4_len = if !self.force_v1 {
+                        quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip])
+                    } else {
+                        0
+                    };
+                self.v1_len = if v1_len < 256 {
+                        v1_len
+                    } else {
+                        let mut elbg_v1: ELBG<YUVCode, YUVCodeSum> = ELBG::new(&self.v1_cur_cb[self.cur_strip]);
+                        elbg_v1.quantise(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip])
+                    };
+                self.v4_len = if v4_len < 256 {
+                        v4_len
+                    } else {
+                        let mut elbg_v4: ELBG<YUVCode, YUVCodeSum> = ELBG::new(&self.v4_cur_cb[self.cur_strip]);
+                        elbg_v4.quantise(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip])
+                    };
             },
             QuantMode::MedianCut => {
                 self.v1_len = quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]);
-                self.v4_len = quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]);
+                if !self.force_v1 {
+                    self.v4_len = quantise_median_cut::<YUVCode, YUVCodeSum>(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]);
+                } else {
+                    self.v4_len = 0;
+                }
             },
         };
 
@@ -683,7 +701,7 @@ impl CinepakEncoder {
 
             for (v1_entry, v4_entries) in self.v1_entries.iter().zip(self.v4_entries.chunks(4)) {
                 let (v1_idx, v1_dist) = Self::find_nearest(&self.v1_cur_cb[self.cur_strip][..self.v1_len], *v1_entry);
-                if v1_dist == 0 {
+                if v1_dist == 0 || self.force_v1 {
                     self.masks.put_v1();
                     self.v1_idx.push(v1_idx);
                     continue;
@@ -828,7 +846,7 @@ impl CinepakEncoder {
                 } else {
                     self.masks.put_inter(false);
                 }
-                if v1_dist == 0 {
+                if v1_dist == 0 || self.force_v1 {
                     self.masks.put_v1();
                     self.v1_idx.push(v1_idx);
                     continue;
@@ -940,6 +958,7 @@ impl NAEncoder for CinepakEncoder {
             }
         }
     }
+    fn get_capabilities(&self) -> u64 { 0 }
     fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult<NAStreamRef> {
         match encinfo.format {
             NACodecTypeInfo::None => Err(EncoderError::FormatError),
@@ -1033,6 +1052,9 @@ const ENCODER_OPTS: &[NAOptionDefinition] = &[
     NAOptionDefinition {
         name: "quant_mode", description: "Quantisation mode",
         opt_type: NAOptionDefinitionType::String(Some(&["elbg", "hybrid", "mediancut"])) },
+    NAOptionDefinition {
+        name: "force_v1", description: "Force coarse (V1-only) mode",
+        opt_type: NAOptionDefinitionType::Bool },
 ];
 
 impl NAOptionHandler for CinepakEncoder {
@@ -1062,6 +1084,11 @@ impl NAOptionHandler for CinepakEncoder {
                                 };
                             }
                         },
+                        "force_v1" => {
+                            if let NAValue::Bool(val) = option.value {
+                                self.force_v1 = val;
+                            }
+                        },
                         _ => {},
                     };
                 }
@@ -1073,6 +1100,7 @@ impl NAOptionHandler for CinepakEncoder {
             KEYFRAME_OPTION => 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())),
+            "force_v1" => Some(NAValue::Bool(self.force_v1)),
             _ => None,
         }
     }