ac_ffmpeg/codec/video/
scaler.rs1use std::os::raw::{c_int, c_void};
4
5use crate::{
6 codec::video::{PixelFormat, VideoFrame},
7 Error,
8};
9
10const ALG_ID_FAST_BILINEAR: usize = 0;
11const ALG_ID_BILINEAR: usize = 1;
12const ALG_ID_BICUBIC: usize = 2;
13
14extern "C" {
15 fn ffw_frame_scaler_new(
16 sformat: c_int,
17 swidth: c_int,
18 sheight: c_int,
19 tformat: c_int,
20 twidth: c_int,
21 theight: c_int,
22 flags: c_int,
23 ) -> *mut c_void;
24
25 fn ffw_frame_scaler_scale(scaler: *mut c_void, src: *const c_void) -> *mut c_void;
26
27 fn ffw_frame_scaler_free(scaler: *mut c_void);
28
29 fn ffw_alg_id_to_flags(id: usize) -> c_int;
30}
31
32#[derive(Debug, Copy, Clone, Eq, PartialEq)]
34pub enum Algorithm {
35 FastBilinear,
36 Bilinear,
37 Bicubic,
38}
39
40impl Algorithm {
41 fn id(self) -> usize {
43 match self {
44 Algorithm::FastBilinear => ALG_ID_FAST_BILINEAR,
45 Algorithm::Bilinear => ALG_ID_BILINEAR,
46 Algorithm::Bicubic => ALG_ID_BICUBIC,
47 }
48 }
49}
50
51pub struct VideoFrameScalerBuilder {
53 sformat: c_int,
54 swidth: c_int,
55 sheight: c_int,
56
57 tformat: Option<c_int>,
58 twidth: c_int,
59 theight: c_int,
60
61 flags: c_int,
62}
63
64impl VideoFrameScalerBuilder {
65 fn new() -> Self {
67 let default_algorithm = Algorithm::Bicubic;
68
69 let flags = unsafe { ffw_alg_id_to_flags(default_algorithm.id()) };
70
71 Self {
72 sformat: -1,
73 swidth: 0,
74 sheight: 0,
75
76 tformat: None,
77 twidth: 0,
78 theight: 0,
79
80 flags,
81 }
82 }
83
84 pub fn source_pixel_format(mut self, format: PixelFormat) -> Self {
86 self.sformat = format.into_raw();
87 self
88 }
89
90 pub fn source_width(mut self, width: usize) -> Self {
92 self.swidth = width as _;
93 self
94 }
95
96 pub fn source_height(mut self, height: usize) -> Self {
98 self.sheight = height as _;
99 self
100 }
101
102 pub fn target_pixel_format(mut self, format: PixelFormat) -> Self {
104 self.tformat = Some(format.into_raw());
105 self
106 }
107
108 pub fn target_width(mut self, width: usize) -> Self {
110 self.twidth = width as _;
111 self
112 }
113
114 pub fn target_height(mut self, height: usize) -> Self {
116 self.theight = height as _;
117 self
118 }
119
120 pub fn algorithm(mut self, algorithm: Algorithm) -> Self {
122 self.flags = unsafe { ffw_alg_id_to_flags(algorithm.id()) };
123
124 self
125 }
126
127 pub fn build(self) -> Result<VideoFrameScaler, Error> {
129 let tformat = self.tformat.unwrap_or(self.sformat);
130
131 if self.sformat < 0 {
132 return Err(Error::new("invalid source format"));
133 } else if tformat < 0 {
134 return Err(Error::new("invalid target format"));
135 } else if self.swidth < 1 {
136 return Err(Error::new("invalid source width"));
137 } else if self.sheight < 1 {
138 return Err(Error::new("invalid source height"));
139 } else if self.twidth < 1 {
140 return Err(Error::new("invalid target width"));
141 } else if self.theight < 1 {
142 return Err(Error::new("invalid target height"));
143 }
144
145 let ptr = unsafe {
146 ffw_frame_scaler_new(
147 self.sformat,
148 self.swidth,
149 self.sheight,
150 tformat,
151 self.twidth,
152 self.theight,
153 self.flags,
154 )
155 };
156
157 if ptr.is_null() {
158 return Err(Error::new("unable to create a frame scaler"));
159 }
160
161 let res = VideoFrameScaler {
162 ptr,
163
164 sformat: PixelFormat::from_raw(self.sformat),
165 swidth: self.swidth as _,
166 sheight: self.sheight as _,
167 };
168
169 Ok(res)
170 }
171}
172
173pub struct VideoFrameScaler {
175 ptr: *mut c_void,
176
177 sformat: PixelFormat,
178 swidth: usize,
179 sheight: usize,
180}
181
182impl VideoFrameScaler {
183 pub fn builder() -> VideoFrameScalerBuilder {
185 VideoFrameScalerBuilder::new()
186 }
187
188 pub fn scale(&mut self, frame: &VideoFrame) -> Result<VideoFrame, Error> {
190 if self.swidth != frame.width() {
191 return Err(Error::new("frame width does not match"));
192 } else if self.sheight != frame.height() {
193 return Err(Error::new("frame height does not match"));
194 } else if self.sformat != frame.pixel_format() {
195 return Err(Error::new("frame pixel format does not match"));
196 }
197
198 let res = unsafe { ffw_frame_scaler_scale(self.ptr, frame.as_ptr()) };
199
200 if res.is_null() {
201 panic!("unable to scale a frame");
202 }
203
204 let frame = unsafe { VideoFrame::from_raw_ptr(res, frame.time_base()) };
205
206 Ok(frame)
207 }
208}
209
210impl Drop for VideoFrameScaler {
211 fn drop(&mut self) {
212 unsafe { ffw_frame_scaler_free(self.ptr) }
213 }
214}
215
216unsafe impl Send for VideoFrameScaler {}
217unsafe impl Sync for VideoFrameScaler {}