From b2525a3044f7d3b118dfcfbfa4d0ec4a2ca86759 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 20 Jul 2011 09:25:28 +0200 Subject: [PATCH] basevideoencoder: Delay sending of serialized sink events until finish_frame() --- gst-libs/gst/video/gstbasevideoencoder.c | 49 ++++++++++++++++++++++++++++++-- gst-libs/gst/video/gstbasevideoencoder.h | 1 + 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/gst-libs/gst/video/gstbasevideoencoder.c b/gst-libs/gst/video/gstbasevideoencoder.c index 75e7a99..3919f9a 100644 --- a/gst-libs/gst/video/gstbasevideoencoder.c +++ b/gst-libs/gst/video/gstbasevideoencoder.c @@ -188,6 +188,11 @@ gst_base_video_encoder_reset (GstBaseVideoEncoder * base_video_encoder) gst_event_unref (base_video_encoder->force_keyunit_event); base_video_encoder->force_keyunit_event = NULL; } + + g_list_foreach (base_video_encoder->current_frame_events, + (GFunc) gst_event_unref, NULL); + g_list_free (base_video_encoder->current_frame_events); + base_video_encoder->current_frame_events = NULL; } static void @@ -464,8 +469,27 @@ gst_base_video_encoder_sink_event (GstPad * pad, GstEvent * event) if (!handled) handled = gst_base_video_encoder_sink_eventfunc (enc, event); - if (!handled) - ret = gst_pad_event_default (pad, event); + if (!handled) { + /* Forward non-serialized events and EOS/FLUSH_STOP immediately. + * For EOS this is required because no buffer or serialized event + * will come after EOS and nothing could trigger another + * _finish_frame() call. * + * If the subclass handles sending of EOS manually it can return + * _DROPPED from ::finish() and all other subclasses should have + * decoded/flushed all remaining data before this + * + * For FLUSH_STOP this is required because it is expected + * to be forwarded immediately and no buffers are queued anyway. + */ + if (!GST_EVENT_IS_SERIALIZED (event) + || GST_EVENT_TYPE (event) == GST_EVENT_EOS + || GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) { + ret = gst_pad_push_event (enc->base_video_codec.srcpad, event); + } else { + enc->current_frame_events = + g_list_prepend (enc->current_frame_events, event); + } + } GST_DEBUG_OBJECT (enc, "event handled"); @@ -641,6 +665,8 @@ gst_base_video_encoder_chain (GstPad * pad, GstBuffer * buf) frame = gst_base_video_codec_new_frame (GST_BASE_VIDEO_CODEC (base_video_encoder)); + frame->events = base_video_encoder->current_frame_events; + base_video_encoder->current_frame_events = NULL; frame->sink_buffer = buf; frame->presentation_timestamp = GST_BUFFER_TIMESTAMP (buf); frame->presentation_duration = GST_BUFFER_DURATION (buf); @@ -724,6 +750,7 @@ gst_base_video_encoder_finish_frame (GstBaseVideoEncoder * base_video_encoder, { GstFlowReturn ret; GstBaseVideoEncoderClass *base_video_encoder_class; + GList *l; g_return_val_if_fail (frame->src_buffer != NULL, GST_FLOW_ERROR); @@ -798,6 +825,24 @@ gst_base_video_encoder_finish_frame (GstBaseVideoEncoder * base_video_encoder, gst_buffer_set_caps (GST_BUFFER (frame->src_buffer), GST_PAD_CAPS (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder))); + /* Push all pending events that arrived before this frame */ + for (l = base_video_encoder->base_video_codec.frames; l; l = l->next) { + GstVideoFrame *tmp = l->data; + + if (tmp->events) { + GList *k; + + for (k = g_list_last (tmp->events); k; k = k->prev) + gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), + k->data); + g_list_free (tmp->events); + tmp->events = NULL; + } + + if (tmp == frame) + break; + } + if (frame->force_keyframe) { GstClockTime stream_time; GstClockTime running_time; diff --git a/gst-libs/gst/video/gstbasevideoencoder.h b/gst-libs/gst/video/gstbasevideoencoder.h index 1286577..e1dd03b 100644 --- a/gst-libs/gst/video/gstbasevideoencoder.h +++ b/gst-libs/gst/video/gstbasevideoencoder.h @@ -96,6 +96,7 @@ struct _GstBaseVideoEncoder gint64 max_latency; GstEvent *force_keyunit_event; + GList *current_frame_events; union { void *padding; -- 2.7.4