X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-commonfmt%2Fsrc%2Fcodecs%2Fcinepakenc.rs;h=f4ac9b24fd375c52b4f5717fcb4aac1fbd3e2e42;hb=2757a0289c980aeba002609c777815b51ace8e56;hp=28f9c9309e4f60ced7e1774ad59462775540d0b8;hpb=2931e237d609968086a560eb2f9c7beaf320e44b;p=nihav.git diff --git a/nihav-commonfmt/src/codecs/cinepakenc.rs b/nihav-commonfmt/src/codecs/cinepakenc.rs index 28f9c93..f4ac9b2 100644 --- a/nihav-commonfmt/src/codecs/cinepakenc.rs +++ b/nihav-commonfmt/src/codecs/cinepakenc.rs @@ -237,6 +237,7 @@ struct CinepakEncoder { qmode: QuantMode, quality: u8, nstrips: usize, + force_v1: bool, cur_strip: usize, v1_entries: Vec, v4_entries: Vec, @@ -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(), @@ -360,18 +362,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 +384,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 +392,8 @@ impl CinepakEncoder { } } } else { - let mut end = 256; - for (i, (ncw, ocw)) in new_cb.iter().zip(old_cb.iter()).enumerate().rev() { + 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 { @@ -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::(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]); - quantise_median_cut::(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]); - let mut elbg_v1: ELBG = ELBG::new(&self.v1_cur_cb[self.cur_strip]); - let mut elbg_v4: ELBG = 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::(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]); + let v4_len = if !self.force_v1 { + quantise_median_cut::(&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 = 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 = 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::(&self.v1_entries, &mut self.v1_cur_cb[self.cur_strip]); - self.v4_len = quantise_median_cut::(&self.v4_entries, &mut self.v4_cur_cb[self.cur_strip]); + if !self.force_v1 { + self.v4_len = quantise_median_cut::(&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; @@ -708,8 +726,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 +742,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); @@ -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; @@ -852,8 +870,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 +881,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); @@ -940,6 +958,7 @@ impl NAEncoder for CinepakEncoder { } } } + fn get_capabilities(&self) -> u64 { 0 } fn init(&mut self, stream_id: u32, encinfo: EncodeParameters) -> EncoderResult { 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, } } @@ -1132,6 +1160,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]); } }