pub struct Palettiser {
pal: [[u8; 3]; 256],
nclrs: usize,
+ nbits: u8,
pmode: PMode,
}
#[allow(dead_code)]
impl Palettiser {
pub fn get_default_mode() -> PaletteSearchMode { PaletteSearchMode::Full }
- pub fn new(mode: PaletteSearchMode, pal: &[[u8; 3]; 256], nclrs: usize) -> Self {
+ pub fn new(mode: PaletteSearchMode, pal: &[[u8; 3]; 256], nclrs: usize, nbits: u8) -> Self {
let pmode = match mode {
PaletteSearchMode::Full => {
let mut tab = vec![0; 1 << 24];
PaletteSearchMode::Local => PMode::Local(LocalSearch::new(pal)),
PaletteSearchMode::KDTree => PMode::Tree(KDTree::new(pal)),
};
- Self { pal: *pal, nclrs, pmode }
+ Self { pal: *pal, nclrs, nbits, pmode }
}
pub fn search(&self, pix: [u8; 3]) -> usize {
match &self.pmode {
PMode::Tree(kdt) => kdt.search(pix),
}
}
- pub fn set_pal(&mut self, pal: &[[u8; 3]; 256], nclrs: usize) {
+ pub fn set_pal(&mut self, pal: &[[u8; 3]; 256], nclrs: usize, nbits: u8) {
self.pal.copy_from_slice(pal);
self.nclrs = nclrs;
+ self.nbits = nbits;
match &mut self.pmode {
PMode::Full(ref mut tab) => { gen_full_lut(tab, &pal[..nclrs]); },
PMode::Local(ref mut ls) => { *ls = LocalSearch::new(&pal[..nclrs]); },
PMode::Tree(ref mut kdt) => { *kdt = KDTree::new(&pal[..nclrs]); },
}
}
+ pub fn get_pal_bits(&self) -> u8 { self.nbits }
pub fn palettise_frame(&self, pic_in: &NABufferType, pic_out: &mut NABufferType) -> Result<(), &'static str> {
// todo remap already paletted format
if matches!(pic_in, NABufferType::None) {
let mut pmode = None;
let mut pal = std::array::from_fn(|i| [i as u8; 3]);
let mut pal_is_some = false;
- let mut nclrs = 256;
+ let mut nclrs = 256usize;
for opt in enc_opts.iter() {
match opt.name.as_str() {
"pal.mode" => {
_ => {},
}
}
+ let nbits = nclrs.ilog2() as u8;
for clr in pal.iter_mut().skip(nclrs) {
*clr = [0; 3];
}
if pmode.is_some() || pal_is_some {
- Some(Palettiser::new(pmode.unwrap_or_default(), &pal, nclrs))
+ Some(Palettiser::new(pmode.unwrap_or_default(), &pal, nclrs, nbits))
} else {
None
}
}
}
-pub type PalSegment = (usize, [[u8; 3]; 256], usize);
+pub type PalSegment = (usize, [[u8; 3]; 256], usize, u8);
struct MultiCount {
glbl_hist: [u64; 1 << 15],
debug: bool,
multi: Option<Box<MultiCount>>,
nclrs: usize,
+ nbits: u8,
}
impl ColourCounter {
let mut debug = false;
let mut multi = None;
let mut nclrs = 256;
+ let mut nbits = 8;
for opt in options.iter() {
match opt.name.as_str() {
"counter" => {
println!("palette size requires a numeric argument");
}
},
+ "bits" | "pal_bits" => {
+ if let Some(val) = opt.value.as_deref() {
+ if let Ok(pb) = val.parse::<u8>() {
+ if (1..=8).contains(&pb) {
+ nbits = pb;
+ } else {
+ println!("palette bits should be in range 1..8");
+ }
+ } else {
+ println!("palette bits requires a numeric argument");
+ }
+ } else {
+ println!("palette bits requires a numeric argument");
+ }
+ },
_ => {},
}
}
+ nclrs = nclrs.min(1 << nbits);
let ctype = match counter_type {
"full" => CounterType::Brawn(vec![0; 1 << 24]),
"bucket" => CounterType::Buckets(BucketCounter::new(nclrs)),
scaler: None,
sc_buf: NABufferType::None,
oinfo: NAVideoInfo{ width: 0, height: 0, flipped: false, format: RGB24_FORMAT, bits: 24 },
- ctype, debug, multi, nclrs,
+ ctype, debug, multi, nclrs, nbits,
}
}
pub fn add(&mut self, clr: [u8; 3]) {
let (pal, nclrs) = self.get_pal();
self.reset();
if let Some(ref mut multi) = self.multi {
- multi.pals.push((multi.fstart, pal, nclrs));
+ multi.pals.push((multi.fstart, pal, nclrs, self.nbits));
multi.fstart = multi.frameno - 1;
}
}
Err("not a video frame")
}
}
+ pub fn get_pal_bits(&self) -> u8 { self.nbits }
pub fn get_pal(&self) -> ([[u8; 3]; 256], usize) {
match self.ctype {
CounterType::Buckets(ref bkt) => bkt.get_pal(self.debug),
}
pub fn get_multi_pals(&self) -> Vec<PalSegment> {
let (last_pal, nclrs) = self.get_pal();
+ let nbits = self.get_pal_bits();
if let Some(ref multi) = self.multi {
let mut pals = multi.pals.clone();
if multi.fstart < multi.frameno {
- pals.push((multi.fstart, last_pal, nclrs));
+ pals.push((multi.fstart, last_pal, nclrs, nbits));
}
return pals;
}
- vec![(0, last_pal, nclrs)]
+ vec![(0, last_pal, nclrs, nbits)]
}
}
if let Some(ref mut plt) = self.plt {
if !self.pals.is_empty() && !matches!(buf, NABufferType::None) {
if self.pal_frm >= self.pals[0].0 {
- let (_, pal, nclrs) = self.pals.remove(0);
- plt.set_pal(&pal, nclrs);
+ let (_, pal, nclrs, nbits) = self.pals.remove(0);
+ plt.set_pal(&pal, nclrs, nbits);
}
self.pal_frm += 1;
}
for (src_id, pals) in qsupp.pals.iter() {
if *src_id == iidx && !pals.is_empty() {
if let Some(ref mut p) = plt {
- p.set_pal(&pals[0].1, pals[0].2);
+ p.set_pal(&pals[0].1, pals[0].2, pals[0].3);
} else {
- plt = Some(Palettiser::new(Palettiser::get_default_mode(), &pals[0].1, pals[0].2));
+ plt = Some(Palettiser::new(Palettiser::get_default_mode(), &pals[0].1, pals[0].2, pals[0].3));
}
}
}
if plt.is_some() {
if let NACodecTypeInfo::Video(ref mut vinfo) = oopts.enc_params.format {
if !vinfo.format.is_paletted() {
- println!(" warning: output stream did not specify paletted output, setting pixfmt=pal8");
+ let pal_bpp = plt.as_ref().map(|pp| pp.get_pal_bits()).unwrap_or(8);
+ println!(" warning: output stream did not specify paletted output, setting pixfmt=pal{pal_bpp}");
vinfo.format = PAL8_FORMAT;
+ vinfo.bits = pal_bpp;
}
}
}