Skip to main content

ffmpeg_next/util/frame/
video.rs

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