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