1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// DO NOT EDIT

use glib;
use glib::object::Cast;
use glib::object::IsA;
use glib::signal::connect_raw;
use glib::signal::SignalHandlerId;
use glib::translate::*;
use glib::StaticType;
use glib::Value;
use glib_sys;
use gobject_sys;
use gst;
use gst_video_sys;
use std::boxed::Box as Box_;
use std::mem::transmute;
#[cfg(any(feature = "v1_14", feature = "dox"))]
use VideoCodecFrame;

glib_wrapper! {
    /// This base class is for video encoders turning raw video into
    /// encoded video data.
    ///
    /// GstVideoEncoder and subclass should cooperate as follows.
    ///
    /// ## Configuration
    ///
    ///  * Initially, GstVideoEncoder calls `start` when the encoder element
    ///  is activated, which allows subclass to perform any global setup.
    ///  * GstVideoEncoder calls `set_format` to inform subclass of the format
    ///  of input video data that it is about to receive. Subclass should
    ///  setup for encoding and configure base class as appropriate
    ///  (e.g. latency). While unlikely, it might be called more than once,
    ///  if changing input parameters require reconfiguration. Baseclass
    ///  will ensure that processing of current configuration is finished.
    ///  * GstVideoEncoder calls `stop` at end of all processing.
    ///
    /// ## Data processing
    ///
    ///  * Base class collects input data and metadata into a frame and hands
    ///  this to subclass' `handle_frame`.
    ///
    ///  * If codec processing results in encoded data, subclass should call
    ///  `VideoEncoder::finish_frame` to have encoded data pushed
    ///  downstream.
    ///
    ///  * If implemented, baseclass calls subclass `pre_push` just prior to
    ///  pushing to allow subclasses to modify some metadata on the buffer.
    ///  If it returns GST_FLOW_OK, the buffer is pushed downstream.
    ///
    ///  * GstVideoEncoderClass will handle both srcpad and sinkpad events.
    ///  Sink events will be passed to subclass if `event` callback has been
    ///  provided.
    ///
    /// ## Shutdown phase
    ///
    ///  * GstVideoEncoder class calls `stop` to inform the subclass that data
    ///  parsing will be stopped.
    ///
    /// Subclass is responsible for providing pad template caps for
    /// source and sink pads. The pads need to be named "sink" and "src". It should
    /// also be able to provide fixed src pad caps in `getcaps` by the time it calls
    /// `VideoEncoder::finish_frame`.
    ///
    /// Things that subclass need to take care of:
    ///
    ///  * Provide pad templates
    ///  * Provide source pad caps before pushing the first buffer
    ///  * Accept data in `handle_frame` and provide encoded results to
    ///  `VideoEncoder::finish_frame`.
    ///
    ///
    /// The `VideoEncoder:qos` property will enable the Quality-of-Service
    /// features of the encoder which gather statistics about the real-time
    /// performance of the downstream elements. If enabled, subclasses can
    /// use `VideoEncoderExt::get_max_encode_time` to check if input frames
    /// are already late and drop them right away to give a chance to the
    /// pipeline to catch up.
    ///
    /// # Implements
    ///
    /// [`VideoEncoderExt`](trait.VideoEncoderExt.html), [`gst::ElementExt`](../gst/trait.ElementExt.html), [`gst::ObjectExt`](../gst/trait.ObjectExt.html), [`glib::object::ObjectExt`](../glib/object/trait.ObjectExt.html)
    pub struct VideoEncoder(Object<gst_video_sys::GstVideoEncoder, gst_video_sys::GstVideoEncoderClass, VideoEncoderClass>) @extends gst::Element, gst::Object;

    match fn {
        get_type => || gst_video_sys::gst_video_encoder_get_type(),
    }
}

unsafe impl Send for VideoEncoder {}
unsafe impl Sync for VideoEncoder {}

pub const NONE_VIDEO_ENCODER: Option<&VideoEncoder> = None;

