1 | use std::mem; |
2 | use std::ops::{Deref, DerefMut}; |
3 | use std::slice; |
4 | |
5 | use super::Frame; |
6 | use color; |
7 | use ffi::*; |
8 | use libc::c_int; |
9 | use picture; |
10 | use util::chroma; |
11 | use util::format; |
12 | use Rational; |
13 | |
14 | #[derive (PartialEq, Eq)] |
15 | pub struct Video(Frame); |
16 | |
17 | impl Video { |
18 | #[inline (always)] |
19 | pub unsafe fn wrap(ptr: *mut AVFrame) -> Self { |
20 | Video(Frame::wrap(ptr)) |
21 | } |
22 | |
23 | #[inline ] |
24 | pub unsafe fn alloc(&mut self, format: format::Pixel, width: u32, height: u32) { |
25 | self.set_format(format); |
26 | self.set_width(width); |
27 | self.set_height(height); |
28 | |
29 | av_frame_get_buffer(self.as_mut_ptr(), 32); |
30 | } |
31 | } |
32 | |
33 | impl Video { |
34 | #[inline (always)] |
35 | pub fn empty() -> Self { |
36 | unsafe { Video(Frame::empty()) } |
37 | } |
38 | |
39 | #[inline ] |
40 | pub fn new(format: format::Pixel, width: u32, height: u32) -> Self { |
41 | unsafe { |
42 | let mut frame = Video::empty(); |
43 | frame.alloc(format, width, height); |
44 | |
45 | frame |
46 | } |
47 | } |
48 | |
49 | #[inline ] |
50 | pub fn format(&self) -> format::Pixel { |
51 | unsafe { |
52 | if (*self.as_ptr()).format == -1 { |
53 | format::Pixel::None |
54 | } else { |
55 | format::Pixel::from(mem::transmute::<i32, AVPixelFormat>( |
56 | (*self.as_ptr()).format, |
57 | )) |
58 | } |
59 | } |
60 | } |
61 | |
62 | #[inline ] |
63 | pub fn set_format(&mut self, value: format::Pixel) { |
64 | unsafe { |
65 | (*self.as_mut_ptr()).format = mem::transmute::<AVPixelFormat, c_int>(value.into()); |
66 | } |
67 | } |
68 | |
69 | #[inline ] |
70 | pub fn kind(&self) -> picture::Type { |
71 | unsafe { picture::Type::from((*self.as_ptr()).pict_type) } |
72 | } |
73 | |
74 | #[inline ] |
75 | pub fn set_kind(&mut self, value: picture::Type) { |
76 | unsafe { |
77 | (*self.as_mut_ptr()).pict_type = value.into(); |
78 | } |
79 | } |
80 | |
81 | #[inline ] |
82 | pub fn is_interlaced(&self) -> bool { |
83 | unsafe { (*self.as_ptr()).interlaced_frame != 0 } |
84 | } |
85 | |
86 | #[inline ] |
87 | pub fn is_top_first(&self) -> bool { |
88 | unsafe { (*self.as_ptr()).top_field_first != 0 } |
89 | } |
90 | |
91 | #[inline ] |
92 | pub fn has_palette_changed(&self) -> bool { |
93 | unsafe { (*self.as_ptr()).palette_has_changed != 0 } |
94 | } |
95 | |
96 | #[inline ] |
97 | pub fn width(&self) -> u32 { |
98 | unsafe { (*self.as_ptr()).width as u32 } |
99 | } |
100 | |
101 | #[inline ] |
102 | pub fn set_width(&mut self, value: u32) { |
103 | unsafe { |
104 | (*self.as_mut_ptr()).width = value as c_int; |
105 | } |
106 | } |
107 | |
108 | #[inline ] |
109 | pub fn height(&self) -> u32 { |
110 | unsafe { (*self.as_ptr()).height as u32 } |
111 | } |
112 | |
113 | #[inline ] |
114 | pub fn set_height(&mut self, value: u32) { |
115 | unsafe { |
116 | (*self.as_mut_ptr()).height = value as c_int; |
117 | } |
118 | } |
119 | |
120 | #[inline ] |
121 | pub fn color_space(&self) -> color::Space { |
122 | unsafe { color::Space::from((*self.as_ptr()).colorspace) } |
123 | } |
124 | |
125 | #[inline ] |
126 | pub fn set_color_space(&mut self, value: color::Space) { |
127 | unsafe { |
128 | (*self.as_mut_ptr()).colorspace = value.into(); |
129 | } |
130 | } |
131 | |
132 | #[inline ] |
133 | pub fn color_range(&self) -> color::Range { |
134 | unsafe { color::Range::from((*self.as_ptr()).color_range) } |
135 | } |
136 | |
137 | #[inline ] |
138 | pub fn set_color_range(&mut self, value: color::Range) { |
139 | unsafe { |
140 | (*self.as_mut_ptr()).color_range = value.into(); |
141 | } |
142 | } |
143 | |
144 | #[inline ] |
145 | pub fn color_primaries(&self) -> color::Primaries { |
146 | unsafe { color::Primaries::from((*self.as_ptr()).color_primaries) } |
147 | } |
148 | |
149 | #[inline ] |
150 | pub fn set_color_primaries(&mut self, value: color::Primaries) { |
151 | unsafe { |
152 | (*self.as_mut_ptr()).color_primaries = value.into(); |
153 | } |
154 | } |
155 | |
156 | #[inline ] |
157 | pub fn color_transfer_characteristic(&self) -> color::TransferCharacteristic { |
158 | unsafe { color::TransferCharacteristic::from((*self.as_ptr()).color_trc) } |
159 | } |
160 | |
161 | #[inline ] |
162 | pub fn set_color_transfer_characteristic(&mut self, value: color::TransferCharacteristic) { |
163 | unsafe { |
164 | (*self.as_mut_ptr()).color_trc = value.into(); |
165 | } |
166 | } |
167 | |
168 | #[inline ] |
169 | pub fn chroma_location(&self) -> chroma::Location { |
170 | unsafe { chroma::Location::from((*self.as_ptr()).chroma_location) } |
171 | } |
172 | |
173 | #[inline ] |
174 | pub fn aspect_ratio(&self) -> Rational { |
175 | unsafe { Rational::from((*self.as_ptr()).sample_aspect_ratio) } |
176 | } |
177 | |
178 | #[inline ] |
179 | #[cfg (not(feature = "ffmpeg_7_0" ))] |
180 | pub fn coded_number(&self) -> usize { |
181 | unsafe { (*self.as_ptr()).coded_picture_number as usize } |
182 | } |
183 | |
184 | #[inline ] |
185 | #[cfg (not(feature = "ffmpeg_7_0" ))] |
186 | pub fn display_number(&self) -> usize { |
187 | unsafe { (*self.as_ptr()).display_picture_number as usize } |
188 | } |
189 | |
190 | #[inline ] |
191 | pub fn repeat(&self) -> f64 { |
192 | unsafe { f64::from((*self.as_ptr()).repeat_pict) } |
193 | } |
194 | |
195 | #[inline ] |
196 | pub fn stride(&self, index: usize) -> usize { |
197 | if index >= self.planes() { |
198 | panic!("out of bounds" ); |
199 | } |
200 | |
201 | unsafe { (*self.as_ptr()).linesize[index] as usize } |
202 | } |
203 | |
204 | #[inline ] |
205 | pub fn planes(&self) -> usize { |
206 | for i in 0..8 { |
207 | unsafe { |
208 | if (*self.as_ptr()).linesize[i] == 0 { |
209 | return i; |
210 | } |
211 | } |
212 | } |
213 | |
214 | 8 |
215 | } |
216 | |
217 | #[inline ] |
218 | pub fn plane_width(&self, index: usize) -> u32 { |
219 | if index >= self.planes() { |
220 | panic!("out of bounds" ); |
221 | } |
222 | |
223 | // Logic taken from image_get_linesize(). |
224 | if index != 1 && index != 2 { |
225 | return self.width(); |
226 | } |
227 | |
228 | if let Some(desc) = self.format().descriptor() { |
229 | let s = desc.log2_chroma_w(); |
230 | (self.width() + (1 << s) - 1) >> s |
231 | } else { |
232 | self.width() |
233 | } |
234 | } |
235 | |
236 | #[inline ] |
237 | pub fn plane_height(&self, index: usize) -> u32 { |
238 | if index >= self.planes() { |
239 | panic!("out of bounds" ); |
240 | } |
241 | |
242 | // Logic taken from av_image_fill_pointers(). |
243 | if index != 1 && index != 2 { |
244 | return self.height(); |
245 | } |
246 | |
247 | if let Some(desc) = self.format().descriptor() { |
248 | let s = desc.log2_chroma_h(); |
249 | (self.height() + (1 << s) - 1) >> s |
250 | } else { |
251 | self.height() |
252 | } |
253 | } |
254 | |
255 | #[inline ] |
256 | pub fn plane<T: Component>(&self, index: usize) -> &[T] { |
257 | if index >= self.planes() { |
258 | panic!("out of bounds" ); |
259 | } |
260 | |
261 | if !<T as Component>::is_valid(self.format()) { |
262 | panic!("unsupported type" ); |
263 | } |
264 | |
265 | unsafe { |
266 | slice::from_raw_parts( |
267 | (*self.as_ptr()).data[index] as *const T, |
268 | self.stride(index) * self.plane_height(index) as usize / mem::size_of::<T>(), |
269 | ) |
270 | } |
271 | } |
272 | |
273 | #[inline ] |
274 | pub fn plane_mut<T: Component>(&mut self, index: usize) -> &mut [T] { |
275 | if index >= self.planes() { |
276 | panic!("out of bounds" ); |
277 | } |
278 | |
279 | if !<T as Component>::is_valid(self.format()) { |
280 | panic!("unsupported type" ); |
281 | } |
282 | |
283 | unsafe { |
284 | slice::from_raw_parts_mut( |
285 | (*self.as_mut_ptr()).data[index] as *mut T, |
286 | self.stride(index) * self.plane_height(index) as usize / mem::size_of::<T>(), |
287 | ) |
288 | } |
289 | } |
290 | |
291 | #[inline ] |
292 | pub fn data(&self, index: usize) -> &[u8] { |
293 | if index >= self.planes() { |
294 | panic!("out of bounds" ); |
295 | } |
296 | |
297 | unsafe { |
298 | slice::from_raw_parts( |
299 | (*self.as_ptr()).data[index], |
300 | self.stride(index) * self.plane_height(index) as usize, |
301 | ) |
302 | } |
303 | } |
304 | |
305 | #[inline ] |
306 | pub fn data_mut(&mut self, index: usize) -> &mut [u8] { |
307 | if index >= self.planes() { |
308 | panic!("out of bounds" ); |
309 | } |
310 | |
311 | unsafe { |
312 | slice::from_raw_parts_mut( |
313 | (*self.as_mut_ptr()).data[index], |
314 | self.stride(index) * self.plane_height(index) as usize, |
315 | ) |
316 | } |
317 | } |
318 | } |
319 | |
320 | impl Deref for Video { |
321 | type Target = Frame; |
322 | |
323 | #[inline ] |
324 | fn deref(&self) -> &Frame { |
325 | &self.0 |
326 | } |
327 | } |
328 | |
329 | impl DerefMut for Video { |
330 | #[inline ] |
331 | fn deref_mut(&mut self) -> &mut Frame { |
332 | &mut self.0 |
333 | } |
334 | } |
335 | |
336 | impl Clone for Video { |
337 | #[inline ] |
338 | fn clone(&self) -> Self { |
339 | let mut cloned: Video = Video::new(self.format(), self.width(), self.height()); |
340 | cloned.clone_from(self); |
341 | |
342 | cloned |
343 | } |
344 | |
345 | #[inline ] |
346 | fn clone_from(&mut self, source: &Self) { |
347 | unsafe { |
348 | av_frame_copy(self.as_mut_ptr(), source.as_ptr()); |
349 | av_frame_copy_props(self.as_mut_ptr(), source.as_ptr()); |
350 | } |
351 | } |
352 | } |
353 | |
354 | impl From<Frame> for Video { |
355 | #[inline ] |
356 | fn from(frame: Frame) -> Self { |
357 | Video(frame) |
358 | } |
359 | } |
360 | |
361 | pub unsafe trait Component { |
362 | fn is_valid(format: format::Pixel) -> bool; |
363 | } |
364 | |
365 | #[cfg (feature = "image" )] |
366 | unsafe impl Component for ::image::Luma<u8> { |
367 | #[inline (always)] |
368 | fn is_valid(format: format::Pixel) -> bool { |
369 | format == format::Pixel::GRAY8 |
370 | } |
371 | } |
372 | |
373 | #[cfg (feature = "image" )] |
374 | unsafe impl Component for ::image::Rgb<u8> { |
375 | #[inline (always)] |
376 | fn is_valid(format: format::Pixel) -> bool { |
377 | format == format::Pixel::RGB24 |
378 | } |
379 | } |
380 | |
381 | #[cfg (feature = "image" )] |
382 | unsafe impl Component for ::image::Rgba<u8> { |
383 | #[inline (always)] |
384 | fn is_valid(format: format::Pixel) -> bool { |
385 | format == format::Pixel::RGBA |
386 | } |
387 | } |
388 | |
389 | unsafe impl Component for [u8; 3] { |
390 | #[inline (always)] |
391 | fn is_valid(format: format::Pixel) -> bool { |
392 | format == format::Pixel::RGB24 || format == format::Pixel::BGR24 |
393 | } |
394 | } |
395 | |
396 | unsafe impl Component for (u8, u8, u8) { |
397 | #[inline (always)] |
398 | fn is_valid(format: format::Pixel) -> bool { |
399 | format == format::Pixel::RGB24 || format == format::Pixel::BGR24 |
400 | } |
401 | } |
402 | |
403 | unsafe impl Component for [u8; 4] { |
404 | #[inline (always)] |
405 | fn is_valid(format: format::Pixel) -> bool { |
406 | format == format::Pixel::RGBA |
407 | || format == format::Pixel::BGRA |
408 | || format == format::Pixel::ARGB |
409 | || format == format::Pixel::ABGR |
410 | || format == format::Pixel::RGBZ |
411 | || format == format::Pixel::BGRZ |
412 | || format == format::Pixel::ZRGB |
413 | || format == format::Pixel::ZBGR |
414 | } |
415 | } |
416 | |
417 | unsafe impl Component for (u8, u8, u8, u8) { |
418 | #[inline (always)] |
419 | fn is_valid(format: format::Pixel) -> bool { |
420 | format == format::Pixel::RGBA |
421 | || format == format::Pixel::BGRA |
422 | || format == format::Pixel::ARGB |
423 | || format == format::Pixel::ABGR |
424 | || format == format::Pixel::RGBZ |
425 | || format == format::Pixel::BGRZ |
426 | || format == format::Pixel::ZRGB |
427 | || format == format::Pixel::ZBGR |
428 | } |
429 | } |
430 | |