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 = 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}
430