| 1 | // Take a look at the license at the top of the repository in the LICENSE file. |
| 2 | |
| 3 | use std::{mem, ptr}; |
| 4 | |
| 5 | use atomic_refcell::AtomicRefCell; |
| 6 | use glib::{prelude::*, translate::*}; |
| 7 | use gst::{prelude::*, subclass::prelude::*}; |
| 8 | |
| 9 | use crate::{ffi, prelude::*, BaseSrc}; |
| 10 | |
| 11 | #[derive (Default)] |
| 12 | pub(super) struct InstanceData { |
| 13 | pub(super) pending_buffer_list: AtomicRefCell<Option<gst::BufferList>>, |
| 14 | } |
| 15 | |
| 16 | #[derive (Debug)] |
| 17 | pub enum CreateSuccess { |
| 18 | FilledBuffer, |
| 19 | NewBuffer(gst::Buffer), |
| 20 | NewBufferList(gst::BufferList), |
| 21 | } |
| 22 | |
| 23 | pub trait BaseSrcImpl: BaseSrcImplExt + ElementImpl { |
| 24 | fn start(&self) -> Result<(), gst::ErrorMessage> { |
| 25 | self.parent_start() |
| 26 | } |
| 27 | |
| 28 | fn stop(&self) -> Result<(), gst::ErrorMessage> { |
| 29 | self.parent_stop() |
| 30 | } |
| 31 | |
| 32 | fn is_seekable(&self) -> bool { |
| 33 | self.parent_is_seekable() |
| 34 | } |
| 35 | |
| 36 | fn size(&self) -> Option<u64> { |
| 37 | self.parent_size() |
| 38 | } |
| 39 | |
| 40 | #[doc (alias = "get_times" )] |
| 41 | fn times(&self, buffer: &gst::BufferRef) -> (Option<gst::ClockTime>, Option<gst::ClockTime>) { |
| 42 | self.parent_times(buffer) |
| 43 | } |
| 44 | |
| 45 | fn fill( |
| 46 | &self, |
| 47 | offset: u64, |
| 48 | length: u32, |
| 49 | buffer: &mut gst::BufferRef, |
| 50 | ) -> Result<gst::FlowSuccess, gst::FlowError> { |
| 51 | self.parent_fill(offset, length, buffer) |
| 52 | } |
| 53 | |
| 54 | fn alloc(&self, offset: u64, length: u32) -> Result<gst::Buffer, gst::FlowError> { |
| 55 | self.parent_alloc(offset, length) |
| 56 | } |
| 57 | |
| 58 | fn create( |
| 59 | &self, |
| 60 | offset: u64, |
| 61 | buffer: Option<&mut gst::BufferRef>, |
| 62 | length: u32, |
| 63 | ) -> Result<CreateSuccess, gst::FlowError> { |
| 64 | self.parent_create(offset, buffer, length) |
| 65 | } |
| 66 | |
| 67 | fn do_seek(&self, segment: &mut gst::Segment) -> bool { |
| 68 | self.parent_do_seek(segment) |
| 69 | } |
| 70 | |
| 71 | fn query(&self, query: &mut gst::QueryRef) -> bool { |
| 72 | BaseSrcImplExt::parent_query(self, query) |
| 73 | } |
| 74 | |
| 75 | fn event(&self, event: &gst::Event) -> bool { |
| 76 | self.parent_event(event) |
| 77 | } |
| 78 | |
| 79 | fn caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> { |
| 80 | self.parent_caps(filter) |
| 81 | } |
| 82 | |
| 83 | fn negotiate(&self) -> Result<(), gst::LoggableError> { |
| 84 | self.parent_negotiate() |
| 85 | } |
| 86 | |
| 87 | fn set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> { |
| 88 | self.parent_set_caps(caps) |
| 89 | } |
| 90 | |
| 91 | fn fixate(&self, caps: gst::Caps) -> gst::Caps { |
| 92 | self.parent_fixate(caps) |
| 93 | } |
| 94 | |
| 95 | fn unlock(&self) -> Result<(), gst::ErrorMessage> { |
| 96 | self.parent_unlock() |
| 97 | } |
| 98 | |
| 99 | fn unlock_stop(&self) -> Result<(), gst::ErrorMessage> { |
| 100 | self.parent_unlock_stop() |
| 101 | } |
| 102 | |
| 103 | fn decide_allocation( |
| 104 | &self, |
| 105 | query: &mut gst::query::Allocation, |
| 106 | ) -> Result<(), gst::LoggableError> { |
| 107 | self.parent_decide_allocation(query) |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | mod sealed { |
| 112 | pub trait Sealed {} |
| 113 | impl<T: super::BaseSrcImplExt> Sealed for T {} |
| 114 | } |
| 115 | |
| 116 | pub trait BaseSrcImplExt: sealed::Sealed + ObjectSubclass { |
| 117 | fn parent_start(&self) -> Result<(), gst::ErrorMessage> { |
| 118 | unsafe { |
| 119 | let data = Self::type_data(); |
| 120 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 121 | (*parent_class) |
| 122 | .start |
| 123 | .map(|f| { |
| 124 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) { |
| 125 | Ok(()) |
| 126 | } else { |
| 127 | Err(gst::error_msg!( |
| 128 | gst::CoreError::StateChange, |
| 129 | ["Parent function `start` failed" ] |
| 130 | )) |
| 131 | } |
| 132 | }) |
| 133 | .unwrap_or(Ok(())) |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | fn parent_stop(&self) -> Result<(), gst::ErrorMessage> { |
| 138 | unsafe { |
| 139 | let data = Self::type_data(); |
| 140 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 141 | (*parent_class) |
| 142 | .stop |
| 143 | .map(|f| { |
| 144 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) { |
| 145 | Ok(()) |
| 146 | } else { |
| 147 | Err(gst::error_msg!( |
| 148 | gst::CoreError::StateChange, |
| 149 | ["Parent function `stop` failed" ] |
| 150 | )) |
| 151 | } |
| 152 | }) |
| 153 | .unwrap_or(Ok(())) |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | fn parent_is_seekable(&self) -> bool { |
| 158 | unsafe { |
| 159 | let data = Self::type_data(); |
| 160 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 161 | (*parent_class) |
| 162 | .is_seekable |
| 163 | .map(|f| from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0))) |
| 164 | .unwrap_or(false) |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | fn parent_size(&self) -> Option<u64> { |
| 169 | unsafe { |
| 170 | let data = Self::type_data(); |
| 171 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 172 | (*parent_class) |
| 173 | .get_size |
| 174 | .map(|f| { |
| 175 | let mut size = mem::MaybeUninit::uninit(); |
| 176 | if from_glib(f( |
| 177 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 178 | size.as_mut_ptr(), |
| 179 | )) { |
| 180 | Some(size.assume_init()) |
| 181 | } else { |
| 182 | None |
| 183 | } |
| 184 | }) |
| 185 | .unwrap_or(None) |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | fn parent_times( |
| 190 | &self, |
| 191 | buffer: &gst::BufferRef, |
| 192 | ) -> (Option<gst::ClockTime>, Option<gst::ClockTime>) { |
| 193 | unsafe { |
| 194 | let data = Self::type_data(); |
| 195 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 196 | (*parent_class) |
| 197 | .get_times |
| 198 | .map(|f| { |
| 199 | let mut start = mem::MaybeUninit::uninit(); |
| 200 | let mut stop = mem::MaybeUninit::uninit(); |
| 201 | f( |
| 202 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 203 | buffer.as_mut_ptr(), |
| 204 | start.as_mut_ptr(), |
| 205 | stop.as_mut_ptr(), |
| 206 | ); |
| 207 | ( |
| 208 | from_glib(start.assume_init()), |
| 209 | from_glib(stop.assume_init()), |
| 210 | ) |
| 211 | }) |
| 212 | .unwrap_or((gst::ClockTime::NONE, gst::ClockTime::NONE)) |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | fn parent_fill( |
| 217 | &self, |
| 218 | offset: u64, |
| 219 | length: u32, |
| 220 | buffer: &mut gst::BufferRef, |
| 221 | ) -> Result<gst::FlowSuccess, gst::FlowError> { |
| 222 | unsafe { |
| 223 | let data = Self::type_data(); |
| 224 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 225 | (*parent_class) |
| 226 | .fill |
| 227 | .map(|f| { |
| 228 | try_from_glib(f( |
| 229 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 230 | offset, |
| 231 | length, |
| 232 | buffer.as_mut_ptr(), |
| 233 | )) |
| 234 | }) |
| 235 | .unwrap_or(Err(gst::FlowError::NotSupported)) |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | fn parent_alloc(&self, offset: u64, length: u32) -> Result<gst::Buffer, gst::FlowError> { |
| 240 | unsafe { |
| 241 | let data = Self::type_data(); |
| 242 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 243 | (*parent_class) |
| 244 | .alloc |
| 245 | .map(|f| { |
| 246 | let mut buffer_ptr: *mut gst::ffi::GstBuffer = ptr::null_mut(); |
| 247 | |
| 248 | // FIXME: Wrong signature in -sys bindings |
| 249 | // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 |
| 250 | let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer; |
| 251 | |
| 252 | gst::FlowSuccess::try_from_glib(f( |
| 253 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 254 | offset, |
| 255 | length, |
| 256 | buffer_ref, |
| 257 | )) |
| 258 | .map(|_| from_glib_full(buffer_ptr)) |
| 259 | }) |
| 260 | .unwrap_or(Err(gst::FlowError::NotSupported)) |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | fn parent_create( |
| 265 | &self, |
| 266 | offset: u64, |
| 267 | mut buffer: Option<&mut gst::BufferRef>, |
| 268 | length: u32, |
| 269 | ) -> Result<CreateSuccess, gst::FlowError> { |
| 270 | unsafe { |
| 271 | let data = Self::type_data(); |
| 272 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 273 | (*parent_class) |
| 274 | .create |
| 275 | .map(|f| { |
| 276 | let instance = self.obj(); |
| 277 | let instance = instance.unsafe_cast_ref::<BaseSrc>(); |
| 278 | let orig_buffer_ptr = buffer |
| 279 | .as_mut() |
| 280 | .map(|b| b.as_mut_ptr()) |
| 281 | .unwrap_or(ptr::null_mut()); |
| 282 | let mut buffer_ptr = orig_buffer_ptr; |
| 283 | |
| 284 | // FIXME: Wrong signature in -sys bindings |
| 285 | // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 |
| 286 | let buffer_ref = &mut buffer_ptr as *mut _ as *mut gst::ffi::GstBuffer; |
| 287 | |
| 288 | let instance_data = self.instance_data::<InstanceData>(BaseSrc::static_type()).unwrap(); |
| 289 | |
| 290 | if let Err(err) = gst::FlowSuccess::try_from_glib( |
| 291 | f( |
| 292 | instance.to_glib_none().0, |
| 293 | offset, |
| 294 | length, |
| 295 | buffer_ref, |
| 296 | ) |
| 297 | ) { |
| 298 | *instance_data.pending_buffer_list.borrow_mut() = None; |
| 299 | return Err(err); |
| 300 | } |
| 301 | |
| 302 | let pending_buffer_list = instance_data.pending_buffer_list.borrow_mut().take(); |
| 303 | if pending_buffer_list.is_some() && |
| 304 | (buffer.is_some() || instance.src_pad().mode() == gst::PadMode::Pull) { |
| 305 | panic!("Buffer lists can only be returned in push mode" ); |
| 306 | } |
| 307 | |
| 308 | if buffer_ptr.is_null() && pending_buffer_list.is_none() { |
| 309 | gst::error!( |
| 310 | gst::CAT_RUST, |
| 311 | obj = instance, |
| 312 | "No buffer and no buffer list returned" |
| 313 | ); |
| 314 | return Err(gst::FlowError::Error); |
| 315 | } |
| 316 | |
| 317 | if !buffer_ptr.is_null() && pending_buffer_list.is_some() { |
| 318 | gst::error!( |
| 319 | gst::CAT_RUST, |
| 320 | obj = instance, |
| 321 | "Both buffer and buffer list returned" |
| 322 | ); |
| 323 | return Err(gst::FlowError::Error); |
| 324 | } |
| 325 | |
| 326 | if let Some(passed_buffer) = buffer { |
| 327 | if buffer_ptr != orig_buffer_ptr { |
| 328 | let new_buffer = gst::Buffer::from_glib_full(buffer_ptr); |
| 329 | |
| 330 | gst::debug!( |
| 331 | gst::CAT_PERFORMANCE, |
| 332 | obj = instance, |
| 333 | "Returned new buffer from parent create function, copying into passed buffer" |
| 334 | ); |
| 335 | |
| 336 | let mut map = match passed_buffer.map_writable() { |
| 337 | Ok(map) => map, |
| 338 | Err(_) => { |
| 339 | gst::error!( |
| 340 | gst::CAT_RUST, |
| 341 | obj = instance, |
| 342 | "Failed to map passed buffer writable" |
| 343 | ); |
| 344 | return Err(gst::FlowError::Error); |
| 345 | } |
| 346 | }; |
| 347 | |
| 348 | let copied_size = new_buffer.copy_to_slice(0, &mut map); |
| 349 | drop(map); |
| 350 | |
| 351 | if let Err(copied_size) = copied_size { |
| 352 | passed_buffer.set_size(copied_size); |
| 353 | } |
| 354 | |
| 355 | match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..) { |
| 356 | Ok(_) => Ok(CreateSuccess::FilledBuffer), |
| 357 | Err(_) => { |
| 358 | gst::error!( |
| 359 | gst::CAT_RUST, |
| 360 | obj = instance, |
| 361 | "Failed to copy buffer metadata" |
| 362 | ); |
| 363 | |
| 364 | Err(gst::FlowError::Error) |
| 365 | } |
| 366 | } |
| 367 | } else { |
| 368 | Ok(CreateSuccess::FilledBuffer) |
| 369 | } |
| 370 | } else if let Some(buffer_list) = pending_buffer_list { |
| 371 | Ok(CreateSuccess::NewBufferList(buffer_list)) |
| 372 | } else { |
| 373 | Ok(CreateSuccess::NewBuffer(from_glib_full(buffer_ptr))) |
| 374 | } |
| 375 | }) |
| 376 | .unwrap_or(Err(gst::FlowError::NotSupported)) |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | fn parent_do_seek(&self, segment: &mut gst::Segment) -> bool { |
| 381 | unsafe { |
| 382 | let data = Self::type_data(); |
| 383 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 384 | (*parent_class) |
| 385 | .do_seek |
| 386 | .map(|f| { |
| 387 | from_glib(f( |
| 388 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 389 | segment.to_glib_none_mut().0, |
| 390 | )) |
| 391 | }) |
| 392 | .unwrap_or(false) |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | fn parent_query(&self, query: &mut gst::QueryRef) -> bool { |
| 397 | unsafe { |
| 398 | let data = Self::type_data(); |
| 399 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 400 | (*parent_class) |
| 401 | .query |
| 402 | .map(|f| { |
| 403 | from_glib(f( |
| 404 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 405 | query.as_mut_ptr(), |
| 406 | )) |
| 407 | }) |
| 408 | .unwrap_or(false) |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | fn parent_event(&self, event: &gst::Event) -> bool { |
| 413 | unsafe { |
| 414 | let data = Self::type_data(); |
| 415 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 416 | (*parent_class) |
| 417 | .event |
| 418 | .map(|f| { |
| 419 | from_glib(f( |
| 420 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 421 | event.to_glib_none().0, |
| 422 | )) |
| 423 | }) |
| 424 | .unwrap_or(false) |
| 425 | } |
| 426 | } |
| 427 | |
| 428 | fn parent_caps(&self, filter: Option<&gst::Caps>) -> Option<gst::Caps> { |
| 429 | unsafe { |
| 430 | let data = Self::type_data(); |
| 431 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 432 | |
| 433 | (*parent_class) |
| 434 | .get_caps |
| 435 | .map(|f| { |
| 436 | from_glib_full(f( |
| 437 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 438 | filter.to_glib_none().0, |
| 439 | )) |
| 440 | }) |
| 441 | .unwrap_or(None) |
| 442 | } |
| 443 | } |
| 444 | |
| 445 | fn parent_negotiate(&self) -> Result<(), gst::LoggableError> { |
| 446 | unsafe { |
| 447 | let data = Self::type_data(); |
| 448 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 449 | (*parent_class) |
| 450 | .negotiate |
| 451 | .map(|f| { |
| 452 | gst::result_from_gboolean!( |
| 453 | f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0), |
| 454 | gst::CAT_RUST, |
| 455 | "Parent function `negotiate` failed" |
| 456 | ) |
| 457 | }) |
| 458 | .unwrap_or(Ok(())) |
| 459 | } |
| 460 | } |
| 461 | |
| 462 | fn parent_set_caps(&self, caps: &gst::Caps) -> Result<(), gst::LoggableError> { |
| 463 | unsafe { |
| 464 | let data = Self::type_data(); |
| 465 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 466 | (*parent_class) |
| 467 | .set_caps |
| 468 | .map(|f| { |
| 469 | gst::result_from_gboolean!( |
| 470 | f( |
| 471 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 472 | caps.to_glib_none().0 |
| 473 | ), |
| 474 | gst::CAT_RUST, |
| 475 | "Parent function `set_caps` failed" |
| 476 | ) |
| 477 | }) |
| 478 | .unwrap_or(Ok(())) |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | fn parent_fixate(&self, caps: gst::Caps) -> gst::Caps { |
| 483 | unsafe { |
| 484 | let data = Self::type_data(); |
| 485 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 486 | |
| 487 | match (*parent_class).fixate { |
| 488 | Some(fixate) => from_glib_full(fixate( |
| 489 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 490 | caps.into_glib_ptr(), |
| 491 | )), |
| 492 | None => caps, |
| 493 | } |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | fn parent_unlock(&self) -> Result<(), gst::ErrorMessage> { |
| 498 | unsafe { |
| 499 | let data = Self::type_data(); |
| 500 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 501 | (*parent_class) |
| 502 | .unlock |
| 503 | .map(|f| { |
| 504 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) { |
| 505 | Ok(()) |
| 506 | } else { |
| 507 | Err(gst::error_msg!( |
| 508 | gst::CoreError::Failed, |
| 509 | ["Parent function `unlock` failed" ] |
| 510 | )) |
| 511 | } |
| 512 | }) |
| 513 | .unwrap_or(Ok(())) |
| 514 | } |
| 515 | } |
| 516 | |
| 517 | fn parent_unlock_stop(&self) -> Result<(), gst::ErrorMessage> { |
| 518 | unsafe { |
| 519 | let data = Self::type_data(); |
| 520 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 521 | (*parent_class) |
| 522 | .unlock_stop |
| 523 | .map(|f| { |
| 524 | if from_glib(f(self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0)) { |
| 525 | Ok(()) |
| 526 | } else { |
| 527 | Err(gst::error_msg!( |
| 528 | gst::CoreError::Failed, |
| 529 | ["Parent function `unlock_stop` failed" ] |
| 530 | )) |
| 531 | } |
| 532 | }) |
| 533 | .unwrap_or(Ok(())) |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | fn parent_decide_allocation( |
| 538 | &self, |
| 539 | query: &mut gst::query::Allocation, |
| 540 | ) -> Result<(), gst::LoggableError> { |
| 541 | unsafe { |
| 542 | let data = Self::type_data(); |
| 543 | let parent_class = data.as_ref().parent_class() as *mut ffi::GstBaseSrcClass; |
| 544 | (*parent_class) |
| 545 | .decide_allocation |
| 546 | .map(|f| { |
| 547 | gst::result_from_gboolean!( |
| 548 | f( |
| 549 | self.obj().unsafe_cast_ref::<BaseSrc>().to_glib_none().0, |
| 550 | query.as_mut_ptr(), |
| 551 | ), |
| 552 | gst::CAT_RUST, |
| 553 | "Parent function `decide_allocation` failed" , |
| 554 | ) |
| 555 | }) |
| 556 | .unwrap_or(Ok(())) |
| 557 | } |
| 558 | } |
| 559 | } |
| 560 | |
| 561 | impl<T: BaseSrcImpl> BaseSrcImplExt for T {} |
| 562 | |
| 563 | unsafe impl<T: BaseSrcImpl> IsSubclassable<T> for BaseSrc { |
| 564 | fn class_init(klass: &mut glib::Class<Self>) { |
| 565 | Self::parent_class_init::<T>(klass); |
| 566 | let klass = klass.as_mut(); |
| 567 | klass.start = Some(base_src_start::<T>); |
| 568 | klass.stop = Some(base_src_stop::<T>); |
| 569 | klass.is_seekable = Some(base_src_is_seekable::<T>); |
| 570 | klass.get_size = Some(base_src_get_size::<T>); |
| 571 | klass.get_times = Some(base_src_get_times::<T>); |
| 572 | klass.fill = Some(base_src_fill::<T>); |
| 573 | klass.alloc = Some(base_src_alloc::<T>); |
| 574 | klass.create = Some(base_src_create::<T>); |
| 575 | klass.do_seek = Some(base_src_do_seek::<T>); |
| 576 | klass.query = Some(base_src_query::<T>); |
| 577 | klass.event = Some(base_src_event::<T>); |
| 578 | klass.get_caps = Some(base_src_get_caps::<T>); |
| 579 | klass.negotiate = Some(base_src_negotiate::<T>); |
| 580 | klass.set_caps = Some(base_src_set_caps::<T>); |
| 581 | klass.fixate = Some(base_src_fixate::<T>); |
| 582 | klass.unlock = Some(base_src_unlock::<T>); |
| 583 | klass.unlock_stop = Some(base_src_unlock_stop::<T>); |
| 584 | klass.decide_allocation = Some(base_src_decide_allocation::<T>); |
| 585 | } |
| 586 | |
| 587 | fn instance_init(instance: &mut glib::subclass::InitializingObject<T>) { |
| 588 | Self::parent_instance_init(instance); |
| 589 | |
| 590 | instance.set_instance_data(BaseSrc::static_type(), InstanceData::default()); |
| 591 | } |
| 592 | } |
| 593 | |
| 594 | unsafe extern "C" fn base_src_start<T: BaseSrcImpl>( |
| 595 | ptr: *mut ffi::GstBaseSrc, |
| 596 | ) -> glib::ffi::gboolean { |
| 597 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 598 | let imp: &T = instance.imp(); |
| 599 | |
| 600 | gstbool::panic_to_error!(imp, false, { |
| 601 | match imp.start() { |
| 602 | Ok(()) => true, |
| 603 | Err(err) => { |
| 604 | imp.post_error_message(err); |
| 605 | false |
| 606 | } |
| 607 | } |
| 608 | }) |
| 609 | .into_glib() |
| 610 | } |
| 611 | |
| 612 | unsafe extern "C" fn base_src_stop<T: BaseSrcImpl>( |
| 613 | ptr: *mut ffi::GstBaseSrc, |
| 614 | ) -> glib::ffi::gboolean { |
| 615 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 616 | let imp: &T = instance.imp(); |
| 617 | |
| 618 | gstbool::panic_to_error!(imp, false, { |
| 619 | match imp.stop() { |
| 620 | Ok(()) => true, |
| 621 | Err(err) => { |
| 622 | imp.post_error_message(err); |
| 623 | false |
| 624 | } |
| 625 | } |
| 626 | }) |
| 627 | .into_glib() |
| 628 | } |
| 629 | |
| 630 | unsafe extern "C" fn base_src_is_seekable<T: BaseSrcImpl>( |
| 631 | ptr: *mut ffi::GstBaseSrc, |
| 632 | ) -> glib::ffi::gboolean { |
| 633 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 634 | let imp: &T = instance.imp(); |
| 635 | |
| 636 | gst::panic_to_error!(imp, false, { imp.is_seekable() }).into_glib() |
| 637 | } |
| 638 | |
| 639 | unsafe extern "C" fn base_src_get_size<T: BaseSrcImpl>( |
| 640 | ptr: *mut ffi::GstBaseSrc, |
| 641 | size: *mut u64, |
| 642 | ) -> glib::ffi::gboolean { |
| 643 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 644 | let imp: &T = instance.imp(); |
| 645 | |
| 646 | gstbool::panic_to_error!(imp, false, { |
| 647 | match imp.size() { |
| 648 | Some(s) => { |
| 649 | *size = s; |
| 650 | true |
| 651 | } |
| 652 | None => false, |
| 653 | } |
| 654 | }) |
| 655 | .into_glib() |
| 656 | } |
| 657 | |
| 658 | unsafe extern "C" fn base_src_get_times<T: BaseSrcImpl>( |
| 659 | ptr: *mut ffi::GstBaseSrc, |
| 660 | buffer: *mut gst::ffi::GstBuffer, |
| 661 | start: *mut gst::ffi::GstClockTime, |
| 662 | stop: *mut gst::ffi::GstClockTime, |
| 663 | ) { |
| 664 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 665 | let imp: &T = instance.imp(); |
| 666 | let buffer: &BufferRef = gst::BufferRef::from_ptr(buffer); |
| 667 | |
| 668 | *start = gst::ffi::GST_CLOCK_TIME_NONE; |
| 669 | *stop = gst::ffi::GST_CLOCK_TIME_NONE; |
| 670 | |
| 671 | gst::panic_to_error!(imp, (), { |
| 672 | let (start_, stop_) = imp.times(buffer); |
| 673 | *start = start_.into_glib(); |
| 674 | *stop = stop_.into_glib(); |
| 675 | }); |
| 676 | } |
| 677 | |
| 678 | unsafe extern "C" fn base_src_fill<T: BaseSrcImpl>( |
| 679 | ptr: *mut ffi::GstBaseSrc, |
| 680 | offset: u64, |
| 681 | length: u32, |
| 682 | buffer: *mut gst::ffi::GstBuffer, |
| 683 | ) -> gst::ffi::GstFlowReturn { |
| 684 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 685 | let imp: &T = instance.imp(); |
| 686 | let buffer: &mut BufferRef = gst::BufferRef::from_mut_ptr(buffer); |
| 687 | |
| 688 | gstFlowReturn::panic_to_error!(imp, gst::FlowReturn::Error, { |
| 689 | imp.fill(offset, length, buffer).into() |
| 690 | }) |
| 691 | .into_glib() |
| 692 | } |
| 693 | |
| 694 | unsafe extern "C" fn base_src_alloc<T: BaseSrcImpl>( |
| 695 | ptr: *mut ffi::GstBaseSrc, |
| 696 | offset: u64, |
| 697 | length: u32, |
| 698 | buffer_ptr: *mut gst::ffi::GstBuffer, |
| 699 | ) -> gst::ffi::GstFlowReturn { |
| 700 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 701 | let imp: &T = instance.imp(); |
| 702 | // FIXME: Wrong signature in -sys bindings |
| 703 | // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 |
| 704 | let buffer_ptr: *mut *mut GstBuffer = buffer_ptr as *mut *mut gst::ffi::GstBuffer; |
| 705 | |
| 706 | gstFlowReturn::panic_to_error!(imp, gst::FlowReturn::Error, { |
| 707 | match imp.alloc(offset, length) { |
| 708 | Ok(buffer) => { |
| 709 | *buffer_ptr = buffer.into_glib_ptr(); |
| 710 | gst::FlowReturn::Ok |
| 711 | } |
| 712 | Err(err) => gst::FlowReturn::from(err), |
| 713 | } |
| 714 | }) |
| 715 | .into_glib() |
| 716 | } |
| 717 | |
| 718 | #[allow (clippy::needless_option_as_deref)] |
| 719 | unsafe extern "C" fn base_src_create<T: BaseSrcImpl>( |
| 720 | ptr: *mut ffi::GstBaseSrc, |
| 721 | offset: u64, |
| 722 | length: u32, |
| 723 | buffer_ptr: *mut gst::ffi::GstBuffer, |
| 724 | ) -> gst::ffi::GstFlowReturn { |
| 725 | let instance = &*(ptr as *mut T::Instance); |
| 726 | let imp = instance.imp(); |
| 727 | let instance = imp.obj(); |
| 728 | let instance = instance.unsafe_cast_ref::<BaseSrc>(); |
| 729 | // FIXME: Wrong signature in -sys bindings |
| 730 | // https://gitlab.freedesktop.org/gstreamer/gstreamer-rs-sys/issues/3 |
| 731 | let buffer_ptr = buffer_ptr as *mut *mut gst::ffi::GstBuffer; |
| 732 | |
| 733 | let mut buffer = if (*buffer_ptr).is_null() { |
| 734 | None |
| 735 | } else { |
| 736 | Some(gst::BufferRef::from_mut_ptr(*buffer_ptr)) |
| 737 | }; |
| 738 | |
| 739 | let instance_data = imp |
| 740 | .instance_data::<InstanceData>(BaseSrc::static_type()) |
| 741 | .unwrap(); |
| 742 | |
| 743 | // If there is a pending buffer list at this point then unset it. |
| 744 | if instance.type_() == T::Type::static_type() { |
| 745 | *instance_data.pending_buffer_list.borrow_mut() = None; |
| 746 | } |
| 747 | |
| 748 | let res = gst::panic_to_error!(imp, gst::FlowReturn::Error, { |
| 749 | match imp.create(offset, buffer.as_deref_mut(), length) { |
| 750 | Ok(CreateSuccess::NewBuffer(new_buffer)) => { |
| 751 | if let Some(passed_buffer) = buffer { |
| 752 | if passed_buffer.as_ptr() != new_buffer.as_ptr() { |
| 753 | gst::debug!( |
| 754 | gst::CAT_PERFORMANCE, |
| 755 | obj = instance, |
| 756 | "Returned new buffer from create function, copying into passed buffer" |
| 757 | ); |
| 758 | |
| 759 | let mut map = match passed_buffer.map_writable() { |
| 760 | Ok(map) => map, |
| 761 | Err(_) => { |
| 762 | gst::error!( |
| 763 | gst::CAT_RUST, |
| 764 | obj = instance, |
| 765 | "Failed to map passed buffer writable" |
| 766 | ); |
| 767 | return gst::FlowReturn::Error; |
| 768 | } |
| 769 | }; |
| 770 | |
| 771 | let copied_size = new_buffer.copy_to_slice(0, &mut map); |
| 772 | drop(map); |
| 773 | |
| 774 | if let Err(copied_size) = copied_size { |
| 775 | passed_buffer.set_size(copied_size); |
| 776 | } |
| 777 | |
| 778 | match new_buffer.copy_into(passed_buffer, gst::BUFFER_COPY_METADATA, ..) { |
| 779 | Ok(_) => gst::FlowReturn::Ok, |
| 780 | Err(_) => { |
| 781 | gst::error!( |
| 782 | gst::CAT_RUST, |
| 783 | obj = instance, |
| 784 | "Failed to copy buffer metadata" |
| 785 | ); |
| 786 | |
| 787 | gst::FlowReturn::Error |
| 788 | } |
| 789 | } |
| 790 | } else { |
| 791 | gst::FlowReturn::Ok |
| 792 | } |
| 793 | } else { |
| 794 | *buffer_ptr = new_buffer.into_glib_ptr(); |
| 795 | gst::FlowReturn::Ok |
| 796 | } |
| 797 | } |
| 798 | Ok(CreateSuccess::NewBufferList(new_buffer_list)) => { |
| 799 | if buffer.is_some() || instance.src_pad().mode() == gst::PadMode::Pull { |
| 800 | panic!("Buffer lists can only be returned in push mode" ); |
| 801 | } |
| 802 | |
| 803 | *buffer_ptr = ptr::null_mut(); |
| 804 | |
| 805 | // If this is the final type then submit the buffer list. This can only be done |
| 806 | // once so can only really be done here. |
| 807 | // FIXME: This won't work if a non-Rust subclass of a Rust subclass is created. |
| 808 | if instance.type_() == T::Type::static_type() { |
| 809 | ffi::gst_base_src_submit_buffer_list( |
| 810 | instance.to_glib_none().0, |
| 811 | new_buffer_list.into_glib_ptr(), |
| 812 | ); |
| 813 | } else { |
| 814 | *instance_data.pending_buffer_list.borrow_mut() = Some(new_buffer_list); |
| 815 | } |
| 816 | |
| 817 | gst::FlowReturn::Ok |
| 818 | } |
| 819 | Ok(CreateSuccess::FilledBuffer) => gst::FlowReturn::Ok, |
| 820 | Err(err) => gst::FlowReturn::from(err), |
| 821 | } |
| 822 | }) |
| 823 | .into_glib(); |
| 824 | |
| 825 | // If there is a pending buffer list at this point then unset it. |
| 826 | if instance.type_() == T::Type::static_type() { |
| 827 | *instance_data.pending_buffer_list.borrow_mut() = None; |
| 828 | } |
| 829 | |
| 830 | res |
| 831 | } |
| 832 | |
| 833 | unsafe extern "C" fn base_src_do_seek<T: BaseSrcImpl>( |
| 834 | ptr: *mut ffi::GstBaseSrc, |
| 835 | segment: *mut gst::ffi::GstSegment, |
| 836 | ) -> glib::ffi::gboolean { |
| 837 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 838 | let imp: &T = instance.imp(); |
| 839 | |
| 840 | gstbool::panic_to_error!(imp, false, { |
| 841 | let mut s = from_glib_none(segment); |
| 842 | let res = imp.do_seek(&mut s); |
| 843 | ptr::write(segment, *(s.to_glib_none().0)); |
| 844 | |
| 845 | res |
| 846 | }) |
| 847 | .into_glib() |
| 848 | } |
| 849 | |
| 850 | unsafe extern "C" fn base_src_query<T: BaseSrcImpl>( |
| 851 | ptr: *mut ffi::GstBaseSrc, |
| 852 | query_ptr: *mut gst::ffi::GstQuery, |
| 853 | ) -> glib::ffi::gboolean { |
| 854 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 855 | let imp: &T = instance.imp(); |
| 856 | let query: &mut QueryRef = gst::QueryRef::from_mut_ptr(query_ptr); |
| 857 | |
| 858 | gst::panic_to_error!(imp, false, { BaseSrcImpl::query(imp, query) }).into_glib() |
| 859 | } |
| 860 | |
| 861 | unsafe extern "C" fn base_src_event<T: BaseSrcImpl>( |
| 862 | ptr: *mut ffi::GstBaseSrc, |
| 863 | event_ptr: *mut gst::ffi::GstEvent, |
| 864 | ) -> glib::ffi::gboolean { |
| 865 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 866 | let imp: &T = instance.imp(); |
| 867 | |
| 868 | gst::panic_to_error!(imp, false, { imp.event(&from_glib_borrow(event_ptr)) }).into_glib() |
| 869 | } |
| 870 | |
| 871 | unsafe extern "C" fn base_src_get_caps<T: BaseSrcImpl>( |
| 872 | ptr: *mut ffi::GstBaseSrc, |
| 873 | filter: *mut gst::ffi::GstCaps, |
| 874 | ) -> *mut gst::ffi::GstCaps { |
| 875 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 876 | let imp: &T = instance.imp(); |
| 877 | let filter: Borrowed = Option::<gst::Caps>::from_glib_borrow(_ptr:filter); |
| 878 | |
| 879 | gst::panic_to_error!(imp, None, { imp.caps(filter.as_ref().as_ref()) }) |
| 880 | .map(|caps| caps.into_glib_ptr()) |
| 881 | .unwrap_or(default:ptr::null_mut()) |
| 882 | } |
| 883 | |
| 884 | unsafe extern "C" fn base_src_negotiate<T: BaseSrcImpl>( |
| 885 | ptr: *mut ffi::GstBaseSrc, |
| 886 | ) -> glib::ffi::gboolean { |
| 887 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 888 | let imp: &T = instance.imp(); |
| 889 | |
| 890 | gstbool::panic_to_error!(imp, false, { |
| 891 | match imp.negotiate() { |
| 892 | Ok(()) => true, |
| 893 | Err(err) => { |
| 894 | err.log_with_imp(imp); |
| 895 | false |
| 896 | } |
| 897 | } |
| 898 | }) |
| 899 | .into_glib() |
| 900 | } |
| 901 | |
| 902 | unsafe extern "C" fn base_src_set_caps<T: BaseSrcImpl>( |
| 903 | ptr: *mut ffi::GstBaseSrc, |
| 904 | caps: *mut gst::ffi::GstCaps, |
| 905 | ) -> glib::ffi::gboolean { |
| 906 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 907 | let imp: &T = instance.imp(); |
| 908 | let caps: Borrowed = from_glib_borrow(ptr:caps); |
| 909 | |
| 910 | gstbool::panic_to_error!(imp, false, { |
| 911 | match imp.set_caps(&caps) { |
| 912 | Ok(()) => true, |
| 913 | Err(err) => { |
| 914 | err.log_with_imp(imp); |
| 915 | false |
| 916 | } |
| 917 | } |
| 918 | }) |
| 919 | .into_glib() |
| 920 | } |
| 921 | |
| 922 | unsafe extern "C" fn base_src_fixate<T: BaseSrcImpl>( |
| 923 | ptr: *mut ffi::GstBaseSrc, |
| 924 | caps: *mut gst::ffi::GstCaps, |
| 925 | ) -> *mut gst::ffi::GstCaps { |
| 926 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 927 | let imp: &T = instance.imp(); |
| 928 | let caps: Caps = from_glib_full(ptr:caps); |
| 929 | |
| 930 | gst::panic_to_error!(imp, gst::Caps::new_empty(), { imp.fixate(caps) }).into_glib_ptr() |
| 931 | } |
| 932 | |
| 933 | unsafe extern "C" fn base_src_unlock<T: BaseSrcImpl>( |
| 934 | ptr: *mut ffi::GstBaseSrc, |
| 935 | ) -> glib::ffi::gboolean { |
| 936 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 937 | let imp: &T = instance.imp(); |
| 938 | |
| 939 | gstbool::panic_to_error!(imp, false, { |
| 940 | match imp.unlock() { |
| 941 | Ok(()) => true, |
| 942 | Err(err) => { |
| 943 | imp.post_error_message(err); |
| 944 | false |
| 945 | } |
| 946 | } |
| 947 | }) |
| 948 | .into_glib() |
| 949 | } |
| 950 | |
| 951 | unsafe extern "C" fn base_src_unlock_stop<T: BaseSrcImpl>( |
| 952 | ptr: *mut ffi::GstBaseSrc, |
| 953 | ) -> glib::ffi::gboolean { |
| 954 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 955 | let imp: &T = instance.imp(); |
| 956 | |
| 957 | gstbool::panic_to_error!(imp, false, { |
| 958 | match imp.unlock_stop() { |
| 959 | Ok(()) => true, |
| 960 | Err(err) => { |
| 961 | imp.post_error_message(err); |
| 962 | false |
| 963 | } |
| 964 | } |
| 965 | }) |
| 966 | .into_glib() |
| 967 | } |
| 968 | |
| 969 | unsafe extern "C" fn base_src_decide_allocation<T: BaseSrcImpl>( |
| 970 | ptr: *mut ffi::GstBaseSrc, |
| 971 | query: *mut gst::ffi::GstQuery, |
| 972 | ) -> glib::ffi::gboolean { |
| 973 | let instance: &::Instance = &*(ptr as *mut T::Instance); |
| 974 | let imp: &T = instance.imp(); |
| 975 | let query: &mut Allocation = match gst::QueryRef::from_mut_ptr(query).view_mut() { |
| 976 | gst::QueryViewMut::Allocation(allocation: &mut Allocation) => allocation, |
| 977 | _ => unreachable!(), |
| 978 | }; |
| 979 | |
| 980 | gstbool::panic_to_error!(imp, false, { |
| 981 | match imp.decide_allocation(query) { |
| 982 | Ok(()) => true, |
| 983 | Err(err) => { |
| 984 | err.log_with_imp(imp); |
| 985 | false |
| 986 | } |
| 987 | } |
| 988 | }) |
| 989 | .into_glib() |
| 990 | } |
| 991 | |