X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-core%2Fsrc%2Fscale%2Fmod.rs;h=2192b187dfe14c1054baff8c412c1fb5889ea7af;hb=4abaf99e414dd4dd270e2703ee5e799a61aada88;hp=2b5f1b7f9854e3ea251e811e8424f963968b79ed;hpb=d24468d9dbd54f5cbe414649ff061699337fa7fe;p=nihav.git diff --git a/nihav-core/src/scale/mod.rs b/nihav-core/src/scale/mod.rs index 2b5f1b7..2192b18 100644 --- a/nihav-core/src/scale/mod.rs +++ b/nihav-core/src/scale/mod.rs @@ -1,15 +1,41 @@ +//! Image conversion functionality. + +//! # Examples +//! +//! Convert input image into YUV one and scale down two times. +//! ```no_run +//! use nihav_core::scale::*; +//! use nihav_core::formats::{RGB24_FORMAT, YUV420_FORMAT}; +//! use nihav_core::frame::{alloc_video_buffer, NAVideoInfo}; +//! +//! let mut in_pic = alloc_video_buffer(NAVideoInfo::new(640, 480, false, RGB24_FORMAT), 4).unwrap(); +//! let mut out_pic = alloc_video_buffer(NAVideoInfo::new(320, 240, false, YUV420_FORMAT), 4).unwrap(); +//! let in_fmt = get_scale_fmt_from_pic(&in_pic); +//! let out_fmt = get_scale_fmt_from_pic(&out_pic); +//! let mut scaler = NAScale::new(in_fmt, out_fmt).unwrap(); +//! scaler.convert(&in_pic, &mut out_pic).unwrap(); +//! ``` use crate::frame::*; mod kernel; mod colorcvt; mod repack; +#[allow(clippy::module_inception)] mod scale; +mod palette; + +pub use crate::scale::palette::{palettise_frame, QuantisationMode, PaletteSearchMode}; + +/// Image format information used by the converter. #[derive(Clone,Copy,PartialEq)] pub struct ScaleInfo { + /// Pixel format description. pub fmt: NAPixelFormaton, + /// Image width. pub width: usize, + /// Image height. pub height: usize, } @@ -19,16 +45,23 @@ impl std::fmt::Display for ScaleInfo { } } +/// A list specifying general image conversion errors. #[derive(Debug,Clone,Copy,PartialEq)] #[allow(dead_code)] pub enum ScaleError { + /// Input or output buffer contains no image data. NoFrame, + /// Allocation failed. AllocError, + /// Invalid argument. InvalidArgument, + /// Feature is not implemented. NotImplemented, + /// Internal implementation bug. Bug, } +/// A specialised `Result` type for image conversion operations. pub type ScaleResult = Result; /*trait Kernel { @@ -56,6 +89,7 @@ const KERNELS: &[KernelDesc] = &[ KernelDesc { name: "pack", create: repack::create_pack }, KernelDesc { name: "unpack", create: repack::create_unpack }, KernelDesc { name: "depal", create: repack::create_depal }, + KernelDesc { name: "palette", create: palette::create_palettise }, KernelDesc { name: "scale", create: scale::create_scale }, KernelDesc { name: "rgb_to_yuv", create: colorcvt::create_rgb2yuv }, KernelDesc { name: "yuv_to_rgb", create: colorcvt::create_yuv2rgb }, @@ -68,6 +102,7 @@ struct Stage { worker: Box, } +/// Converts input picture information into format used by scaler. pub fn get_scale_fmt_from_pic(pic: &NABufferType) -> ScaleInfo { let info = pic.get_video_info().unwrap(); ScaleInfo { fmt: info.get_format(), width: info.get_width(), height: info.get_height() } @@ -105,6 +140,7 @@ impl Stage { } } +/// Image format converter. pub struct NAScale { fmt_in: ScaleInfo, fmt_out: ScaleInfo, @@ -197,6 +233,7 @@ println!("convert {} -> {}", ifmt, ofmt); let needs_convert = inname != outname; let scale_before_cvt = is_better_fmt(&ifmt, &ofmt) && needs_convert && (ofmt.fmt.get_max_subsampling() == 0); + let needs_palettise = ofmt.fmt.palette; //todo stages for model and gamma conversion let mut stages: Option = None; @@ -234,12 +271,18 @@ println!("[adding scale]"); cur_fmt = new_stage.fmt_out; add_stage!(stages, new_stage); } - if needs_pack { + if needs_pack && !needs_palettise { println!("[adding pack]"); let new_stage = Stage::new("pack", &cur_fmt, &ofmt)?; //cur_fmt = new_stage.fmt_out; add_stage!(stages, new_stage); } + if needs_palettise { +println!("[adding palettise]"); + let new_stage = Stage::new("palette", &cur_fmt, &ofmt)?; + //cur_fmt = new_stage.fmt_out; + add_stage!(stages, new_stage); + } if let Some(ref mut head) = stages { head.drop_last_tmp(); @@ -261,6 +304,7 @@ fn swap_plane(data: &mut [T], stride: usize, h: usize, line0: &mut [T], } } +/// Flips the picture contents. pub fn flip_picture(pic: &mut NABufferType) -> ScaleResult<()> { match pic { NABufferType::Video(ref mut vb) => { @@ -317,6 +361,7 @@ pub fn flip_picture(pic: &mut NABufferType) -> ScaleResult<()> { } impl NAScale { + /// Constructs a new `NAScale` instance. pub fn new(fmt_in: ScaleInfo, fmt_out: ScaleInfo) -> ScaleResult { let pipeline; let just_convert = (fmt_in.width == fmt_out.width) && (fmt_in.height == fmt_out.height); @@ -327,9 +372,13 @@ impl NAScale { } Ok(Self { fmt_in, fmt_out, just_convert, pipeline }) } + /// Checks whether requested conversion operation is needed at all. pub fn needs_processing(&self) -> bool { self.pipeline.is_some() } + /// Returns the input image format. pub fn get_in_fmt(&self) -> ScaleInfo { self.fmt_in } + /// Returns the output image format. pub fn get_out_fmt(&self) -> ScaleInfo { self.fmt_out } + /// Performs the image format conversion. pub fn convert(&mut self, pic_in: &NABufferType, pic_out: &mut NABufferType) -> ScaleResult<()> { let in_info = pic_in.get_video_info(); let out_info = pic_out.get_video_info(); @@ -443,4 +492,23 @@ mod test { assert_eq!(odata[uoff], 154); assert_eq!(odata[voff], 103); } + #[test] + fn test_scale_and_convert_to_pal() { + let mut in_pic = alloc_video_buffer(NAVideoInfo::new(7, 3, false, YUV420_FORMAT), 3).unwrap(); + fill_pic(&mut in_pic, 142); + let mut out_pic = alloc_video_buffer(NAVideoInfo::new(4, 4, false, PAL8_FORMAT), 0).unwrap(); + fill_pic(&mut out_pic, 0); + let ifmt = get_scale_fmt_from_pic(&in_pic); + let ofmt = get_scale_fmt_from_pic(&out_pic); + let mut scaler = NAScale::new(ifmt, ofmt).unwrap(); + scaler.convert(&in_pic, &mut out_pic).unwrap(); + let obuf = out_pic.get_vbuf().unwrap(); + let dataoff = obuf.get_offset(0); + let paloff = obuf.get_offset(1); + let odata = obuf.get_data(); + assert_eq!(odata[dataoff], 0); + assert_eq!(odata[paloff], 157); + assert_eq!(odata[paloff + 1], 99); + assert_eq!(odata[paloff + 2], 170); + } }