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