From: Kostya Shishkov Date: Sat, 25 Apr 2026 16:33:17 +0000 (+0200) Subject: allow low-bits palette modes as well X-Git-Url: https://git.nihav.org/?a=commitdiff_plain;h=2658430b184725eca43d2ac78a7f13b37da4b4f2;p=nihav-encoder.git allow low-bits palette modes as well --- diff --git a/src/palettise.rs b/src/palettise.rs index 5342c1c..23cdc77 100644 --- a/src/palettise.rs +++ b/src/palettise.rs @@ -218,6 +218,7 @@ enum PMode { pub struct Palettiser { pal: [[u8; 3]; 256], nclrs: usize, + nbits: u8, pmode: PMode, } @@ -249,7 +250,7 @@ impl LookupCache { #[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]; @@ -259,7 +260,7 @@ impl Palettiser { 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 { @@ -271,15 +272,17 @@ impl Palettiser { 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) { @@ -382,7 +385,7 @@ pub fn create_palettiser(enc_opts: &[OptionArgs]) -> Option { 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" => { @@ -463,11 +466,12 @@ pub fn create_palettiser(enc_opts: &[OptionArgs]) -> Option { _ => {}, } } + 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 } @@ -707,7 +711,7 @@ impl BucketCounter { } } -pub type PalSegment = (usize, [[u8; 3]; 256], usize); +pub type PalSegment = (usize, [[u8; 3]; 256], usize, u8); struct MultiCount { glbl_hist: [u64; 1 << 15], @@ -780,6 +784,7 @@ pub struct ColourCounter { debug: bool, multi: Option>, nclrs: usize, + nbits: u8, } impl ColourCounter { @@ -788,6 +793,7 @@ 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" => { @@ -861,9 +867,25 @@ impl ColourCounter { println!("palette size requires a numeric argument"); } }, + "bits" | "pal_bits" => { + if let Some(val) = opt.value.as_deref() { + if let Ok(pb) = val.parse::() { + 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)), @@ -873,7 +895,7 @@ impl ColourCounter { 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]) { @@ -920,7 +942,7 @@ impl ColourCounter { 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; } } @@ -965,6 +987,7 @@ impl ColourCounter { 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), @@ -994,13 +1017,14 @@ impl ColourCounter { } pub fn get_multi_pals(&self) -> Vec { 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)] } } diff --git a/src/transcoder.rs b/src/transcoder.rs index b70981e..1cff30c 100644 --- a/src/transcoder.rs +++ b/src/transcoder.rs @@ -247,8 +247,8 @@ impl EncoderInterface for VideoEncodeContext { 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; } @@ -980,9 +980,9 @@ impl Transcoder { 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)); } } } @@ -990,8 +990,10 @@ impl Transcoder { 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; } } }