/// Trait containing all `VideoEncoder` methods.
///
/// # Implementors
///
/// [`VideoEncoder`](struct.VideoEncoder.html)
pub trait VideoEncoderExt: 'static {
    /// Helper function that allocates a buffer to hold an encoded video frame
    /// for `self`'s current `VideoCodecState`.
    /// ## `size`
    /// size of the buffer
    ///
    /// # Returns
    ///
    /// allocated buffer
    fn allocate_output_buffer(&self, size: usize) -> Result<gst::Buffer, glib::BoolError>;

    /// Determines maximum possible encoding time for `frame` that will
    /// allow it to encode and arrive in time (as determined by QoS events).
    /// In particular, a negative result means encoding in time is no longer possible
    /// and should therefore occur as soon/skippy as possible.
    ///
    /// If no QoS events have been received from downstream, or if
    /// `VideoEncoder:qos` is disabled this function returns `G_MAXINT64`.
    ///
    /// Feature: `v1_14`
    ///
    /// ## `frame`
    /// a `VideoCodecFrame`
    ///
    /// # Returns
    ///
    /// max decoding time.
    #[cfg(any(feature = "v1_14", feature = "dox"))]
    fn get_max_encode_time(&self, frame: &VideoCodecFrame) -> gst::ClockTimeDiff;

    /// Checks if `self` is currently configured to handle Quality-of-Service
    /// events from downstream.
    ///
    /// Feature: `v1_14`
    ///
    ///
    /// # Returns
    ///
    /// `true` if the encoder is configured to perform Quality-of-Service.
    #[cfg(any(feature = "v1_14", feature = "dox"))]
    fn is_qos_enabled(&self) -> bool;

    /// Sets the video encoder tags and how they should be merged with any
    /// upstream stream tags. This will override any tags previously-set
    /// with `VideoEncoderExt::merge_tags`.
    ///
    /// Note that this is provided for convenience, and the subclass is
    /// not required to use this and can still do tag handling on its own.
    ///
    /// MT safe.
    /// ## `tags`
    /// a `gst::TagList` to merge, or NULL to unset
    ///  previously-set tags
    /// ## `mode`
    /// the `gst::TagMergeMode` to use, usually `gst::TagMergeMode::Replace`
    fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode);

    /// Returns caps that express `caps` (or sink template caps if `caps` == NULL)
    /// restricted to resolution/format/... combinations supported by downstream
    /// elements (e.g. muxers).
    /// ## `caps`
    /// initial caps
    /// ## `filter`
    /// filter caps
    ///
    /// # Returns
    ///
    /// a `gst::Caps` owned by caller
    fn proxy_getcaps(&self, caps: Option<&gst::Caps>, filter: Option<&gst::Caps>) -> gst::Caps;

    /// Set the codec headers to be sent downstream whenever requested.
    /// ## `headers`
    /// a list of `gst::Buffer` containing the codec header
    fn set_headers(&self, headers: &[&gst::Buffer]);

    /// Request minimal value for PTS passed to handle_frame.
    ///
    /// For streams with reordered frames this can be used to ensure that there
    /// is enough time to accomodate first DTS, which may be less than first PTS
    /// ## `min_pts`
    /// minimal PTS that will be passed to handle_frame
    fn set_min_pts(&self, min_pts: gst::ClockTime);

    /// Configures `self` to handle Quality-of-Service events from downstream.
    ///
    /// Feature: `v1_14`
    ///
    /// ## `enabled`
    /// the new qos value.
    #[cfg(any(feature = "v1_14", feature = "dox"))]
    fn set_qos_enabled(&self, enabled: bool);

    fn get_property_qos(&self) -> bool;

    fn set_property_qos(&self, qos: bool);

    fn connect_property_qos_notify<F: Fn(&Self) + Send + Sync + 'static>(
        &self,
        f: F,
    ) -> SignalHandlerId;
}

impl<O: IsA<VideoEncoder>> VideoEncoderExt for O {
    fn allocate_output_buffer(&self, size: usize) -> Result<gst::Buffer, glib::BoolError> {
        unsafe {
            Option::<_>::from_glib_full(gst_video_sys::gst_video_encoder_allocate_output_buffer(
                self.as_ref().to_glib_none().0,
                size,
            ))
            .ok_or_else(|| glib_bool_error!("Failed to allocate output buffer"))
        }
    }

