1use std::{borrow::Cow, fmt::Debug};
2
3use bytemuck::{self, Pod};
4use pic_scale::{BufferStore, ImageStore, ImageStoreMut, LinearScaler, ResamplingFunction, Scaling, ScalingU16};
5
6use super::{
7 frame::VideoFrame,
8 video::{PixelFormat, ScaleFilter, VideoFrameDescriptor},
9};
10use crate::{
11 error::Error,
12 frame::{DataMappable, Frame, FrameData, MappedPlane},
13 FrameDescriptor, Result,
14};
15
16impl From<ScaleFilter> for ResamplingFunction {
17 fn from(filter: ScaleFilter) -> Self {
18 match filter {
19 ScaleFilter::Nearest => ResamplingFunction::Nearest,
20 ScaleFilter::Bilinear => ResamplingFunction::Bilinear,
21 ScaleFilter::Bicubic => ResamplingFunction::Bicubic,
22 }
23 }
24}
25
26fn into_image_store<'a, T, const N: usize>(src: &'a MappedPlane, width: u32, height: u32) -> Result<ImageStore<'a, T, N>>
27where
28 T: Debug + Pod,
29{
30 Ok(ImageStore::<T, N> {
31 buffer: Cow::Borrowed(bytemuck::cast_slice(src.data().unwrap())),
32 channels: N,
33 width: width as usize,
34 height: height as usize,
35 stride: src.stride().unwrap() / size_of::<T>(),
36 bit_depth: 0,
37 })
38}
39
40fn into_image_store_mut<'a, T, const N: usize>(dst: &'a mut MappedPlane, width: u32, height: u32) -> Result<ImageStoreMut<'a, T, N>>
41where
42 T: Debug + Pod,
43{
44 let stride = dst.stride().unwrap() / size_of::<T>();
45
46 Ok(ImageStoreMut::<T, N> {
47 buffer: BufferStore::Borrowed(bytemuck::cast_slice_mut(dst.data_mut().unwrap())),
48 channels: N,
49 width: width as usize,
50 height: height as usize,
51 stride,
52 bit_depth: 0,
53 })
54}
55
56impl Frame<'_> {
57 pub fn scale_to(&self, dst: &mut Frame<'_>, scale_filter: ScaleFilter) -> Result<()> {
58 let (FrameDescriptor::Video(src_desc), FrameDescriptor::Video(dst_desc)) = (&self.desc, &dst.desc) else {
59 return Err(Error::Invalid("not video frame".to_string()));
60 };
61
62 VideoFrame::scale_to_internal(src_desc, &self.data, dst_desc, &mut dst.data, scale_filter)
63 }
64}
65
66impl VideoFrame<'_> {
67 fn scale_to_internal(
68 src_desc: &VideoFrameDescriptor,
69 src_data: &FrameData,
70 dst_desc: &VideoFrameDescriptor,
71 dst_data: &mut FrameData,
72 scale_filter: ScaleFilter,
73 ) -> Result<()> {
74 if src_desc.format != dst_desc.format {
75 return Err(Error::Invalid("pixel format mismatch".to_string()));
76 }
77
78 let guard = src_data.map().map_err(|_| Error::Invalid("not readable".into()))?;
79 let mut dst_guard = dst_data.map_mut().map_err(|_| Error::Invalid("not writable".into()))?;
80 let src_planes = guard.planes().unwrap();
81 let mut dst_planes = dst_guard.planes_mut().unwrap();
82
83 let resampling_function: ResamplingFunction = scale_filter.into();
84 let scaler = LinearScaler::new(resampling_function);
85
86 let format = src_desc.format;
87 match format {
88 PixelFormat::ARGB32 | PixelFormat::BGRA32 | PixelFormat::ABGR32 | PixelFormat::RGBA32 => {
89 let src = into_image_store::<u8, 4>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
90 let mut dst = into_image_store_mut::<u8, 4>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
91 scaler.resize_rgba(&src, &mut dst, true).map_err(|e| Error::Invalid(e.to_string()))
92 }
93 PixelFormat::RGB24 | PixelFormat::BGR24 => {
94 let src = into_image_store::<u8, 3>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
95 let mut dst = into_image_store_mut::<u8, 3>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
96 scaler.resize_rgb(&src, &mut dst).map_err(|e| Error::Invalid(e.to_string()))
97 }
98 PixelFormat::I420 |
99 PixelFormat::I422 |
100 PixelFormat::I444 |
101 PixelFormat::I440 |
102 PixelFormat::YV12 |
103 PixelFormat::YV16 |
104 PixelFormat::YV24 => {
105 let (src_chroma_width, src_chroma_height) = format.calc_chroma_dimensions(src_desc.width().get(), src_desc.height().get());
106 let (dst_chroma_width, dst_chroma_height) = format.calc_chroma_dimensions(dst_desc.width().get(), dst_desc.height().get());
107 let src_y = into_image_store::<u8, 1>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
108 let src_u = into_image_store::<u8, 1>(&src_planes.planes[1], src_chroma_width, src_chroma_height)?;
109 let src_v = into_image_store::<u8, 1>(&src_planes.planes[2], src_chroma_width, src_chroma_height)?;
110 let mut dst_y = into_image_store_mut::<u8, 1>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
111 scaler.resize_plane(&src_y, &mut dst_y).map_err(|e| Error::Invalid(e.to_string()))?;
112 let mut dst_u = into_image_store_mut::<u8, 1>(&mut dst_planes.planes[1], dst_chroma_width, dst_chroma_height)?;
113 scaler.resize_plane(&src_u, &mut dst_u).map_err(|e| Error::Invalid(e.to_string()))?;
114 let mut dst_v = into_image_store_mut::<u8, 1>(&mut dst_planes.planes[2], dst_chroma_width, dst_chroma_height)?;
115 scaler.resize_plane(&src_v, &mut dst_v).map_err(|e| Error::Invalid(e.to_string()))?;
116 Ok(())
117 }
118 PixelFormat::NV12 | PixelFormat::NV21 | PixelFormat::NV16 | PixelFormat::NV61 | PixelFormat::NV24 | PixelFormat::NV42 => {
119 let (src_chroma_width, src_chroma_height) = format.calc_chroma_dimensions(src_desc.width().get(), src_desc.height().get());
120 let (dst_chroma_width, dst_chroma_height) = format.calc_chroma_dimensions(dst_desc.width().get(), dst_desc.height().get());
121 let src_y = into_image_store::<u8, 1>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
122 let src_uv = into_image_store::<u8, 2>(&src_planes.planes[1], src_chroma_width, src_chroma_height)?;
123 let mut dst_y = into_image_store_mut::<u8, 1>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
124 scaler.resize_plane(&src_y, &mut dst_y).map_err(|e| Error::Invalid(e.to_string()))?;
125 let mut dst_uv = into_image_store_mut::<u8, 2>(&mut dst_planes.planes[1], dst_chroma_width, dst_chroma_height)?;
126 scaler.resize_cbcr8(&src_uv, &mut dst_uv).map_err(|e| Error::Invalid(e.to_string()))?;
127 Ok(())
128 }
129 PixelFormat::ARGB64 | PixelFormat::BGRA64 | PixelFormat::ABGR64 | PixelFormat::RGBA64 => {
130 let src = into_image_store::<u16, 4>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
131 let mut dst = into_image_store_mut::<u16, 4>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
132 scaler.resize_rgba_u16(&src, &mut dst, true).map_err(|e| Error::Invalid(e.to_string()))
133 }
134 PixelFormat::I010 |
135 PixelFormat::I210 |
136 PixelFormat::I410 |
137 PixelFormat::I44010 |
138 PixelFormat::I012 |
139 PixelFormat::I212 |
140 PixelFormat::I412 |
141 PixelFormat::I44012 |
142 PixelFormat::I016 |
143 PixelFormat::I216 |
144 PixelFormat::I416 |
145 PixelFormat::I44016 => {
146 let (src_chroma_width, src_chroma_height) = format.calc_chroma_dimensions(src_desc.width().get(), src_desc.height().get());
147 let (dst_chroma_width, dst_chroma_height) = format.calc_chroma_dimensions(dst_desc.width().get(), dst_desc.height().get());
148 let src_y = into_image_store::<u16, 1>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
149 let src_u = into_image_store::<u16, 1>(&src_planes.planes[1], src_chroma_width, src_chroma_height)?;
150 let src_v = into_image_store::<u16, 1>(&src_planes.planes[2], src_chroma_width, src_chroma_height)?;
151 let mut dst_y = into_image_store_mut::<u16, 1>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
152 scaler.resize_plane_u16(&src_y, &mut dst_y).map_err(|e| Error::Invalid(e.to_string()))?;
153 let mut dst_u = into_image_store_mut::<u16, 1>(&mut dst_planes.planes[1], dst_chroma_width, dst_chroma_height)?;
154 scaler.resize_plane_u16(&src_u, &mut dst_u).map_err(|e| Error::Invalid(e.to_string()))?;
155 let mut dst_v = into_image_store_mut::<u16, 1>(&mut dst_planes.planes[2], dst_chroma_width, dst_chroma_height)?;
156 scaler.resize_plane_u16(&src_v, &mut dst_v).map_err(|e| Error::Invalid(e.to_string()))?;
157 Ok(())
158 }
159 PixelFormat::P010 |
160 PixelFormat::P210 |
161 PixelFormat::P410 |
162 PixelFormat::P012 |
163 PixelFormat::P212 |
164 PixelFormat::P412 |
165 PixelFormat::P016 |
166 PixelFormat::P216 |
167 PixelFormat::P416 => {
168 let (src_chroma_width, src_chroma_height) = format.calc_chroma_dimensions(src_desc.width().get(), src_desc.height().get());
169 let (dst_chroma_width, dst_chroma_height) = format.calc_chroma_dimensions(dst_desc.width().get(), dst_desc.height().get());
170 let src_y = into_image_store::<u16, 1>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
171 let src_uv = into_image_store::<u16, 2>(&src_planes.planes[1], src_chroma_width, src_chroma_height)?;
172 let mut dst_y = into_image_store_mut::<u16, 1>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
173 scaler.resize_plane_u16(&src_y, &mut dst_y).map_err(|e| Error::Invalid(e.to_string()))?;
174 let mut dst_uv = into_image_store_mut::<u16, 2>(&mut dst_planes.planes[1], dst_chroma_width, dst_chroma_height)?;
175 scaler.resize_cbcr_u16(&src_uv, &mut dst_uv).map_err(|e| Error::Invalid(e.to_string()))?;
176 Ok(())
177 }
178 PixelFormat::Y8 => {
179 let src = into_image_store::<u8, 1>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
180 let mut dst = into_image_store_mut::<u8, 1>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
181 scaler.resize_plane(&src, &mut dst).map_err(|e| Error::Invalid(e.to_string()))
182 }
183 PixelFormat::YA8 => {
184 let src = into_image_store::<u8, 2>(&src_planes.planes[0], src_desc.width().get(), src_desc.height().get())?;
185 let mut dst = into_image_store_mut::<u8, 2>(&mut dst_planes.planes[0], dst_desc.width().get(), dst_desc.height().get())?;
186 scaler.resize_cbcr8(&src, &mut dst).map_err(|e| Error::Invalid(e.to_string()))
188 }
189 _ => Err(Error::Invalid("unsupported pixel format".to_string())),
190 }
191 }
192
193 pub fn scale_to(&self, dst: &mut VideoFrame<'_>, scale_filter: ScaleFilter) -> Result<()> {
194 Self::scale_to_internal(&self.desc, &self.data, &dst.desc, &mut dst.data, scale_filter)
195 }
196}