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