ffmpeg_next/util/frame/
video.rs1use 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 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 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}