playa_ffmpeg/util/frame/
video.rs

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