| 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::<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 | |
| 320 | impl Deref for Video { |
| 321 | type Target = Frame; |
| 322 | |
| 323 | #[inline ] |
| 324 | fn deref(&self) -> &Frame { |
| 325 | &self.0 |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | impl DerefMut for Video { |
| 330 | #[inline ] |
| 331 | fn deref_mut(&mut self) -> &mut Frame { |
| 332 | &mut self.0 |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | impl 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 | |
| 354 | impl From<Frame> for Video { |
| 355 | #[inline ] |
| 356 | fn from(frame: Frame) -> Self { |
| 357 | Video(frame) |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | pub unsafe trait Component { |
| 362 | fn is_valid(format: format::Pixel) -> bool; |
| 363 | } |
| 364 | |
| 365 | #[cfg (feature = "image" )] |
| 366 | unsafe 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" )] |
| 374 | unsafe 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" )] |
| 382 | unsafe 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 | |
| 389 | unsafe 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 | |
| 396 | unsafe 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 | |
| 403 | unsafe 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 | |
| 417 | unsafe 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 | |