1 // Take a look at the license at the top of the repository in the LICENSE file. 2 3 use crate::utils::HasStreamLock; 4 use crate::video_codec_state::{InNegotiation, Readable, VideoCodecState, VideoCodecStateContext}; 5 use crate::VideoCodecFrame; 6 use crate::VideoDecoder; 7 use crate::VideoFormat; 8 #[cfg(any(feature = "v1_16", feature = "dox"))] 9 #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))] 10 use crate::VideoInterlaceMode; 11 use glib::prelude::*; 12 use glib::translate::*; 13 use std::mem; 14 use std::ptr; 15 16 extern "C" { _gst_video_decoder_error( dec: *mut ffi::GstVideoDecoder, weight: i32, domain: glib::ffi::GQuark, code: i32, txt: *mut libc::c_char, debug: *mut libc::c_char, file: *const libc::c_char, function: *const libc::c_char, line: i32, ) -> gst::ffi::GstFlowReturn17 fn _gst_video_decoder_error( 18 dec: *mut ffi::GstVideoDecoder, 19 weight: i32, 20 domain: glib::ffi::GQuark, 21 code: i32, 22 txt: *mut libc::c_char, 23 debug: *mut libc::c_char, 24 file: *const libc::c_char, 25 function: *const libc::c_char, 26 line: i32, 27 ) -> gst::ffi::GstFlowReturn; 28 } 29 30 pub trait VideoDecoderExtManual: 'static { 31 #[cfg(any(feature = "v1_12", feature = "dox"))] 32 #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_12")))] allocate_output_frame( &self, frame: &mut VideoCodecFrame, params: Option<&gst::BufferPoolAcquireParams>, ) -> Result<gst::FlowSuccess, gst::FlowError>33 fn allocate_output_frame( 34 &self, 35 frame: &mut VideoCodecFrame, 36 params: Option<&gst::BufferPoolAcquireParams>, 37 ) -> Result<gst::FlowSuccess, gst::FlowError>; 38 39 #[doc(alias = "get_frame")] frame(&self, frame_number: i32) -> Option<VideoCodecFrame>40 fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame>; 41 #[doc(alias = "get_frames")] frames(&self) -> Vec<VideoCodecFrame>42 fn frames(&self) -> Vec<VideoCodecFrame>; 43 #[doc(alias = "get_oldest_frame")] oldest_frame(&self) -> Option<VideoCodecFrame>44 fn oldest_frame(&self) -> Option<VideoCodecFrame>; 45 46 #[doc(alias = "get_allocator")] allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams)47 fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams); 48 finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>49 fn finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>; release_frame(&self, frame: VideoCodecFrame)50 fn release_frame(&self, frame: VideoCodecFrame); drop_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>51 fn drop_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>; 52 53 #[doc(alias = "get_latency")] latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>)54 fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>); set_latency( &self, min_latency: gst::ClockTime, max_latency: impl Into<Option<gst::ClockTime>>, )55 fn set_latency( 56 &self, 57 min_latency: gst::ClockTime, 58 max_latency: impl Into<Option<gst::ClockTime>>, 59 ); 60 61 #[doc(alias = "get_output_state")] output_state(&self) -> Option<VideoCodecState<'static, Readable>>62 fn output_state(&self) -> Option<VideoCodecState<'static, Readable>>; set_output_state( &self, fmt: VideoFormat, width: u32, height: u32, reference: Option<&VideoCodecState<Readable>>, ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>63 fn set_output_state( 64 &self, 65 fmt: VideoFormat, 66 width: u32, 67 height: u32, 68 reference: Option<&VideoCodecState<Readable>>, 69 ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>; 70 #[cfg(any(feature = "v1_16", feature = "dox"))] 71 #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))] set_interlaced_output_state( &self, fmt: VideoFormat, mode: VideoInterlaceMode, width: u32, height: u32, reference: Option<&VideoCodecState<Readable>>, ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>72 fn set_interlaced_output_state( 73 &self, 74 fmt: VideoFormat, 75 mode: VideoInterlaceMode, 76 width: u32, 77 height: u32, 78 reference: Option<&VideoCodecState<Readable>>, 79 ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>; 80 negotiate<'a>( &'a self, output_state: VideoCodecState<'a, InNegotiation<'a>>, ) -> Result<(), gst::FlowError>81 fn negotiate<'a>( 82 &'a self, 83 output_state: VideoCodecState<'a, InNegotiation<'a>>, 84 ) -> Result<(), gst::FlowError>; 85 86 #[allow(clippy::too_many_arguments)] error<T: gst::MessageErrorDomain>( &self, weight: i32, code: T, message: Option<&str>, debug: Option<&str>, file: &str, function: &str, line: u32, ) -> Result<gst::FlowSuccess, gst::FlowError>87 fn error<T: gst::MessageErrorDomain>( 88 &self, 89 weight: i32, 90 code: T, 91 message: Option<&str>, 92 debug: Option<&str>, 93 file: &str, 94 function: &str, 95 line: u32, 96 ) -> Result<gst::FlowSuccess, gst::FlowError>; 97 } 98 99 impl<O: IsA<VideoDecoder>> VideoDecoderExtManual for O { 100 #[cfg(any(feature = "v1_12", feature = "dox"))] 101 #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_12")))] allocate_output_frame( &self, frame: &mut VideoCodecFrame, params: Option<&gst::BufferPoolAcquireParams>, ) -> Result<gst::FlowSuccess, gst::FlowError>102 fn allocate_output_frame( 103 &self, 104 frame: &mut VideoCodecFrame, 105 params: Option<&gst::BufferPoolAcquireParams>, 106 ) -> Result<gst::FlowSuccess, gst::FlowError> { 107 unsafe { 108 let params_ptr = params.to_glib_none().0 as *mut _; 109 try_from_glib(ffi::gst_video_decoder_allocate_output_frame_with_params( 110 self.as_ref().to_glib_none().0, 111 frame.to_glib_none().0, 112 params_ptr, 113 )) 114 } 115 } 116 117 #[doc(alias = "gst_video_decoder_get_allocator")] allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams)118 fn allocator(&self) -> (Option<gst::Allocator>, gst::AllocationParams) { 119 unsafe { 120 let mut allocator = ptr::null_mut(); 121 let mut params = mem::zeroed(); 122 ffi::gst_video_decoder_get_allocator( 123 self.as_ref().to_glib_none().0, 124 &mut allocator, 125 &mut params, 126 ); 127 (from_glib_full(allocator), params.into()) 128 } 129 } 130 131 #[doc(alias = "gst_video_decoder_finish_frame")] finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>132 fn finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError> { 133 unsafe { 134 try_from_glib(ffi::gst_video_decoder_finish_frame( 135 self.as_ref().to_glib_none().0, 136 frame.into_ptr(), 137 )) 138 } 139 } 140 141 #[doc(alias = "gst_video_decoder_release_frame")] release_frame(&self, frame: VideoCodecFrame)142 fn release_frame(&self, frame: VideoCodecFrame) { 143 unsafe { 144 ffi::gst_video_decoder_release_frame(self.as_ref().to_glib_none().0, frame.into_ptr()) 145 } 146 } 147 148 #[doc(alias = "gst_video_decoder_drop_frame")] drop_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>149 fn drop_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError> { 150 unsafe { 151 try_from_glib(ffi::gst_video_decoder_drop_frame( 152 self.as_ref().to_glib_none().0, 153 frame.into_ptr(), 154 )) 155 } 156 } 157 158 #[doc(alias = "gst_video_decoder_get_latency")] latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>)159 fn latency(&self) -> (gst::ClockTime, Option<gst::ClockTime>) { 160 let mut min_latency = gst::ffi::GST_CLOCK_TIME_NONE; 161 let mut max_latency = gst::ffi::GST_CLOCK_TIME_NONE; 162 163 unsafe { 164 ffi::gst_video_decoder_get_latency( 165 self.as_ref().to_glib_none().0, 166 &mut min_latency, 167 &mut max_latency, 168 ); 169 170 ( 171 try_from_glib(min_latency).expect("undefined min_latency"), 172 from_glib(max_latency), 173 ) 174 } 175 } 176 177 #[doc(alias = "gst_video_decoder_set_latency")] set_latency( &self, min_latency: gst::ClockTime, max_latency: impl Into<Option<gst::ClockTime>>, )178 fn set_latency( 179 &self, 180 min_latency: gst::ClockTime, 181 max_latency: impl Into<Option<gst::ClockTime>>, 182 ) { 183 unsafe { 184 ffi::gst_video_decoder_set_latency( 185 self.as_ref().to_glib_none().0, 186 min_latency.into_glib(), 187 max_latency.into().into_glib(), 188 ); 189 } 190 } 191 192 #[doc(alias = "gst_video_decoder_get_frame")] frame(&self, frame_number: i32) -> Option<VideoCodecFrame>193 fn frame(&self, frame_number: i32) -> Option<VideoCodecFrame> { 194 let frame = unsafe { 195 ffi::gst_video_decoder_get_frame(self.as_ref().to_glib_none().0, frame_number) 196 }; 197 198 if frame.is_null() { 199 None 200 } else { 201 unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) } 202 } 203 } 204 205 #[doc(alias = "gst_video_decoder_get_frames")] frames(&self) -> Vec<VideoCodecFrame>206 fn frames(&self) -> Vec<VideoCodecFrame> { 207 unsafe { 208 let frames = ffi::gst_video_decoder_get_frames(self.as_ref().to_glib_none().0); 209 let mut iter: *const glib::ffi::GList = frames; 210 let mut vec = Vec::new(); 211 212 while !iter.is_null() { 213 let frame_ptr = Ptr::from((*iter).data); 214 /* transfer ownership of the frame */ 215 let frame = VideoCodecFrame::new(frame_ptr, self.as_ref()); 216 vec.push(frame); 217 iter = (*iter).next; 218 } 219 220 glib::ffi::g_list_free(frames); 221 vec 222 } 223 } 224 225 #[doc(alias = "gst_video_decoder_get_oldest_frame")] oldest_frame(&self) -> Option<VideoCodecFrame>226 fn oldest_frame(&self) -> Option<VideoCodecFrame> { 227 let frame = 228 unsafe { ffi::gst_video_decoder_get_oldest_frame(self.as_ref().to_glib_none().0) }; 229 230 if frame.is_null() { 231 None 232 } else { 233 unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) } 234 } 235 } 236 237 #[doc(alias = "gst_video_decoder_get_output_state")] output_state(&self) -> Option<VideoCodecState<'static, Readable>>238 fn output_state(&self) -> Option<VideoCodecState<'static, Readable>> { 239 let state = 240 unsafe { ffi::gst_video_decoder_get_output_state(self.as_ref().to_glib_none().0) }; 241 242 if state.is_null() { 243 None 244 } else { 245 unsafe { Some(VideoCodecState::<Readable>::new(state)) } 246 } 247 } 248 249 #[doc(alias = "gst_video_decoder_set_output_state")] set_output_state( &self, fmt: VideoFormat, width: u32, height: u32, reference: Option<&VideoCodecState<Readable>>, ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>250 fn set_output_state( 251 &self, 252 fmt: VideoFormat, 253 width: u32, 254 height: u32, 255 reference: Option<&VideoCodecState<Readable>>, 256 ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> { 257 let state = unsafe { 258 let reference = match reference { 259 Some(reference) => reference.as_mut_ptr(), 260 None => ptr::null_mut(), 261 }; 262 ffi::gst_video_decoder_set_output_state( 263 self.as_ref().to_glib_none().0, 264 fmt.into_glib(), 265 width, 266 height, 267 reference, 268 ) 269 }; 270 271 if state.is_null() { 272 Err(gst::FlowError::NotNegotiated) 273 } else { 274 unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) } 275 } 276 } 277 278 #[cfg(any(feature = "v1_16", feature = "dox"))] 279 #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))] 280 #[doc(alias = "gst_video_decoder_set_interlaced_output_state")] set_interlaced_output_state( &self, fmt: VideoFormat, mode: VideoInterlaceMode, width: u32, height: u32, reference: Option<&VideoCodecState<Readable>>, ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>281 fn set_interlaced_output_state( 282 &self, 283 fmt: VideoFormat, 284 mode: VideoInterlaceMode, 285 width: u32, 286 height: u32, 287 reference: Option<&VideoCodecState<Readable>>, 288 ) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> { 289 let state = unsafe { 290 let reference = match reference { 291 Some(reference) => reference.as_mut_ptr(), 292 None => ptr::null_mut(), 293 }; 294 ffi::gst_video_decoder_set_interlaced_output_state( 295 self.as_ref().to_glib_none().0, 296 fmt.into_glib(), 297 mode.into_glib(), 298 width, 299 height, 300 reference, 301 ) 302 }; 303 304 if state.is_null() { 305 Err(gst::FlowError::NotNegotiated) 306 } else { 307 unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) } 308 } 309 } 310 311 #[doc(alias = "gst_video_decoder_negotiate")] negotiate<'a>( &'a self, output_state: VideoCodecState<'a, InNegotiation<'a>>, ) -> Result<(), gst::FlowError>312 fn negotiate<'a>( 313 &'a self, 314 output_state: VideoCodecState<'a, InNegotiation<'a>>, 315 ) -> Result<(), gst::FlowError> { 316 // Consume output_state so user won't be able to modify it anymore 317 let self_ptr = self.to_glib_none().0 as *const gst::ffi::GstElement; 318 assert_eq!(output_state.context.element_as_ptr(), self_ptr); 319 320 let ret = unsafe { 321 from_glib(ffi::gst_video_decoder_negotiate( 322 self.as_ref().to_glib_none().0, 323 )) 324 }; 325 if ret { 326 Ok(()) 327 } else { 328 Err(gst::FlowError::NotNegotiated) 329 } 330 } error<T: gst::MessageErrorDomain>( &self, weight: i32, code: T, message: Option<&str>, debug: Option<&str>, file: &str, function: &str, line: u32, ) -> Result<gst::FlowSuccess, gst::FlowError>331 fn error<T: gst::MessageErrorDomain>( 332 &self, 333 weight: i32, 334 code: T, 335 message: Option<&str>, 336 debug: Option<&str>, 337 file: &str, 338 function: &str, 339 line: u32, 340 ) -> Result<gst::FlowSuccess, gst::FlowError> { 341 unsafe { 342 try_from_glib(_gst_video_decoder_error( 343 self.as_ref().to_glib_none().0, 344 weight, 345 T::domain().into_glib(), 346 code.code(), 347 message.to_glib_full(), 348 debug.to_glib_full(), 349 file.to_glib_none().0, 350 function.to_glib_none().0, 351 line as i32, 352 )) 353 } 354 } 355 } 356 357 impl HasStreamLock for VideoDecoder { stream_lock(&self) -> *mut glib::ffi::GRecMutex358 fn stream_lock(&self) -> *mut glib::ffi::GRecMutex { 359 let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0; 360 unsafe { &(*decoder_sys).stream_lock as *const _ as usize as *mut _ } 361 } 362 element_as_ptr(&self) -> *const gst::ffi::GstElement363 fn element_as_ptr(&self) -> *const gst::ffi::GstElement { 364 let decoder_sys: *const ffi::GstVideoDecoder = self.to_glib_none().0; 365 decoder_sys as *const gst::ffi::GstElement 366 } 367 } 368 369 #[macro_export] 370 macro_rules! video_decoder_error( 371 ($obj:expr, $weight:expr, $err:expr, ($msg:expr), [$debug:expr]) => { { 372 use $crate::prelude::VideoDecoderExtManual; 373 $obj.error( 374 $weight, 375 $err, 376 Some($msg), 377 Some($debug), 378 file!(), 379 module_path!(), 380 line!(), 381 ) 382 }}; 383 ($obj:expr, $weight:expr, $err:expr, ($msg:expr)) => { { 384 use $crate::prelude::VideoDecoderExtManual; 385 $obj.error( 386 $weight, 387 $err, 388 Some($msg), 389 None, 390 file!(), 391 module_path!(), 392 line!(), 393 ) 394 }}; 395 ($obj:expr, $weight:expr, $err:expr, [$debug:expr]) => { { 396 use $crate::prelude::VideoDecoderExtManual; 397 $obj.error( 398 $weight, 399 $err, 400 None, 401 Some($debug), 402 file!(), 403 module_path!(), 404 line!(), 405 ) 406 }}; 407 ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*), [$($debug:tt)*]) => { { 408 use $crate::prelude::VideoDecoderExtManual; 409 $obj.error( 410 $weight, 411 $err, 412 Some(&format!($($msg)*)), 413 Some(&format!($($debug)*)), 414 file!(), 415 module_path!(), 416 line!(), 417 ) 418 }}; 419 ($obj:expr, $weight:expr, $err:expr, ($($msg:tt)*)) => { { 420 use $crate::prelude::VideoDecoderExtManual; 421 $obj.error( 422 $weight, 423 $err, 424 Some(&format!($($msg)*)), 425 None, 426 file!(), 427 module_path!(), 428 line!(), 429 ) 430 }}; 431 ($obj:expr, $weight:expr, $err:expr, [$($debug:tt)*]) => { { 432 use $crate::prelude::VideoDecoderExtManual; 433 $obj.error( 434 $weight, 435 $err, 436 None, 437 Some(&format!($($debug)*)), 438 file!(), 439 module_path!(), 440 line!(), 441 ) 442 }}; 443 ); 444