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