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        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
320impl Deref for Video {
321    type Target = Frame;
322
323    #[inline]
324    fn deref(&self) -> &Frame {
325        &self.0
326    }
327}
328
329impl DerefMut for Video {
330    #[inline]
331    fn deref_mut(&mut self) -> &mut Frame {
332        &mut self.0
333    }
334}
335
336impl Clone for Video {
337    #[inline]
338    fn clone(&self) -> Self {
339        let mut cloned = 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
354impl From<Frame> for Video {
355    #[inline]
356    fn from(frame: Frame) -> Self {
357        Video(frame)
358    }
359}
360
361pub unsafe trait Component {
362    fn is_valid(format: format::Pixel) -> bool;
363}
364
365#[cfg(feature = "image")]
366unsafe 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")]
374unsafe 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")]
382unsafe 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
389unsafe 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
396unsafe 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
403unsafe 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
417unsafe 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}