    #[cfg(any(feature = "v1_14", feature = "dox"))]
    fn get_max_encode_time(&self, frame: &VideoCodecFrame) -> gst::ClockTimeDiff {
        unsafe {
            gst_video_sys::gst_video_encoder_get_max_encode_time(
                self.as_ref().to_glib_none().0,
                frame.to_glib_none().0,
            )
        }
    }

    #[cfg(any(feature = "v1_14", feature = "dox"))]
    fn is_qos_enabled(&self) -> bool {
        unsafe {
            from_glib(gst_video_sys::gst_video_encoder_is_qos_enabled(
                self.as_ref().to_glib_none().0,
            ))
        }
    }

    fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode) {
        unsafe {
            gst_video_sys::gst_video_encoder_merge_tags(
                self.as_ref().to_glib_none().0,
                tags.to_glib_none().0,
                mode.to_glib(),
            );
        }
    }

    fn proxy_getcaps(&self, caps: Option<&gst::Caps>, filter: Option<&gst::Caps>) -> gst::Caps {
        unsafe {
            from_glib_full(gst_video_sys::gst_video_encoder_proxy_getcaps(
                self.as_ref().to_glib_none().0,
                caps.to_glib_none().0,
                filter.to_glib_none().0,
            ))
        }
    }

    fn set_headers(&self, headers: &[&gst::Buffer]) {
        unsafe {
            gst_video_sys::gst_video_encoder_set_headers(
                self.as_ref().to_glib_none().0,
                headers.to_glib_full(),
            );
        }
    }

    fn set_min_pts(&self, min_pts: gst::ClockTime) {
        unsafe {
            gst_video_sys::gst_video_encoder_set_min_pts(
                self.as_ref().to_glib_none().0,
                min_pts.to_glib(),
            );
        }
    }

    #[cfg(any(feature = "v1_14", feature = "dox"))]
    fn set_qos_enabled(&self, enabled: bool) {
        unsafe {
            gst_video_sys::gst_video_encoder_set_qos_enabled(
                self.as_ref().to_glib_none().0,
                enabled.to_glib(),
            );
        }
    }

    fn get_property_qos(&self) -> bool {
        unsafe {
            let mut value = Value::from_type(<bool as StaticType>::static_type());
            gobject_sys::g_object_get_property(
                self.to_glib_none().0 as *mut gobject_sys::GObject,
                b"qos\0".as_ptr() as *const _,
                value.to_glib_none_mut().0,
            );
            value
                .get()
                .expect("Return Value for property `qos` getter")
                .unwrap()
        }
    }

    fn set_property_qos(&self, qos: bool) {
        unsafe {
            gobject_sys::g_object_set_property(
                self.to_glib_none().0 as *mut gobject_sys::GObject,
                b"qos\0".as_ptr() as *const _,
                Value::from(&qos).to_glib_none().0,
            );
        }
    }

    fn connect_property_qos_notify<F: Fn(&Self) + Send + Sync + 'static>(
        &self,
        f: F,
    ) -> SignalHandlerId {
        unsafe extern "C" fn notify_qos_trampoline<P, F: Fn(&P) + Send + Sync + 'static>(
            this: *mut gst_video_sys::GstVideoEncoder,
            _param_spec: glib_sys::gpointer,
            f: glib_sys::gpointer,
        ) where
            P: IsA<VideoEncoder>,
        {
            let f: &F = &*(f as *const F);
            f(&VideoEncoder::from_glib_borrow(this).unsafe_cast())
        }
        unsafe {
            let f: Box_<F> = Box_::new(f);
            connect_raw(
                self.as_ptr() as *mut _,
                b"notify::qos\0".as_ptr() as *const _,
                Some(transmute(notify_qos_trampoline::<Self, F> as usize)),
                Box_::into_raw(f),
            )
        }
    }
}