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