2 * Copyright (C) 2008 David Schleef <ds@schleef.org>
3 * Copyright (C) 2011 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>.
4 * Copyright (C) 2011 Nokia Corporation. All rights reserved.
5 * Contact: Stefan Kost <stefan.kost@nokia.com>
6 * Copyright (C) 2012 Collabora Ltd.
7 * Author : Edward Hervey <edward@collabora.com>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * SECTION:gstvideoencoder
27 * @short_description: Base class for video encoders
30 * This base class is for video encoders turning raw video into
33 * GstVideoEncoder and subclass should cooperate as follows.
36 * <itemizedlist><title>Configuration</title>
38 * Initially, GstVideoEncoder calls @start when the encoder element
39 * is activated, which allows subclass to perform any global setup.
42 * GstVideoEncoder calls @set_format to inform subclass of the format
43 * of input video data that it is about to receive. Subclass should
44 * setup for encoding and configure base class as appropriate
45 * (e.g. latency). While unlikely, it might be called more than once,
46 * if changing input parameters require reconfiguration. Baseclass
47 * will ensure that processing of current configuration is finished.
50 * GstVideoEncoder calls @stop at end of all processing.
56 * <title>Data processing</title>
58 * Base class collects input data and metadata into a frame and hands
59 * this to subclass' @handle_frame.
62 * If codec processing results in encoded data, subclass should call
63 * @gst_video_encoder_finish_frame to have encoded data pushed
67 * If implemented, baseclass calls subclass @pre_push just prior to
68 * pushing to allow subclasses to modify some metadata on the buffer.
69 * If it returns GST_FLOW_OK, the buffer is pushed downstream.
72 * GstVideoEncoderClass will handle both srcpad and sinkpad events.
73 * Sink events will be passed to subclass if @event callback has been
79 * <itemizedlist><title>Shutdown phase</title>
81 * GstVideoEncoder class calls @stop to inform the subclass that data
82 * parsing will be stopped.
88 * Subclass is responsible for providing pad template caps for
89 * source and sink pads. The pads need to be named "sink" and "src". It should
90 * also be able to provide fixed src pad caps in @getcaps by the time it calls
91 * @gst_video_encoder_finish_frame.
93 * Things that subclass need to take care of:
95 * <listitem><para>Provide pad templates</para></listitem>
97 * Provide source pad caps before pushing the first buffer
100 * Accept data in @handle_frame and provide encoded results to
101 * @gst_video_encoder_finish_frame.
113 * * Change _set_output_format() to steal the reference of the provided caps
114 * * Calculate actual latency based on input/output timestamp/frame_number
115 * and if it exceeds the recorded one, save it and emit a GST_MESSAGE_LATENCY
118 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
119 * with newer GLib versions (>= 2.31.0) */
120 #define GLIB_DISABLE_DEPRECATION_WARNINGS
122 #include "gstvideoencoder.h"
123 #include "gstvideoutils.h"
127 GST_DEBUG_CATEGORY (videoencoder_debug);
128 #define GST_CAT_DEFAULT videoencoder_debug
130 #define GST_VIDEO_ENCODER_GET_PRIVATE(obj) \
131 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_VIDEO_ENCODER, \
132 GstVideoEncoderPrivate))
134 struct _GstVideoEncoderPrivate
136 guint64 presentation_frame_number;
137 int distance_from_sync;
139 /* FIXME : (and introduce a context ?) */
146 GList *current_frame_events;
149 gboolean new_headers; /* Whether new headers were just set */
151 GList *force_key_unit; /* List of pending forced keyunits */
153 guint64 system_frame_number;
155 GList *frames; /* Protected with OBJECT_LOCK */
156 GstVideoCodecState *input_state;
157 GstVideoCodecState *output_state;
158 gboolean output_state_changed;
164 typedef struct _ForcedKeyUnitEvent ForcedKeyUnitEvent;
165 struct _ForcedKeyUnitEvent
167 GstClockTime running_time;
168 gboolean pending; /* TRUE if this was requested already */
169 gboolean all_headers;
174 forced_key_unit_event_free (ForcedKeyUnitEvent * evt)
176 g_slice_free (ForcedKeyUnitEvent, evt);
179 static ForcedKeyUnitEvent *
180 forced_key_unit_event_new (GstClockTime running_time, gboolean all_headers,
183 ForcedKeyUnitEvent *evt = g_slice_new0 (ForcedKeyUnitEvent);
185 evt->running_time = running_time;
186 evt->all_headers = all_headers;
192 static void gst_video_encoder_finalize (GObject * object);
194 static gboolean gst_video_encoder_sink_setcaps (GstPad * pad, GstCaps * caps);
195 static GstCaps *gst_video_encoder_sink_getcaps (GstPad * pad);
196 static gboolean gst_video_encoder_src_event (GstPad * pad, GstEvent * event);
197 static gboolean gst_video_encoder_sink_event (GstPad * pad, GstEvent * event);
198 static GstFlowReturn gst_video_encoder_chain (GstPad * pad, GstBuffer * buf);
199 static GstStateChangeReturn gst_video_encoder_change_state (GstElement *
200 element, GstStateChange transition);
201 static const GstQueryType *gst_video_encoder_get_query_types (GstPad * pad);
202 static gboolean gst_video_encoder_src_query (GstPad * pad, GstQuery * query);
203 static GstVideoCodecFrame *gst_video_encoder_new_frame (GstVideoEncoder *
204 encoder, GstBuffer * buf, GstClockTime timestamp, GstClockTime duration);
207 _do_init (GType object_type)
209 const GInterfaceInfo preset_interface_info = {
210 NULL, /* interface_init */
211 NULL, /* interface_finalize */
212 NULL /* interface_data */
215 g_type_add_interface_static (object_type, GST_TYPE_PRESET,
216 &preset_interface_info);
219 GST_BOILERPLATE_FULL (GstVideoEncoder, gst_video_encoder,
220 GstElement, GST_TYPE_ELEMENT, _do_init);
223 gst_video_encoder_base_init (gpointer g_class)
225 GST_DEBUG_CATEGORY_INIT (videoencoder_debug, "videoencoder", 0,
226 "Base Video Encoder");
230 gst_video_encoder_class_init (GstVideoEncoderClass * klass)
232 GObjectClass *gobject_class;
233 GstElementClass *gstelement_class;
235 gobject_class = G_OBJECT_CLASS (klass);
236 gstelement_class = GST_ELEMENT_CLASS (klass);
238 g_type_class_add_private (klass, sizeof (GstVideoEncoderPrivate));
240 gobject_class->finalize = gst_video_encoder_finalize;
242 gstelement_class->change_state =
243 GST_DEBUG_FUNCPTR (gst_video_encoder_change_state);
247 gst_video_encoder_reset (GstVideoEncoder * encoder)
249 GstVideoEncoderPrivate *priv = encoder->priv;
252 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
254 priv->presentation_frame_number = 0;
255 priv->distance_from_sync = 0;
257 g_list_foreach (priv->force_key_unit, (GFunc) forced_key_unit_event_free,
259 g_list_free (priv->force_key_unit);
260 priv->force_key_unit = NULL;
262 priv->drained = TRUE;
263 priv->min_latency = 0;
264 priv->max_latency = 0;
266 g_list_foreach (priv->headers, (GFunc) gst_event_unref, NULL);
267 g_list_free (priv->headers);
268 priv->headers = NULL;
269 priv->new_headers = FALSE;
271 g_list_foreach (priv->current_frame_events, (GFunc) gst_event_unref, NULL);
272 g_list_free (priv->current_frame_events);
273 priv->current_frame_events = NULL;
275 for (g = priv->frames; g; g = g->next) {
276 gst_video_codec_frame_unref ((GstVideoCodecFrame *) g->data);
278 g_list_free (priv->frames);
284 if (priv->input_state)
285 gst_video_codec_state_unref (priv->input_state);
286 priv->input_state = NULL;
287 if (priv->output_state)
288 gst_video_codec_state_unref (priv->output_state);
289 priv->output_state = NULL;
291 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
295 gst_video_encoder_init (GstVideoEncoder * encoder, GstVideoEncoderClass * klass)
297 GstVideoEncoderPrivate *priv;
298 GstPadTemplate *pad_template;
301 GST_DEBUG_OBJECT (encoder, "gst_video_encoder_init");
303 priv = encoder->priv = GST_VIDEO_ENCODER_GET_PRIVATE (encoder);
306 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
307 g_return_if_fail (pad_template != NULL);
309 encoder->sinkpad = pad = gst_pad_new_from_template (pad_template, "sink");
311 gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_video_encoder_chain));
312 gst_pad_set_event_function (pad,
313 GST_DEBUG_FUNCPTR (gst_video_encoder_sink_event));
314 gst_pad_set_setcaps_function (pad,
315 GST_DEBUG_FUNCPTR (gst_video_encoder_sink_setcaps));
316 gst_pad_set_getcaps_function (pad,
317 GST_DEBUG_FUNCPTR (gst_video_encoder_sink_getcaps));
318 gst_element_add_pad (GST_ELEMENT (encoder), encoder->sinkpad);
321 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
322 g_return_if_fail (pad_template != NULL);
324 encoder->srcpad = pad = gst_pad_new_from_template (pad_template, "src");
326 gst_pad_set_query_type_function (pad,
327 GST_DEBUG_FUNCPTR (gst_video_encoder_get_query_types));
328 gst_pad_set_query_function (pad,
329 GST_DEBUG_FUNCPTR (gst_video_encoder_src_query));
330 gst_pad_set_event_function (pad,
331 GST_DEBUG_FUNCPTR (gst_video_encoder_src_event));
332 gst_element_add_pad (GST_ELEMENT (encoder), encoder->srcpad);
334 gst_segment_init (&encoder->input_segment, GST_FORMAT_TIME);
335 gst_segment_init (&encoder->output_segment, GST_FORMAT_TIME);
337 g_static_rec_mutex_init (&encoder->stream_lock);
339 priv->at_eos = FALSE;
340 priv->headers = NULL;
341 priv->new_headers = FALSE;
343 gst_video_encoder_reset (encoder);
347 gst_video_encoded_video_convert (gint64 bytes, gint64 time,
348 GstFormat src_format, gint64 src_value, GstFormat * dest_format,
351 gboolean res = FALSE;
353 g_return_val_if_fail (dest_format != NULL, FALSE);
354 g_return_val_if_fail (dest_value != NULL, FALSE);
356 if (G_UNLIKELY (src_format == *dest_format || src_value == 0 ||
359 *dest_value = src_value;
363 if (bytes <= 0 || time <= 0) {
364 GST_DEBUG ("not enough metadata yet to convert");
368 switch (src_format) {
369 case GST_FORMAT_BYTES:
370 switch (*dest_format) {
371 case GST_FORMAT_TIME:
372 *dest_value = gst_util_uint64_scale (src_value, time, bytes);
379 case GST_FORMAT_TIME:
380 switch (*dest_format) {
381 case GST_FORMAT_BYTES:
382 *dest_value = gst_util_uint64_scale (src_value, bytes, time);
390 GST_DEBUG ("unhandled conversion from %d to %d", src_format,
400 * gst_video_encoder_set_headers:
401 * @encoder: a #GstVideoEncoder
402 * @headers: (transfer full) (element-type GstBuffer): a list of #GstBuffer containing the codec header
404 * Set the codec headers to be sent downstream whenever requested.
409 gst_video_encoder_set_headers (GstVideoEncoder * video_encoder, GList * headers)
411 GST_VIDEO_ENCODER_STREAM_LOCK (video_encoder);
413 GST_DEBUG_OBJECT (video_encoder, "new headers %p", headers);
414 if (video_encoder->priv->headers) {
415 g_list_foreach (video_encoder->priv->headers, (GFunc) gst_buffer_unref,
417 g_list_free (video_encoder->priv->headers);
419 video_encoder->priv->headers = headers;
420 video_encoder->priv->new_headers = TRUE;
422 GST_VIDEO_ENCODER_STREAM_UNLOCK (video_encoder);
426 gst_video_encoder_drain (GstVideoEncoder * enc)
428 GstVideoEncoderPrivate *priv;
429 GstVideoEncoderClass *enc_class;
432 enc_class = GST_VIDEO_ENCODER_GET_CLASS (enc);
435 GST_DEBUG_OBJECT (enc, "draining");
438 GST_DEBUG_OBJECT (enc, "already drained");
442 if (enc_class->reset) {
443 GST_DEBUG_OBJECT (enc, "requesting subclass to finish");
444 ret = enc_class->reset (enc, TRUE);
446 /* everything should be away now */
448 /* not fatal/impossible though if subclass/enc eats stuff */
449 g_list_foreach (priv->frames, (GFunc) gst_video_codec_frame_unref, NULL);
450 g_list_free (priv->frames);
457 static GstVideoCodecState *
458 _new_output_state (GstCaps * caps, GstVideoCodecState * reference)
460 GstVideoCodecState *state;
462 state = g_slice_new0 (GstVideoCodecState);
463 state->ref_count = 1;
464 gst_video_info_init (&state->info);
465 gst_video_info_set_format (&state->info, GST_VIDEO_FORMAT_ENCODED, 0, 0);
470 GstVideoInfo *tgt, *ref;
473 ref = &reference->info;
475 /* Copy over extra fields from reference state */
476 tgt->interlace_mode = ref->interlace_mode;
477 tgt->flags = ref->flags;
478 tgt->width = ref->width;
479 tgt->height = ref->height;
480 tgt->chroma_site = ref->chroma_site;
481 tgt->colorimetry = ref->colorimetry;
482 tgt->par_n = ref->par_n;
483 tgt->par_d = ref->par_d;
484 tgt->fps_n = ref->fps_n;
485 tgt->fps_d = ref->fps_d;
491 static GstVideoCodecState *
492 _new_input_state (GstCaps * caps)
494 GstVideoCodecState *state;
496 state = g_slice_new0 (GstVideoCodecState);
497 state->ref_count = 1;
498 gst_video_info_init (&state->info);
499 if (G_UNLIKELY (!gst_video_info_from_caps (&state->info, caps)))
501 state->caps = gst_caps_ref (caps);
507 g_slice_free (GstVideoCodecState, state);
513 gst_video_encoder_sink_setcaps (GstPad * pad, GstCaps * caps)
515 GstVideoEncoder *encoder;
516 GstVideoEncoderClass *encoder_class;
517 GstVideoCodecState *state;
519 gboolean samecaps = FALSE;
521 encoder = GST_VIDEO_ENCODER (gst_pad_get_parent (pad));
522 encoder_class = GST_VIDEO_ENCODER_GET_CLASS (encoder);
524 /* subclass should do something here ... */
525 g_return_val_if_fail (encoder_class->set_format != NULL, FALSE);
527 GST_DEBUG_OBJECT (encoder, "setcaps %" GST_PTR_FORMAT, caps);
529 state = _new_input_state (caps);
530 if (G_UNLIKELY (!state))
533 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
535 if (encoder->priv->input_state)
537 gst_video_info_is_equal (&state->info,
538 &encoder->priv->input_state->info);
541 /* arrange draining pending frames */
542 gst_video_encoder_drain (encoder);
544 /* and subclass should be ready to configure format at any time around */
545 ret = encoder_class->set_format (encoder, state);
547 if (encoder->priv->input_state)
548 gst_video_codec_state_unref (encoder->priv->input_state);
549 encoder->priv->input_state = state;
551 gst_video_codec_state_unref (state);
553 /* no need to stir things up */
554 GST_DEBUG_OBJECT (encoder,
555 "new video format identical to configured format");
556 gst_video_codec_state_unref (state);
560 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
563 GST_WARNING_OBJECT (encoder, "rejected caps %" GST_PTR_FORMAT, caps);
565 gst_object_unref (encoder);
571 GST_WARNING_OBJECT (encoder, "Failed to parse caps");
572 gst_object_unref (encoder);
578 * gst_video_encoder_proxy_getcaps:
579 * @enc: a #GstVideoEncoder
580 * @caps: initial caps
582 * Returns caps that express @caps (or sink template caps if @caps == NULL)
583 * restricted to resolution/format/... combinations supported by downstream
584 * elements (e.g. muxers).
586 * Returns: a #GstCaps owned by caller
591 gst_video_encoder_proxy_getcaps (GstVideoEncoder * encoder, GstCaps * caps)
593 const GstCaps *templ_caps;
595 GstCaps *fcaps, *filter_caps;
598 /* Allow downstream to specify width/height/framerate/PAR constraints
599 * and forward them upstream for video converters to handle
601 templ_caps = caps ? caps : gst_pad_get_pad_template_caps (encoder->sinkpad);
602 allowed = gst_pad_get_allowed_caps (encoder->srcpad);
604 if (!allowed || gst_caps_is_empty (allowed) || gst_caps_is_any (allowed)) {
605 fcaps = gst_caps_copy (templ_caps);
609 GST_LOG_OBJECT (encoder, "template caps %" GST_PTR_FORMAT, templ_caps);
610 GST_LOG_OBJECT (encoder, "allowed caps %" GST_PTR_FORMAT, allowed);
612 filter_caps = gst_caps_new_empty ();
614 for (i = 0; i < gst_caps_get_size (templ_caps); i++) {
616 gst_structure_get_name_id (gst_caps_get_structure (templ_caps, i));
618 for (j = 0; j < gst_caps_get_size (allowed); j++) {
619 const GstStructure *allowed_s = gst_caps_get_structure (allowed, j);
623 s = gst_structure_id_empty_new (q_name);
624 if ((val = gst_structure_get_value (allowed_s, "width")))
625 gst_structure_set_value (s, "width", val);
626 if ((val = gst_structure_get_value (allowed_s, "height")))
627 gst_structure_set_value (s, "height", val);
628 if ((val = gst_structure_get_value (allowed_s, "framerate")))
629 gst_structure_set_value (s, "framerate", val);
630 if ((val = gst_structure_get_value (allowed_s, "pixel-aspect-ratio")))
631 gst_structure_set_value (s, "pixel-aspect-ratio", val);
633 gst_caps_merge_structure (filter_caps, s);
637 fcaps = gst_caps_intersect (filter_caps, templ_caps);
638 gst_caps_unref (filter_caps);
641 gst_caps_replace (&allowed, NULL);
643 GST_LOG_OBJECT (encoder, "proxy caps %" GST_PTR_FORMAT, fcaps);
649 gst_video_encoder_sink_getcaps (GstPad * pad)
651 GstVideoEncoder *encoder;
652 GstVideoEncoderClass *klass;
655 encoder = GST_VIDEO_ENCODER (gst_pad_get_parent (pad));
656 klass = GST_VIDEO_ENCODER_GET_CLASS (encoder);
659 caps = klass->getcaps (encoder);
661 caps = gst_video_encoder_proxy_getcaps (encoder, NULL);
662 gst_object_unref (encoder);
664 GST_LOG_OBJECT (encoder, "Returning caps %" GST_PTR_FORMAT, caps);
670 gst_video_encoder_finalize (GObject * object)
672 GstVideoEncoder *encoder;
674 GST_DEBUG_OBJECT (object, "finalize");
676 encoder = GST_VIDEO_ENCODER (object);
677 if (encoder->priv->headers) {
678 g_list_foreach (encoder->priv->headers, (GFunc) gst_buffer_unref, NULL);
679 g_list_free (encoder->priv->headers);
681 g_static_rec_mutex_free (&encoder->stream_lock);
683 G_OBJECT_CLASS (parent_class)->finalize (object);
687 gst_video_encoder_push_event (GstVideoEncoder * encoder, GstEvent * event)
689 switch (GST_EVENT_TYPE (event)) {
690 case GST_EVENT_NEWSEGMENT:
700 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
701 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
702 &format, &start, &stop, &position);
704 GST_DEBUG_OBJECT (encoder, "newseg rate %g, applied rate %g, "
705 "format %d, start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
706 ", pos = %" GST_TIME_FORMAT, rate, applied_rate, format,
707 GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
708 GST_TIME_ARGS (position));
710 if (format != GST_FORMAT_TIME) {
711 GST_DEBUG_OBJECT (encoder, "received non TIME newsegment");
712 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
716 gst_segment_set_newsegment_full (&encoder->output_segment, update, rate,
717 applied_rate, format, start, stop, position);
718 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
725 return gst_pad_push_event (encoder->srcpad, event);
729 gst_video_encoder_sink_eventfunc (GstVideoEncoder * encoder, GstEvent * event)
731 GstVideoEncoderClass *encoder_class;
732 gboolean ret = FALSE;
734 encoder_class = GST_VIDEO_ENCODER_GET_CLASS (encoder);
736 switch (GST_EVENT_TYPE (event)) {
739 GstFlowReturn flow_ret;
741 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
742 encoder->priv->at_eos = TRUE;
744 if (encoder_class->finish) {
745 flow_ret = encoder_class->finish (encoder);
747 flow_ret = GST_FLOW_OK;
750 ret = (flow_ret == GST_VIDEO_ENCODER_FLOW_DROPPED);
751 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
754 case GST_EVENT_NEWSEGMENT:
764 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
765 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
766 &format, &start, &stop, &position);
768 GST_DEBUG_OBJECT (encoder, "newseg rate %g, applied rate %g, "
769 "format %d, start = %" GST_TIME_FORMAT ", stop = %" GST_TIME_FORMAT
770 ", pos = %" GST_TIME_FORMAT, rate, applied_rate, format,
771 GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
772 GST_TIME_ARGS (position));
774 if (format != GST_FORMAT_TIME) {
775 GST_DEBUG_OBJECT (encoder, "received non TIME newsegment");
776 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
780 encoder->priv->at_eos = FALSE;
782 gst_segment_set_newsegment_full (&encoder->input_segment, update, rate,
783 applied_rate, format, start, stop, position);
784 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
787 case GST_EVENT_CUSTOM_DOWNSTREAM:
789 if (gst_video_event_is_force_key_unit (event)) {
790 GstClockTime running_time;
791 gboolean all_headers;
794 if (gst_video_event_parse_downstream_force_key_unit (event,
795 NULL, NULL, &running_time, &all_headers, &count)) {
796 ForcedKeyUnitEvent *fevt;
798 GST_OBJECT_LOCK (encoder);
799 fevt = forced_key_unit_event_new (running_time, all_headers, count);
800 encoder->priv->force_key_unit =
801 g_list_append (encoder->priv->force_key_unit, fevt);
802 GST_OBJECT_UNLOCK (encoder);
804 GST_DEBUG_OBJECT (encoder,
805 "force-key-unit event: running-time %" GST_TIME_FORMAT
806 ", all_headers %d, count %u",
807 GST_TIME_ARGS (running_time), all_headers, count);
809 gst_event_unref (event);
822 gst_video_encoder_sink_event (GstPad * pad, GstEvent * event)
824 GstVideoEncoder *enc;
825 GstVideoEncoderClass *klass;
826 gboolean handled = FALSE;
829 enc = GST_VIDEO_ENCODER (gst_pad_get_parent (pad));
830 klass = GST_VIDEO_ENCODER_GET_CLASS (enc);
832 GST_DEBUG_OBJECT (enc, "received event %d, %s", GST_EVENT_TYPE (event),
833 GST_EVENT_TYPE_NAME (event));
835 if (klass->sink_event)
836 handled = klass->sink_event (enc, event);
839 handled = gst_video_encoder_sink_eventfunc (enc, event);
842 /* Forward non-serialized events and EOS/FLUSH_STOP immediately.
843 * For EOS this is required because no buffer or serialized event
844 * will come after EOS and nothing could trigger another
845 * _finish_frame() call. *
846 * If the subclass handles sending of EOS manually it can return
847 * _DROPPED from ::finish() and all other subclasses should have
848 * decoded/flushed all remaining data before this
850 * For FLUSH_STOP this is required because it is expected
851 * to be forwarded immediately and no buffers are queued anyway.
853 if (!GST_EVENT_IS_SERIALIZED (event)
854 || GST_EVENT_TYPE (event) == GST_EVENT_EOS
855 || GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
856 ret = gst_video_encoder_push_event (enc, event);
858 GST_VIDEO_ENCODER_STREAM_LOCK (enc);
859 enc->priv->current_frame_events =
860 g_list_prepend (enc->priv->current_frame_events, event);
861 GST_VIDEO_ENCODER_STREAM_UNLOCK (enc);
865 GST_DEBUG_OBJECT (enc, "event handled");
867 gst_object_unref (enc);
872 gst_video_encoder_src_eventfunc (GstVideoEncoder * encoder, GstEvent * event)
874 gboolean handled = FALSE;
876 switch (GST_EVENT_TYPE (event)) {
877 case GST_EVENT_CUSTOM_UPSTREAM:
879 if (gst_video_event_is_force_key_unit (event)) {
880 GstClockTime running_time;
881 gboolean all_headers;
884 if (gst_video_event_parse_upstream_force_key_unit (event,
885 &running_time, &all_headers, &count)) {
886 ForcedKeyUnitEvent *fevt;
888 GST_OBJECT_LOCK (encoder);
889 fevt = forced_key_unit_event_new (running_time, all_headers, count);
890 encoder->priv->force_key_unit =
891 g_list_append (encoder->priv->force_key_unit, fevt);
892 GST_OBJECT_UNLOCK (encoder);
894 GST_DEBUG_OBJECT (encoder,
895 "force-key-unit event: running-time %" GST_TIME_FORMAT
896 ", all_headers %d, count %u",
897 GST_TIME_ARGS (running_time), all_headers, count);
899 gst_event_unref (event);
912 gst_video_encoder_src_event (GstPad * pad, GstEvent * event)
914 GstVideoEncoder *encoder;
915 GstVideoEncoderClass *klass;
916 gboolean ret = FALSE;
917 gboolean handled = FALSE;
919 encoder = GST_VIDEO_ENCODER (gst_pad_get_parent (pad));
920 klass = GST_VIDEO_ENCODER_GET_CLASS (encoder);
922 GST_LOG_OBJECT (encoder, "handling event: %" GST_PTR_FORMAT, event);
924 if (klass->src_event)
925 handled = klass->src_event (encoder, event);
928 handled = gst_video_encoder_src_eventfunc (encoder, event);
931 ret = gst_pad_event_default (pad, event);
933 gst_object_unref (encoder);
938 static const GstQueryType *
939 gst_video_encoder_get_query_types (GstPad * pad)
941 static const GstQueryType query_types[] = {
951 gst_video_encoder_src_query (GstPad * pad, GstQuery * query)
953 GstVideoEncoderPrivate *priv;
954 GstVideoEncoder *enc;
958 enc = GST_VIDEO_ENCODER (gst_pad_get_parent (pad));
960 peerpad = gst_pad_get_peer (enc->sinkpad);
962 GST_LOG_OBJECT (enc, "handling query: %" GST_PTR_FORMAT, query);
964 switch (GST_QUERY_TYPE (query)) {
965 case GST_QUERY_CONVERT:
967 GstFormat src_fmt, dest_fmt;
968 gint64 src_val, dest_val;
970 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
972 gst_video_encoded_video_convert (priv->bytes, priv->time, src_fmt,
973 src_val, &dest_fmt, &dest_val);
976 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
979 case GST_QUERY_LATENCY:
982 GstClockTime min_latency, max_latency;
984 res = gst_pad_query (peerpad, query);
986 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
987 GST_DEBUG_OBJECT (enc, "Peer latency: live %d, min %"
988 GST_TIME_FORMAT " max %" GST_TIME_FORMAT, live,
989 GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
991 GST_OBJECT_LOCK (enc);
992 min_latency += priv->min_latency;
993 if (max_latency != GST_CLOCK_TIME_NONE) {
994 max_latency += priv->max_latency;
996 GST_OBJECT_UNLOCK (enc);
998 gst_query_set_latency (query, live, min_latency, max_latency);
1003 res = gst_pad_query_default (pad, query);
1005 gst_object_unref (peerpad);
1006 gst_object_unref (enc);
1010 GST_DEBUG_OBJECT (enc, "query failed");
1011 gst_object_unref (peerpad);
1012 gst_object_unref (enc);
1016 static GstVideoCodecFrame *
1017 gst_video_encoder_new_frame (GstVideoEncoder * encoder, GstBuffer * buf,
1018 GstClockTime timestamp, GstClockTime duration)
1020 GstVideoEncoderPrivate *priv = encoder->priv;
1021 GstVideoCodecFrame *frame;
1023 frame = g_slice_new0 (GstVideoCodecFrame);
1025 frame->ref_count = 1;
1027 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1028 frame->system_frame_number = priv->system_frame_number;
1029 priv->system_frame_number++;
1031 frame->presentation_frame_number = priv->presentation_frame_number;
1032 priv->presentation_frame_number++;
1033 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1035 frame->events = priv->current_frame_events;
1036 priv->current_frame_events = NULL;
1037 frame->input_buffer = buf;
1038 frame->pts = timestamp;
1039 frame->duration = duration;
1045 static GstFlowReturn
1046 gst_video_encoder_chain (GstPad * pad, GstBuffer * buf)
1048 GstVideoEncoder *encoder;
1049 GstVideoEncoderPrivate *priv;
1050 GstVideoEncoderClass *klass;
1051 GstVideoCodecFrame *frame;
1052 GstFlowReturn ret = GST_FLOW_OK;
1053 gint64 start, stop = GST_CLOCK_TIME_NONE, cstart, cstop;
1055 encoder = GST_VIDEO_ENCODER (gst_pad_get_parent (pad));
1056 priv = encoder->priv;
1057 klass = GST_VIDEO_ENCODER_GET_CLASS (encoder);
1059 g_return_val_if_fail (klass->handle_frame != NULL, GST_FLOW_ERROR);
1061 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1064 if (!GST_PAD_CAPS (pad)) {
1065 ret = GST_FLOW_NOT_NEGOTIATED;
1069 start = GST_BUFFER_TIMESTAMP (buf);
1070 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buf)))
1071 stop = start + GST_BUFFER_DURATION (buf);
1073 GST_LOG_OBJECT (encoder,
1074 "received buffer of size %d with ts %" GST_TIME_FORMAT
1075 ", duration %" GST_TIME_FORMAT, GST_BUFFER_SIZE (buf),
1076 GST_TIME_ARGS (start), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
1079 ret = GST_FLOW_UNEXPECTED;
1083 /* Drop buffers outside of segment */
1084 if (!gst_segment_clip (&encoder->output_segment,
1085 GST_FORMAT_TIME, start, stop, &cstart, &cstop)) {
1086 GST_DEBUG_OBJECT (encoder, "clipping to segment dropped frame");
1087 gst_buffer_unref (buf);
1091 frame = gst_video_encoder_new_frame (encoder, buf, cstart, cstop - cstart);
1093 GST_OBJECT_LOCK (encoder);
1094 if (priv->force_key_unit) {
1095 ForcedKeyUnitEvent *fevt = NULL;
1096 GstClockTime running_time;
1100 gst_segment_to_running_time (&encoder->output_segment, GST_FORMAT_TIME,
1101 GST_BUFFER_TIMESTAMP (buf));
1103 for (l = priv->force_key_unit; l; l = l->next) {
1104 ForcedKeyUnitEvent *tmp = l->data;
1106 /* Skip pending keyunits */
1110 /* Simple case, keyunit ASAP */
1111 if (tmp->running_time == GST_CLOCK_TIME_NONE) {
1116 /* Event for before this frame */
1117 if (tmp->running_time <= running_time) {
1124 GST_DEBUG_OBJECT (encoder,
1125 "Forcing a key unit at running time %" GST_TIME_FORMAT,
1126 GST_TIME_ARGS (running_time));
1127 GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME (frame);
1128 if (fevt->all_headers)
1129 GST_VIDEO_CODEC_FRAME_SET_FORCE_KEYFRAME_HEADERS (frame);
1130 fevt->pending = TRUE;
1133 GST_OBJECT_UNLOCK (encoder);
1135 priv->frames = g_list_append (priv->frames, frame);
1137 /* new data, more finish needed */
1138 priv->drained = FALSE;
1140 GST_LOG_OBJECT (encoder, "passing frame pfn %d to subclass",
1141 frame->presentation_frame_number);
1143 ret = klass->handle_frame (encoder, frame);
1146 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1148 gst_object_unref (encoder);
1153 static GstStateChangeReturn
1154 gst_video_encoder_change_state (GstElement * element, GstStateChange transition)
1156 GstVideoEncoder *encoder;
1157 GstVideoEncoderClass *encoder_class;
1158 GstStateChangeReturn ret;
1160 encoder = GST_VIDEO_ENCODER (element);
1161 encoder_class = GST_VIDEO_ENCODER_GET_CLASS (element);
1163 switch (transition) {
1164 case GST_STATE_CHANGE_NULL_TO_READY:
1165 /* open device/library if needed */
1166 if (encoder_class->open && !encoder_class->open (encoder))
1169 case GST_STATE_CHANGE_READY_TO_PAUSED:
1170 /* Initialize device/library if needed */
1171 if (encoder_class->start && !encoder_class->start (encoder))
1178 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1180 switch (transition) {
1181 case GST_STATE_CHANGE_PAUSED_TO_READY:
1182 gst_video_encoder_reset (encoder);
1183 if (encoder_class->stop && !encoder_class->stop (encoder))
1186 case GST_STATE_CHANGE_READY_TO_NULL:
1187 /* close device/library if needed */
1188 if (encoder_class->close && !encoder_class->close (encoder))
1201 GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, (NULL),
1202 ("Failed to open encoder"));
1203 return GST_STATE_CHANGE_FAILURE;
1208 GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, (NULL),
1209 ("Failed to start encoder"));
1210 return GST_STATE_CHANGE_FAILURE;
1215 GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, (NULL),
1216 ("Failed to stop encoder"));
1217 return GST_STATE_CHANGE_FAILURE;
1222 GST_ELEMENT_ERROR (encoder, LIBRARY, INIT, (NULL),
1223 ("Failed to close encoder"));
1224 return GST_STATE_CHANGE_FAILURE;
1229 gst_video_encoder_set_src_caps (GstVideoEncoder * encoder)
1232 GstVideoCodecState *state = encoder->priv->output_state;
1233 GstVideoInfo *info = &state->info;
1235 g_return_val_if_fail (state->caps != NULL, FALSE);
1237 if (encoder->priv->output_state_changed) {
1238 state->caps = gst_caps_make_writable (state->caps);
1241 gst_caps_set_simple (state->caps, "width", G_TYPE_INT, info->width,
1242 "height", G_TYPE_INT, info->height,
1243 "pixel-aspect-ratio", GST_TYPE_FRACTION,
1244 info->par_n, info->par_d, NULL);
1245 if (info->flags & GST_VIDEO_FLAG_VARIABLE_FPS && info->fps_n != 0) {
1246 /* variable fps with a max-framerate */
1247 gst_caps_set_simple (state->caps, "framerate", GST_TYPE_FRACTION, 0, 1,
1248 "max-framerate", GST_TYPE_FRACTION, info->fps_n, info->fps_d, NULL);
1250 /* no variable fps or no max-framerate */
1251 gst_caps_set_simple (state->caps, "framerate", GST_TYPE_FRACTION,
1252 info->fps_n, info->fps_d, NULL);
1254 if (state->codec_data)
1255 gst_caps_set_simple (state->caps, "codec_data", GST_TYPE_BUFFER,
1256 state->codec_data, NULL);
1257 encoder->priv->output_state_changed = FALSE;
1260 ret = gst_pad_set_caps (encoder->srcpad, state->caps);
1266 * gst_video_encoder_finish_frame:
1267 * @encoder: a #GstVideoEncoder
1268 * @frame: (transfer full): an encoded #GstVideoCodecFrame
1270 * @frame must have a valid encoded data buffer, whose metadata fields
1271 * are then appropriately set according to frame data or no buffer at
1272 * all if the frame should be dropped.
1273 * It is subsequently pushed downstream or provided to @pre_push.
1274 * In any case, the frame is considered finished and released.
1276 * Returns: a #GstFlowReturn resulting from sending data downstream
1281 gst_video_encoder_finish_frame (GstVideoEncoder * encoder,
1282 GstVideoCodecFrame * frame)
1284 GstVideoEncoderPrivate *priv = encoder->priv;
1285 GstFlowReturn ret = GST_FLOW_OK;
1286 GstVideoEncoderClass *encoder_class;
1288 gboolean send_headers = FALSE;
1289 gboolean discont = (frame->presentation_frame_number == 0);
1291 encoder_class = GST_VIDEO_ENCODER_GET_CLASS (encoder);
1293 GST_LOG_OBJECT (encoder,
1294 "finish frame fpn %d", frame->presentation_frame_number);
1296 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1298 if (G_UNLIKELY (priv->output_state_changed))
1299 gst_video_encoder_set_src_caps (encoder);
1301 if (G_UNLIKELY (priv->output_state == NULL))
1302 goto no_output_state;
1304 /* Push all pending events that arrived before this frame */
1305 for (l = priv->frames; l; l = l->next) {
1306 GstVideoCodecFrame *tmp = l->data;
1311 for (k = g_list_last (tmp->events); k; k = k->prev)
1312 gst_video_encoder_push_event (encoder, k->data);
1313 g_list_free (tmp->events);
1321 /* no buffer data means this frame is skipped/dropped */
1322 if (!frame->output_buffer) {
1323 GST_DEBUG_OBJECT (encoder, "skipping frame %" GST_TIME_FORMAT,
1324 GST_TIME_ARGS (frame->pts));
1328 if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame) && priv->force_key_unit) {
1329 GstClockTime stream_time, running_time;
1331 ForcedKeyUnitEvent *fevt = NULL;
1335 gst_segment_to_running_time (&encoder->output_segment, GST_FORMAT_TIME,
1338 GST_OBJECT_LOCK (encoder);
1339 for (l = priv->force_key_unit; l; l = l->next) {
1340 ForcedKeyUnitEvent *tmp = l->data;
1342 /* Skip non-pending keyunits */
1346 /* Simple case, keyunit ASAP */
1347 if (tmp->running_time == GST_CLOCK_TIME_NONE) {
1352 /* Event for before this frame */
1353 if (tmp->running_time <= running_time) {
1360 priv->force_key_unit = g_list_remove (priv->force_key_unit, fevt);
1362 GST_OBJECT_UNLOCK (encoder);
1366 gst_segment_to_stream_time (&encoder->output_segment, GST_FORMAT_TIME,
1369 ev = gst_video_event_new_downstream_force_key_unit
1370 (frame->pts, stream_time, running_time,
1371 fevt->all_headers, fevt->count);
1373 gst_video_encoder_push_event (encoder, ev);
1375 if (fevt->all_headers)
1376 send_headers = TRUE;
1378 GST_DEBUG_OBJECT (encoder,
1379 "Forced key unit: running-time %" GST_TIME_FORMAT
1380 ", all_headers %d, count %u",
1381 GST_TIME_ARGS (running_time), fevt->all_headers, fevt->count);
1382 forced_key_unit_event_free (fevt);
1386 if (GST_VIDEO_CODEC_FRAME_IS_SYNC_POINT (frame)) {
1387 priv->distance_from_sync = 0;
1388 GST_BUFFER_FLAG_UNSET (frame->output_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
1389 /* For keyframes, DTS = PTS */
1390 frame->dts = frame->pts;
1392 GST_BUFFER_FLAG_SET (frame->output_buffer, GST_BUFFER_FLAG_DELTA_UNIT);
1395 frame->distance_from_sync = priv->distance_from_sync;
1396 priv->distance_from_sync++;
1398 GST_BUFFER_TIMESTAMP (frame->output_buffer) = frame->pts;
1399 GST_BUFFER_DURATION (frame->output_buffer) = frame->duration;
1401 /* update rate estimate */
1402 priv->bytes += GST_BUFFER_SIZE (frame->output_buffer);
1403 if (GST_CLOCK_TIME_IS_VALID (frame->duration)) {
1404 priv->time += frame->duration;
1406 /* better none than nothing valid */
1407 priv->time = GST_CLOCK_TIME_NONE;
1410 if (G_UNLIKELY (send_headers || priv->new_headers)) {
1411 GList *tmp, *copy = NULL;
1413 GST_DEBUG_OBJECT (encoder, "Sending headers");
1415 /* First make all buffers metadata-writable */
1416 for (tmp = priv->headers; tmp; tmp = tmp->next) {
1417 GstBuffer *tmpbuf = GST_BUFFER (tmp->data);
1419 copy = g_list_append (copy, gst_buffer_make_metadata_writable (tmpbuf));
1421 g_list_free (priv->headers);
1422 priv->headers = copy;
1424 for (tmp = priv->headers; tmp; tmp = tmp->next) {
1425 GstBuffer *tmpbuf = GST_BUFFER (tmp->data);
1427 gst_buffer_set_caps (tmpbuf, GST_PAD_CAPS (encoder->srcpad));
1428 gst_buffer_ref (tmpbuf);
1429 priv->bytes += GST_BUFFER_SIZE (tmpbuf);
1430 if (G_UNLIKELY (discont)) {
1431 GST_LOG_OBJECT (encoder, "marking discont");
1432 GST_BUFFER_FLAG_SET (tmpbuf, GST_BUFFER_FLAG_DISCONT);
1436 gst_pad_push (encoder->srcpad, tmpbuf);
1438 priv->new_headers = FALSE;
1441 if (G_UNLIKELY (discont)) {
1442 GST_LOG_OBJECT (encoder, "marking discont");
1443 GST_BUFFER_FLAG_SET (frame->output_buffer, GST_BUFFER_FLAG_DISCONT);
1446 gst_buffer_set_caps (GST_BUFFER (frame->output_buffer),
1447 GST_PAD_CAPS (encoder->srcpad));
1449 if (encoder_class->pre_push)
1450 ret = encoder_class->pre_push (encoder, frame);
1452 if (ret == GST_FLOW_OK)
1453 ret = gst_pad_push (encoder->srcpad, frame->output_buffer);
1455 frame->output_buffer = NULL;
1459 priv->frames = g_list_remove (priv->frames, frame);
1461 gst_video_codec_frame_unref (frame);
1463 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1470 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1471 GST_ERROR_OBJECT (encoder, "Output state was not configured");
1472 return GST_FLOW_ERROR;
1477 * gst_video_encoder_get_output_state:
1478 * @encoder: a #GstVideoEncoder
1480 * Get the current #GstVideoCodecState
1482 * Returns: (transfer full): #GstVideoCodecState describing format of video data.
1486 GstVideoCodecState *
1487 gst_video_encoder_get_output_state (GstVideoEncoder * encoder)
1489 GstVideoCodecState *state;
1491 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1492 state = gst_video_codec_state_ref (encoder->priv->output_state);
1493 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1499 * gst_video_encoder_set_output_state:
1500 * @encoder: a #GstVideoEncoder
1501 * @caps: (transfer full): the #GstCaps to use for the output
1502 * @reference: (allow-none) (transfer none): An optional reference @GstVideoCodecState
1504 * Creates a new #GstVideoCodecState with the specified caps as the output state
1506 * Any previously set output state on @decoder will be replaced by the newly
1509 * The specified @caps should not contain any resolution, pixel-aspect-ratio,
1510 * framerate, codec-data, .... Those should be specified instead in the returned
1511 * #GstVideoCodecState.
1513 * If the subclass wishes to copy over existing fields (like pixel aspect ratio,
1514 * or framerate) from an existing #GstVideoCodecState, it can be provided as a
1517 * If the subclass wishes to override some fields from the output state (like
1518 * pixel-aspect-ratio or framerate) it can do so on the returned #GstVideoCodecState.
1520 * The new output state will only take effect (set on pads and buffers) starting
1521 * from the next call to #gst_video_encoder_finish_frame().
1523 * Returns: (transfer full): the newly configured output state.
1527 GstVideoCodecState *
1528 gst_video_encoder_set_output_state (GstVideoEncoder * encoder, GstCaps * caps,
1529 GstVideoCodecState * reference)
1531 GstVideoEncoderPrivate *priv = encoder->priv;
1532 GstVideoCodecState *state;
1534 g_return_val_if_fail (caps != NULL, NULL);
1536 state = _new_output_state (caps, reference);
1538 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1539 if (priv->output_state)
1540 gst_video_codec_state_unref (priv->output_state);
1541 priv->output_state = gst_video_codec_state_ref (state);
1543 priv->output_state_changed = TRUE;
1544 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1550 * gst_video_encoder_set_latency:
1551 * @encoder: a #GstVideoEncoder
1552 * @min_latency: minimum latency
1553 * @max_latency: maximum latency
1555 * Informs baseclass of encoding latency.
1560 gst_video_encoder_set_latency (GstVideoEncoder * encoder,
1561 GstClockTime min_latency, GstClockTime max_latency)
1563 g_return_if_fail (GST_CLOCK_TIME_IS_VALID (min_latency));
1564 g_return_if_fail (max_latency >= min_latency);
1566 GST_OBJECT_LOCK (encoder);
1567 encoder->priv->min_latency = min_latency;
1568 encoder->priv->max_latency = max_latency;
1569 GST_OBJECT_UNLOCK (encoder);
1571 gst_element_post_message (GST_ELEMENT_CAST (encoder),
1572 gst_message_new_latency (GST_OBJECT_CAST (encoder)));
1576 * gst_video_encoder_get_latency:
1577 * @encoder: a #GstVideoEncoder
1578 * @min_latency: (out) (allow-none): the configured minimum latency
1579 * @max_latency: (out) (allow-none): the configured maximum latency
1581 * Returns the configured encoding latency.
1586 gst_video_encoder_get_latency (GstVideoEncoder * encoder,
1587 GstClockTime * min_latency, GstClockTime * max_latency)
1589 GST_OBJECT_LOCK (encoder);
1591 *min_latency = encoder->priv->min_latency;
1593 *max_latency = encoder->priv->max_latency;
1594 GST_OBJECT_UNLOCK (encoder);
1598 * gst_video_encoder_get_oldest_frame:
1599 * @encoder: a #GstVideoEncoder
1601 * Get the oldest unfinished pending #GstVideoCodecFrame
1603 * Returns: oldest unfinished pending #GstVideoCodecFrame
1607 GstVideoCodecFrame *
1608 gst_video_encoder_get_oldest_frame (GstVideoEncoder * encoder)
1612 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1613 g = encoder->priv->frames;
1614 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);
1618 return (GstVideoCodecFrame *) (g->data);
1622 * gst_video_encoder_get_frame:
1623 * @encoder: a #GstVideoEnccoder
1624 * @frame_number: system_frame_number of a frame
1626 * Get a pending unfinished #GstVideoCodecFrame
1628 * Returns: (transfer none): pending unfinished #GstVideoCodecFrame identified by @frame_number.
1632 GstVideoCodecFrame *
1633 gst_video_encoder_get_frame (GstVideoEncoder * encoder, int frame_number)
1636 GstVideoCodecFrame *frame = NULL;
1638 GST_DEBUG_OBJECT (encoder, "frame_number : %d", frame_number);
1640 GST_VIDEO_ENCODER_STREAM_LOCK (encoder);
1641 for (g = encoder->priv->frames; g; g = g->next) {
1642 GstVideoCodecFrame *tmp = g->data;
1644 if (tmp->system_frame_number == frame_number) {
1649 GST_VIDEO_ENCODER_STREAM_UNLOCK (encoder);