]> git.nihav.org Git - nihav.git/commitdiff
indeo3enc: improve handling of skipped frames
authorKostya Shishkov <kostya.shishkov@gmail.com>
Sun, 7 Sep 2025 16:59:17 +0000 (18:59 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Sun, 7 Sep 2025 16:59:17 +0000 (18:59 +0200)
nihav-indeo/src/codecs/indeo3enc/mod.rs
nihav-indeo/src/codecs/indeo3enc/ratectl.rs
nihav-indeo/src/codecs/indeo3enc/tree.rs

index 917b2a46bc74fd5202ed795652591e10a28c59af..156418a946855a86f839878e7a15b6bd9c4d3116 100644 (file)
@@ -133,7 +133,8 @@ impl Indeo3Encoder {
             try_again:  false,
         }
     }
-    fn encode_planes(&mut self, dbuf: &mut Vec<u8>, trees: &[Box<Indeo3PrimaryTree>], is_intra: bool) -> EncoderResult<()> {
+    fn encode_planes(&mut self, dbuf: &mut Vec<u8>, trees: &[Box<Indeo3PrimaryTree>], is_intra: bool) -> EncoderResult<bool> {
+        let mut zero = true;
         for (&planeno, tree) in PLANE_ORDER.iter().zip(trees.iter()) {
             let offset = dbuf.len();
             let ref_plane = &self.pframe.plane[planeno];
@@ -149,6 +150,7 @@ impl Indeo3Encoder {
 
             let mut iw = Indeo3Writer::new(dbuf);
             self.cframe.plane[planeno].encode_tree(&mut iw, tree, &mut self.cenc, ref_plane);
+            zero &= self.cframe.plane[planeno].zero;
             drop(iw);
             while (dbuf.len() & 3) != 0 {
                 dbuf.push(0);
@@ -157,17 +159,21 @@ impl Indeo3Encoder {
             let plane_off = PLANE_OFFSETS + 4 * if planeno > 0 { planeno ^ 3 } else { 0 };
             write_u32le(&mut dbuf[plane_off..], (offset - OS_HEADER_SIZE) as u32)?;
         }
-
-        let mut checksum = 0;
-        for plane in self.cframe.plane.iter() {
-            checksum ^= plane.checksum();
+        if zero {
+            // skip frame
+            dbuf.truncate(48);
+        } else {
+            let mut checksum = 0;
+            for plane in self.cframe.plane.iter() {
+                checksum ^= plane.checksum();
+            }
+            write_u16le(&mut dbuf[26..], checksum * 2)?;
         }
-        write_u16le(&mut dbuf[26..], checksum * 2)?;
 
         let size = (dbuf.len() - OS_HEADER_SIZE) as u32;
         write_u32le(&mut dbuf[8..], self.frameno ^ HDR_FIELD_2 ^ FRMH_TAG ^ size)?;
         write_u32le(&mut dbuf[12..], size)?;
-        write_u32le(&mut dbuf[20..], size * 8)?;
+        write_u32le(&mut dbuf[20..], if !zero { size * 8 } else { 0x80 })?;
 
         if is_intra {
             dbuf.extend_from_slice(b"\x0d\x0aVer 3.99.00.00\x0d\x0a\x00");
@@ -176,7 +182,7 @@ impl Indeo3Encoder {
             }
         }
 
-        Ok(())
+        Ok(zero)
     }
 }
 
@@ -272,7 +278,7 @@ impl NAEncoder for Indeo3Encoder {
             write_u32le(&mut dbuf[20..], size * 8)?;
 
             let fsize = dbuf.len() as u32;
-            self.rc.advance(fsize);
+            self.rc.advance(fsize, true);
             self.frameno += 1;
 
             self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, false, dbuf));
@@ -352,7 +358,7 @@ impl NAEncoder for Indeo3Encoder {
                 trees.push(tree);
             }
 
-            self.encode_planes(&mut dbuf, &trees, is_intra)?;
+            let mut skipped = self.encode_planes(&mut dbuf, &trees, is_intra)?;
 
             let cur_quant = self.cenc.quant.unwrap_or(42);
             if self.try_again && !is_intra && cur_quant < 8 {
@@ -369,7 +375,7 @@ impl NAEncoder for Indeo3Encoder {
                             };
                         self.cenc.quant = Some(new_quant);
                         dbuf.truncate(OS_HEADER_SIZE + BITSTREAM_HEADER_SIZE);
-                        self.encode_planes(&mut dbuf, &trees, is_intra)?;
+                        skipped = self.encode_planes(&mut dbuf, &trees, is_intra)?;
                     }
                 }
             }
@@ -389,7 +395,7 @@ impl NAEncoder for Indeo3Encoder {
             self.frameno += 1;
 
             let fsize = dbuf.len() as u32;
-            self.rc.advance(fsize);
+            self.rc.advance(fsize, skipped);
 
             self.pkt = Some(NAPacket::new(self.stream.clone().unwrap(), frm.ts, is_intra, dbuf));
             Ok(())
index 4bb74c0d32c935dbbd8a1c3c0c41a6f191c321bf..72bed261b0e4bc967b127c23d6be23fb2a37ef77 100644 (file)
@@ -46,14 +46,16 @@ impl RateControl {
         let is_intra = self.key_int == 0 || (frameno % self.key_int) == 0;
         (is_intra, self.quality)
     }
-    pub fn advance(&mut self, size: u32) {
+    pub fn advance(&mut self, size: u32, skipped: bool) {
         if self.bitrate != 0 {
-            let expected = self.get_expected_size();
-            let cur_quant = self.quality.unwrap_or(0);
-            if (size > expected + expected / 10) && (cur_quant < 7) {
-                self.quality = Some(cur_quant + 1);
-            } else if (size < expected - expected / 10) && (cur_quant > 0) {
-                self.quality = Some(cur_quant - 1);
+            if !skipped {
+                let expected = self.get_expected_size();
+                let cur_quant = self.quality.unwrap_or(0);
+                if (size > expected + expected / 10) && (cur_quant < 7) {
+                    self.quality = Some(cur_quant + 1);
+                } else if (size < expected - expected / 10) && (cur_quant > 0) {
+                    self.quality = Some(cur_quant - 1);
+                }
             }
 
             self.f_pos += self.tb_num;
index d6346d972c884f0f1575b82858d224733744b072..6515a7ed1db5e90f9c76c094e07c80d587bb0ae3 100644 (file)
@@ -143,6 +143,7 @@ pub struct Plane {
     pub height: usize,
     pub stripw: u8,
     pub mvs:    Vec<(MV, u16)>,
+    pub zero:   bool,
 }
 
 fn ssd(a: u8, b: u8) -> u32 {
@@ -359,6 +360,7 @@ impl Plane {
     }
     pub fn encode_tree(&mut self, iw: &mut Indeo3Writer, tree: &Indeo3PrimaryTree, cenc: &mut CellEncoder, refp: &Plane) {
         let cell = Indeo3Cell::new(self.width, self.height);
+        self.zero = true;
         self.encode_pri(iw, cell, tree, cenc, refp);
     }
     fn encode_pri(&mut self, iw: &mut Indeo3Writer, mut cell: Indeo3Cell, tree: &Indeo3PrimaryTree, cenc: &mut CellEncoder, refp: &Plane) {
@@ -378,6 +380,7 @@ impl Plane {
             Indeo3PrimaryTree::AbsFill(sec) => {
                 iw.put_2bits(2);
                 cell.intra = true;
+                self.zero = false;
                 self.encode_sec(iw, cell, sec, cenc);
             }
             Indeo3PrimaryTree::RelFill(mv, sec) => {
@@ -390,6 +393,7 @@ impl Plane {
                 } else {
                     iw.put_2bits(2);
                     cell.intra = true;
+                    self.zero = false;
                     self.encode_sec(iw, cell, sec, cenc);
                 }
             },
@@ -415,6 +419,7 @@ impl Plane {
             },
             Indeo3SecondaryTree::VQData(mode) => {
                 iw.put_2bits(3);
+                self.zero = false;
                 self.encode_cell_data_intra(iw, cell, cenc, *mode);
             },
         }
@@ -431,11 +436,15 @@ impl Plane {
                 iw.put_2bits(2);
                 iw.put_2bits(*mode);
                 cenc.read_mv_buffer(refp, cell, mv);
+                if mv.x != 0 || mv.y != 0 {
+                    self.zero = false;
+                }
                 cenc.null_mv();
                 cenc.put_buffer(self);
             },
             Indeo3SecondaryTree::VQData(_mode) => {
                 iw.put_2bits(3);
+                self.zero = false;
                 self.encode_cell_data_inter(iw, cell, cenc, mv, refp);
             },
         }