| 1 | // Take a look at the license at the top of the repository in the LICENSE file. |
| 2 | |
| 3 | use std::{fmt, marker::PhantomData, mem}; |
| 4 | |
| 5 | use glib::translate::*; |
| 6 | |
| 7 | use crate::{ffi, utils::HasStreamLock, VideoCodecFrameFlags}; |
| 8 | |
| 9 | pub struct VideoCodecFrame<'a> { |
| 10 | frame: *mut ffi::GstVideoCodecFrame, |
| 11 | /* GstVideoCodecFrame API isn't safe so protect the frame using the |
| 12 | * element (decoder or encoder) stream lock */ |
| 13 | element: &'a dyn HasStreamLock, |
| 14 | } |
| 15 | |
| 16 | #[doc (hidden)] |
| 17 | impl<'a> ::glib::translate::ToGlibPtr<'a, *mut ffi::GstVideoCodecFrame> for VideoCodecFrame<'a> { |
| 18 | type Storage = PhantomData<&'a Self>; |
| 19 | |
| 20 | #[inline ] |
| 21 | fn to_glib_none(&'a self) -> ::glib::translate::Stash<'a, *mut ffi::GstVideoCodecFrame, Self> { |
| 22 | Stash(self.frame, PhantomData) |
| 23 | } |
| 24 | |
| 25 | #[inline ] |
| 26 | fn to_glib_full(&self) -> *mut ffi::GstVideoCodecFrame { |
| 27 | unsafe { ffi::gst_video_codec_frame_ref(self.frame) } |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | impl fmt::Debug for VideoCodecFrame<'_> { |
| 32 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 33 | let mut b: DebugStruct<'_, '_> = f.debug_struct(name:"VideoCodecFrame" ); |
| 34 | |
| 35 | b.field("flags" , &self.flags()) |
| 36 | .field("system_frame_number" , &self.system_frame_number()) |
| 37 | .field("decode_frame_number" , &self.decode_frame_number()) |
| 38 | .field( |
| 39 | "presentation_frame_number" , |
| 40 | &self.presentation_frame_number(), |
| 41 | ) |
| 42 | .field("dts" , &self.dts()) |
| 43 | .field("pts" , &self.pts()) |
| 44 | .field("duration" , &self.duration()) |
| 45 | .field("distance_from_sync" , &self.distance_from_sync()) |
| 46 | .field("input_buffer" , &self.input_buffer()) |
| 47 | .field("output_buffer" , &self.output_buffer()) |
| 48 | .field(name:"deadline" , &self.deadline()); |
| 49 | |
| 50 | b.finish() |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | impl<'a> VideoCodecFrame<'a> { |
| 55 | // Take ownership of @frame |
| 56 | pub(crate) unsafe fn new<T: HasStreamLock>( |
| 57 | frame: *mut ffi::GstVideoCodecFrame, |
| 58 | element: &'a T, |
| 59 | ) -> Self { |
| 60 | skip_assert_initialized!(); |
| 61 | let stream_lock = element.stream_lock(); |
| 62 | glib::ffi::g_rec_mutex_lock(stream_lock); |
| 63 | Self { frame, element } |
| 64 | } |
| 65 | |
| 66 | #[doc (alias = "get_flags" )] |
| 67 | #[inline ] |
| 68 | pub fn flags(&self) -> VideoCodecFrameFlags { |
| 69 | let flags = unsafe { (*self.to_glib_none().0).flags }; |
| 70 | VideoCodecFrameFlags::from_bits_truncate(flags) |
| 71 | } |
| 72 | |
| 73 | #[inline ] |
| 74 | pub fn set_flags(&mut self, flags: VideoCodecFrameFlags) { |
| 75 | unsafe { (*self.to_glib_none().0).flags |= flags.bits() } |
| 76 | } |
| 77 | |
| 78 | #[inline ] |
| 79 | pub fn unset_flags(&mut self, flags: VideoCodecFrameFlags) { |
| 80 | unsafe { (*self.to_glib_none().0).flags &= !flags.bits() } |
| 81 | } |
| 82 | |
| 83 | #[doc (alias = "get_system_frame_number" )] |
| 84 | #[inline ] |
| 85 | pub fn system_frame_number(&self) -> u32 { |
| 86 | unsafe { (*self.to_glib_none().0).system_frame_number } |
| 87 | } |
| 88 | |
| 89 | #[doc (alias = "get_decode_frame_number" )] |
| 90 | #[inline ] |
| 91 | pub fn decode_frame_number(&self) -> u32 { |
| 92 | unsafe { (*self.to_glib_none().0).decode_frame_number } |
| 93 | } |
| 94 | |
| 95 | #[doc (alias = "get_presentation_frame_number" )] |
| 96 | #[inline ] |
| 97 | pub fn presentation_frame_number(&self) -> u32 { |
| 98 | unsafe { (*self.to_glib_none().0).presentation_frame_number } |
| 99 | } |
| 100 | |
| 101 | #[doc (alias = "get_dts" )] |
| 102 | #[inline ] |
| 103 | pub fn dts(&self) -> Option<gst::ClockTime> { |
| 104 | unsafe { from_glib((*self.to_glib_none().0).dts) } |
| 105 | } |
| 106 | |
| 107 | #[inline ] |
| 108 | pub fn set_dts(&mut self, dts: impl Into<Option<gst::ClockTime>>) { |
| 109 | unsafe { |
| 110 | (*self.to_glib_none().0).dts = dts.into().into_glib(); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | #[doc (alias = "get_pts" )] |
| 115 | #[inline ] |
| 116 | pub fn pts(&self) -> Option<gst::ClockTime> { |
| 117 | unsafe { from_glib((*self.to_glib_none().0).pts) } |
| 118 | } |
| 119 | |
| 120 | #[inline ] |
| 121 | pub fn set_pts(&mut self, pts: impl Into<Option<gst::ClockTime>>) { |
| 122 | unsafe { |
| 123 | (*self.to_glib_none().0).pts = pts.into().into_glib(); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | #[doc (alias = "get_duration" )] |
| 128 | #[inline ] |
| 129 | pub fn duration(&self) -> Option<gst::ClockTime> { |
| 130 | unsafe { from_glib((*self.to_glib_none().0).duration) } |
| 131 | } |
| 132 | |
| 133 | #[inline ] |
| 134 | pub fn set_duration(&mut self, duration: impl Into<Option<gst::ClockTime>>) { |
| 135 | unsafe { |
| 136 | (*self.to_glib_none().0).duration = duration.into().into_glib(); |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | #[doc (alias = "get_distance_from_sync" )] |
| 141 | #[inline ] |
| 142 | pub fn distance_from_sync(&self) -> i32 { |
| 143 | unsafe { (*self.to_glib_none().0).distance_from_sync } |
| 144 | } |
| 145 | |
| 146 | #[doc (alias = "get_input_buffer" )] |
| 147 | #[inline ] |
| 148 | pub fn input_buffer(&self) -> Option<&gst::BufferRef> { |
| 149 | unsafe { |
| 150 | let ptr = (*self.to_glib_none().0).input_buffer; |
| 151 | if ptr.is_null() { |
| 152 | None |
| 153 | } else { |
| 154 | Some(gst::BufferRef::from_ptr(ptr)) |
| 155 | } |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | #[doc (alias = "get_input_buffer" )] |
| 160 | #[inline ] |
| 161 | pub fn input_buffer_owned(&self) -> Option<gst::Buffer> { |
| 162 | unsafe { |
| 163 | let ptr = (*self.to_glib_none().0).input_buffer; |
| 164 | if ptr.is_null() { |
| 165 | None |
| 166 | } else { |
| 167 | Some(from_glib_none(ptr)) |
| 168 | } |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | #[doc (alias = "get_output_buffer" )] |
| 173 | #[inline ] |
| 174 | pub fn output_buffer(&self) -> Option<&gst::BufferRef> { |
| 175 | unsafe { |
| 176 | let ptr = (*self.to_glib_none().0).output_buffer; |
| 177 | if ptr.is_null() { |
| 178 | None |
| 179 | } else { |
| 180 | Some(gst::BufferRef::from_ptr(ptr)) |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | #[doc (alias = "get_output_buffer_mut" )] |
| 186 | pub fn output_buffer_mut(&mut self) -> Option<&mut gst::BufferRef> { |
| 187 | unsafe { |
| 188 | let ptr = (*self.to_glib_none().0).output_buffer; |
| 189 | if ptr.is_null() { |
| 190 | None |
| 191 | } else { |
| 192 | let writable: bool = from_glib(gst::ffi::gst_mini_object_is_writable( |
| 193 | ptr as *const gst::ffi::GstMiniObject, |
| 194 | )); |
| 195 | debug_assert!(writable); |
| 196 | |
| 197 | Some(gst::BufferRef::from_mut_ptr(ptr)) |
| 198 | } |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | pub fn set_output_buffer(&mut self, output_buffer: gst::Buffer) { |
| 203 | unsafe { |
| 204 | assert!(output_buffer.is_writable()); |
| 205 | let prev = (*self.to_glib_none().0).output_buffer; |
| 206 | |
| 207 | if !prev.is_null() { |
| 208 | gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject); |
| 209 | } |
| 210 | |
| 211 | (*self.to_glib_none().0).output_buffer = output_buffer.into_glib_ptr(); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | #[doc (alias = "get_deadline" )] |
| 216 | #[inline ] |
| 217 | pub fn deadline(&self) -> Option<gst::ClockTime> { |
| 218 | unsafe { from_glib((*self.to_glib_none().0).deadline) } |
| 219 | } |
| 220 | |
| 221 | #[cfg (feature = "v1_20" )] |
| 222 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_20" )))] |
| 223 | #[doc (alias = "gst_video_decoder_get_processed_subframe_index" )] |
| 224 | #[inline ] |
| 225 | pub fn subframes_processed(&self) -> u32 { |
| 226 | unsafe { (*self.to_glib_none().0).abidata.ABI.subframes_processed } |
| 227 | } |
| 228 | |
| 229 | #[cfg (feature = "v1_20" )] |
| 230 | #[cfg_attr (docsrs, doc(cfg(feature = "v1_20" )))] |
| 231 | #[doc (alias = "gst_video_decoder_get_input_subframe_index" )] |
| 232 | #[inline ] |
| 233 | pub fn num_subframes(&self) -> u32 { |
| 234 | unsafe { (*self.to_glib_none().0).abidata.ABI.num_subframes } |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | impl IntoGlibPtr<*mut ffi::GstVideoCodecFrame> for VideoCodecFrame<'_> { |
| 239 | #[inline ] |
| 240 | unsafe fn into_glib_ptr(self) -> *mut ffi::GstVideoCodecFrame { |
| 241 | let stream_lock: *mut GRecMutex = self.element.stream_lock(); |
| 242 | glib::ffi::g_rec_mutex_unlock(rec_mutex:stream_lock); |
| 243 | |
| 244 | let s: ManuallyDrop> = mem::ManuallyDrop::new(self); |
| 245 | s.to_glib_none().0 |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | impl Drop for VideoCodecFrame<'_> { |
| 250 | #[inline ] |
| 251 | fn drop(&mut self) { |
| 252 | unsafe { |
| 253 | let stream_lock: *mut GRecMutex = self.element.stream_lock(); |
| 254 | glib::ffi::g_rec_mutex_unlock(rec_mutex:stream_lock); |
| 255 | |
| 256 | ffi::gst_video_codec_frame_unref(self.frame); |
| 257 | } |
| 258 | } |
| 259 | } |
| 260 | |