]> git.nihav.org Git - nihav.git/blobdiff - nihav-commonfmt/src/codecs/cinepakenc.rs
cinepakenc: output only the active codebook part
[nihav.git] / nihav-commonfmt / src / codecs / cinepakenc.rs
index ddf2584321afa3881787c4680bc4f559de7fc07f..5ce22eec7bede9c298393c97aed26480894b5dc0 100644 (file)
@@ -360,18 +360,18 @@ impl CinepakEncoder {
         }
         (idx as u8, min_dist)
     }
-    fn can_update_cb(new_cb: &[YUVCode; 256], old_cb: &[YUVCode; 256], cb_size: usize) -> bool {
+    fn can_update_cb(new_cb: &[YUVCode], old_cb: &[YUVCode], cb_size: usize) -> bool {
         let mut skip_count = 0;
         for (new, old) in new_cb.iter().zip(old_cb.iter()) {
             if new == old {
                 skip_count += 1;
             }
         }
-        let full_size = cb_size * 256;
-        let upd_size = cb_size * (256 - skip_count) + 64;
+        let full_size = cb_size * new_cb.len();
+        let upd_size = cb_size * (new_cb.len() - skip_count) + (new_cb.len() + 31) / 32 * 4;
         upd_size < full_size
     }
-    fn write_cb(bw: &mut ByteWriter, mut id: u8, new_cb: &[YUVCode; 256], old_cb: &[YUVCode; 256], grayscale: bool, update: bool) -> EncoderResult<()> {
+    fn write_cb(bw: &mut ByteWriter, mut id: u8, new_cb: &[YUVCode], old_cb: &[YUVCode], grayscale: bool, update: bool, num_elem: usize) -> EncoderResult<()> {
         if grayscale {
             id |= 4;
         }
@@ -382,7 +382,7 @@ impl CinepakEncoder {
         bw.write_u24be(0)?;
         let chunk_pos = bw.tell();
         if !update {
-            for entry in new_cb.iter() {
+            for entry in new_cb.iter().take(num_elem) {
                 bw.write_buf(&entry.y)?;
                 if !grayscale {
                     bw.write_byte(entry.u ^ 0x80)?;
@@ -390,8 +390,8 @@ impl CinepakEncoder {
                 }
             }
         } else {
-            let mut end = 256;
-            for (i, (ncw, ocw)) in new_cb.iter().rev().zip(old_cb.iter().rev()).enumerate() {
+            let mut end = num_elem;
+            for (i, (ncw, ocw)) in new_cb.iter().zip(old_cb.iter()).enumerate().take(num_elem).rev() {
                 if ncw == ocw {
                     end = i;
                 } else {
@@ -708,8 +708,8 @@ impl CinepakEncoder {
             let mut is_intra_strip = start_line == 0;
             let (upd_v1, upd_v4) = if !is_intra_strip {
                     let cb_size = if self.grayscale { 4 } else { 6 };
-                    (Self::can_update_cb(&self.v1_cur_cb[self.cur_strip], &self.v1_cb[self.cur_strip], cb_size),
-                     Self::can_update_cb(&self.v4_cur_cb[self.cur_strip], &self.v4_cb[self.cur_strip], cb_size))
+                    (Self::can_update_cb(&self.v1_cur_cb[self.cur_strip][..self.v1_len], &self.v1_cb[self.cur_strip][..self.v1_len], cb_size),
+                     Self::can_update_cb(&self.v4_cur_cb[self.cur_strip][..self.v4_len], &self.v4_cb[self.cur_strip][..self.v4_len], cb_size))
                 } else {
                     (false, false)
                 };
@@ -724,8 +724,8 @@ impl CinepakEncoder {
             bw.write_u16be((end_line - start_line) as u16)?;
             bw.write_u16be(width as u16)?;
 
-            Self::write_cb(bw, 0x20, &self.v4_cur_cb[self.cur_strip], &self.v4_cb[self.cur_strip], self.grayscale, upd_v4)?;
-            Self::write_cb(bw, 0x22, &self.v1_cur_cb[self.cur_strip], &self.v1_cb[self.cur_strip], self.grayscale, upd_v1)?;
+            Self::write_cb(bw, 0x20, &self.v4_cur_cb[self.cur_strip], &self.v4_cb[self.cur_strip], self.grayscale, upd_v4, self.v4_len)?;
+            Self::write_cb(bw, 0x22, &self.v1_cur_cb[self.cur_strip], &self.v1_cb[self.cur_strip], self.grayscale, upd_v1, self.v1_len)?;
 
             self.render_stripe(true, start_line, end_line);
 
@@ -852,8 +852,8 @@ impl CinepakEncoder {
 
             let (upd_v1, upd_v4) = {
                     let cb_size = if self.grayscale { 4 } else { 6 };
-                    (Self::can_update_cb(&self.v1_cur_cb[self.cur_strip], &self.v1_cb[self.cur_strip], cb_size),
-                     Self::can_update_cb(&self.v4_cur_cb[self.cur_strip], &self.v4_cb[self.cur_strip], cb_size))
+                    (Self::can_update_cb(&self.v1_cur_cb[self.cur_strip][..self.v1_len], &self.v1_cb[self.cur_strip][..self.v1_len], cb_size),
+                     Self::can_update_cb(&self.v4_cur_cb[self.cur_strip][..self.v4_len], &self.v4_cb[self.cur_strip][..self.v4_len], cb_size))
                 };
             bw.write_byte(0x11)?;
             bw.write_u24be(0)?; // strip size
@@ -863,8 +863,8 @@ impl CinepakEncoder {
             bw.write_u16be((end_line - start_line) as u16)?;
             bw.write_u16be(width as u16)?;
 
-            Self::write_cb(bw, 0x20, &self.v4_cur_cb[self.cur_strip], &self.v4_cb[self.cur_strip], self.grayscale, upd_v4)?;
-            Self::write_cb(bw, 0x22, &self.v1_cur_cb[self.cur_strip], &self.v1_cb[self.cur_strip], self.grayscale, upd_v1)?;
+            Self::write_cb(bw, 0x20, &self.v4_cur_cb[self.cur_strip], &self.v4_cb[self.cur_strip], self.grayscale, upd_v4, self.v4_len)?;
+            Self::write_cb(bw, 0x22, &self.v1_cur_cb[self.cur_strip], &self.v1_cb[self.cur_strip], self.grayscale, upd_v1, self.v1_len)?;
 
             self.render_stripe(false, start_line, end_line);
 
@@ -883,7 +883,7 @@ impl CinepakEncoder {
             let mut skip = true;
             for mask in self.masks.masks.iter() {
                 bw.write_u32be(*mask)?;
-                if *mask == 0 { continue; }
+                if *mask == 0 && skip { continue; }
                 let mut bit = 1 << 31;
                 while bit > 0 {
                     if skip {
@@ -925,9 +925,10 @@ impl NAEncoder for CinepakEncoder {
     fn negotiate_format(&self, encinfo: &EncodeParameters) -> EncoderResult<EncodeParameters> {
         match encinfo.format {
             NACodecTypeInfo::None => {
-                let mut ofmt = EncodeParameters::default();
-                ofmt.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, true, YUV420_FORMAT));
-                Ok(ofmt)
+                Ok(EncodeParameters {
+                        format: NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, true, YUV420_FORMAT)),
+                        ..Default::default()
+                    })
             },
             NACodecTypeInfo::Audio(_) => Err(EncoderError::FormatError),
             NACodecTypeInfo::Video(vinfo) => {
@@ -1052,8 +1053,8 @@ impl NAOptionHandler for CinepakEncoder {
                             }
                         },
                         "quant_mode" => {
-                            if let NAValue::String(ref str) = option.value {
-                                match str.as_str() {
+                            if let NAValue::String(ref strval) = option.value {
+                                match strval.as_str() {
                                     "elbg"      => self.qmode = QuantMode::ELBG,
                                     "hybrid"    => self.qmode = QuantMode::Hybrid,
                                     "mediancut" => self.qmode = QuantMode::MedianCut,
@@ -1100,6 +1101,7 @@ mod test {
         let mut enc_reg = RegisteredEncoders::new();
         generic_register_all_encoders(&mut enc_reg);
 
+        // sample: https://samples.mplayerhq.hu/V-codecs/UCOD/TalkingHead_352x288.avi
         let dec_config = DecoderTestParams {
                 demuxer:        "avi",
                 in_name:        "assets/Misc/TalkingHead_352x288.avi",
@@ -1130,6 +1132,6 @@ mod test {
             };
         //test_encoding_to_file(&dec_config, &enc_config, enc_params, &[]);
         test_encoding_md5(&dec_config, &enc_config, enc_params, &[],
-                          &[0xd73cb3c7, 0x30d59f90, 0x1d6e0e28, 0x5b72cc0c]);
+                          &[0x1d4690c8, 0x3b15b4b3, 0xc2df3c7b, 0x1a25b159]);
     }
 }