qmode: QuantMode,
quality: u8,
nstrips: usize,
+ force_v1: bool,
cur_strip: usize,
v1_entries: Vec<YUVCode>,
v4_entries: Vec<YUVCode>,
key_int: 25,
quality: 0,
nstrips: 2,
+ force_v1: false,
cur_strip: 0,
v1_entries: Vec::new(),
v4_entries: Vec::new(),
}
(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;
}
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)?;
}
}
} 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 {
}
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;
+ }
},
};
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;
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)
};
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);
} 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;
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
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);
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 {
}
}
}
+ 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),
fn encode(&mut self, frm: &NAFrame) -> EncoderResult<()> {
let buf = frm.get_buffer();
if let Some(ref vbuf) = buf.get_vbuf() {
+ if self.nstrips == 0 {
+ let (w, h) = vbuf.get_dimensions(0);
+ self.nstrips = ((((w * h) >> 4) + 1200) / 2400).max(1).min(3);
+ let strip_h = ((h + self.nstrips - 1) / self.nstrips + 3) & !3;
+ self.nstrips = (h + strip_h - 1) / strip_h;
+ }
let cur_strips = self.v1_cb.len();
if cur_strips != self.nstrips {
self.frmcount = 0;
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 {
};
}
},
+ "force_v1" => {
+ if let NAValue::Bool(val) = option.value {
+ self.force_v1 = val;
+ }
+ },
_ => {},
};
}
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,
}
}
};
//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]);
}
}