ffmpeg_the_third/util/frame/
video.rs

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