From 3cb4bbe97e434334af834c1c9ef90177ce6b1f12 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Tue, 29 Nov 2011 12:12:04 +0100 Subject: [PATCH] basevideoencoder: Implement full support for the new force-key-unit event Including support for the running-time and count fields. --- omx/gstbasevideoencoder.c | 190 ++++++++++++++++++++++++++++++++++++---------- omx/gstbasevideoencoder.h | 5 +- 2 files changed, 153 insertions(+), 42 deletions(-) diff --git a/omx/gstbasevideoencoder.c b/omx/gstbasevideoencoder.c index 97d0e17..45a1daa 100644 --- a/omx/gstbasevideoencoder.c +++ b/omx/gstbasevideoencoder.c @@ -113,6 +113,34 @@ GST_DEBUG_CATEGORY (basevideoencoder_debug); #define GST_CAT_DEFAULT basevideoencoder_debug +typedef struct _ForcedKeyUnitEvent ForcedKeyUnitEvent; +struct _ForcedKeyUnitEvent +{ + GstClockTime running_time; + gboolean pending; /* TRUE if this was requested already */ + gboolean all_headers; + guint count; +}; + +static void +forced_key_unit_event_free (ForcedKeyUnitEvent * evt) +{ + g_slice_free (ForcedKeyUnitEvent, evt); +} + +static ForcedKeyUnitEvent * +forced_key_unit_event_new (GstClockTime running_time, gboolean all_headers, + guint count) +{ + ForcedKeyUnitEvent *evt = g_slice_new0 (ForcedKeyUnitEvent); + + evt->running_time = running_time; + evt->all_headers = all_headers; + evt->count = count; + + return evt; +} + static void gst_base_video_encoder_finalize (GObject * object); static gboolean gst_base_video_encoder_sink_setcaps (GstPad * pad, @@ -131,7 +159,6 @@ static const GstQueryType *gst_base_video_encoder_get_query_types (GstPad * static gboolean gst_base_video_encoder_src_query (GstPad * pad, GstQuery * query); - static void _do_init (GType object_type) { @@ -178,8 +205,11 @@ gst_base_video_encoder_reset (GstBaseVideoEncoder * base_video_encoder) base_video_encoder->presentation_frame_number = 0; base_video_encoder->distance_from_sync = 0; - base_video_encoder->force_keyframe = FALSE; - base_video_encoder->force_keyframe_pending = FALSE; + + g_list_foreach (base_video_encoder->force_key_unit, + (GFunc) forced_key_unit_event_free, NULL); + g_list_free (base_video_encoder->force_key_unit); + base_video_encoder->force_key_unit = NULL; base_video_encoder->drained = TRUE; base_video_encoder->min_latency = 0; @@ -521,16 +551,25 @@ gst_base_video_encoder_sink_eventfunc (GstBaseVideoEncoder * base_video_encoder, case GST_EVENT_CUSTOM_DOWNSTREAM: { if (gst_video_event_is_force_key_unit (event)) { - GST_OBJECT_LOCK (base_video_encoder); - - base_video_encoder->force_keyframe = TRUE; - gst_video_event_parse_downstream_force_key_unit (event, NULL, NULL, - NULL, &base_video_encoder->force_keyframe_headers, NULL); - - GST_DEBUG_OBJECT (base_video_encoder, - "force-keyunit event, all-headers %d", - base_video_encoder->force_keyframe_headers); - GST_OBJECT_UNLOCK (base_video_encoder); + GstClockTime running_time; + gboolean all_headers; + guint count; + + if (gst_video_event_parse_downstream_force_key_unit (event, + NULL, NULL, &running_time, &all_headers, &count)) { + ForcedKeyUnitEvent *fevt; + + GST_OBJECT_LOCK (base_video_encoder); + fevt = forced_key_unit_event_new (running_time, all_headers, count); + base_video_encoder->force_key_unit = + g_list_append (base_video_encoder->force_key_unit, fevt); + GST_OBJECT_UNLOCK (base_video_encoder); + + GST_DEBUG_OBJECT (base_video_encoder, + "force-key-unit event: running-time %" GST_TIME_FORMAT + ", all_headers %d, count %u", + GST_TIME_ARGS (running_time), all_headers, count); + } gst_event_unref (event); ret = TRUE; } @@ -608,16 +647,26 @@ gst_base_video_encoder_src_event (GstPad * pad, GstEvent * event) case GST_EVENT_CUSTOM_UPSTREAM: { if (gst_video_event_is_force_key_unit (event)) { - GST_OBJECT_LOCK (base_video_encoder); - base_video_encoder->force_keyframe = TRUE; - gst_video_event_parse_upstream_force_key_unit (event, NULL, - &base_video_encoder->force_keyframe_headers, NULL); - GST_OBJECT_UNLOCK (base_video_encoder); - + GstClockTime running_time; + gboolean all_headers; + guint count; + + if (gst_video_event_parse_upstream_force_key_unit (event, + &running_time, &all_headers, &count)) { + ForcedKeyUnitEvent *fevt; + + GST_OBJECT_LOCK (base_video_encoder); + fevt = forced_key_unit_event_new (running_time, all_headers, count); + base_video_encoder->force_key_unit = + g_list_append (base_video_encoder->force_key_unit, fevt); + GST_OBJECT_UNLOCK (base_video_encoder); + + GST_DEBUG_OBJECT (base_video_encoder, + "force-key-unit event: running-time %" GST_TIME_FORMAT + ", all_headers %d, count %u", + GST_TIME_ARGS (running_time), all_headers, count); + } gst_event_unref (event); - GST_DEBUG_OBJECT (base_video_encoder, - "force-keyunit event, all-headers %d", - base_video_encoder->force_keyframe_headers); ret = TRUE; } else { ret = @@ -774,9 +823,46 @@ gst_base_video_encoder_chain (GstPad * pad, GstBuffer * buf) frame->presentation_frame_number = base_video_encoder->presentation_frame_number; base_video_encoder->presentation_frame_number++; - frame->force_keyframe = base_video_encoder->force_keyframe; - base_video_encoder->force_keyframe = FALSE; - base_video_encoder->force_keyframe_pending = TRUE; + + GST_OBJECT_LOCK (base_video_encoder); + if (base_video_encoder->force_key_unit) { + ForcedKeyUnitEvent *fevt = NULL; + GstClockTime running_time; + GList *l; + + running_time = gst_segment_to_running_time (&GST_BASE_VIDEO_CODEC + (base_video_encoder)->segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (buf)); + + for (l = base_video_encoder->force_key_unit; l; l = l->next) { + ForcedKeyUnitEvent *tmp = l->data; + + /* Skip pending keyunits */ + if (tmp->pending) + continue; + + /* Simple case, keyunit ASAP */ + if (tmp->running_time == GST_CLOCK_TIME_NONE) { + fevt = tmp; + break; + } + + /* Event for before this frame */ + if (tmp->running_time <= running_time) { + fevt = tmp; + break; + } + } + + if (fevt) { + GST_DEBUG_OBJECT (base_video_encoder, + "Forcing a key unit at running time %" GST_TIME_FORMAT, + GST_TIME_ARGS (running_time)); + frame->force_keyframe = TRUE; + fevt->pending = TRUE; + } + } + GST_OBJECT_UNLOCK (base_video_encoder); GST_BASE_VIDEO_CODEC (base_video_encoder)->frames = g_list_append (GST_BASE_VIDEO_CODEC (base_video_encoder)->frames, frame); @@ -890,38 +976,66 @@ gst_base_video_encoder_finish_frame (GstBaseVideoEncoder * base_video_encoder, goto done; } - if (frame->is_sync_point && base_video_encoder->force_keyframe_pending) { - GstClockTime stream_time; - GstClockTime running_time; + if (frame->is_sync_point && base_video_encoder->force_key_unit) { + GstClockTime stream_time, running_time; GstEvent *ev; + ForcedKeyUnitEvent *fevt = NULL; + GList *l; - base_video_encoder->force_keyframe_pending = FALSE; - - running_time = - gst_segment_to_running_time (&GST_BASE_VIDEO_CODEC + running_time = gst_segment_to_running_time (&GST_BASE_VIDEO_CODEC (base_video_encoder)->segment, GST_FORMAT_TIME, frame->presentation_timestamp); + + GST_OBJECT_LOCK (base_video_encoder); + for (l = base_video_encoder->force_key_unit; l; l = l->next) { + ForcedKeyUnitEvent *tmp = l->data; + + /* Skip pending keyunits */ + if (tmp->pending) + continue; + + /* Simple case, keyunit ASAP */ + if (tmp->running_time == GST_CLOCK_TIME_NONE) { + fevt = tmp; + break; + } + + /* Event for before this frame */ + if (tmp->running_time <= running_time) { + fevt = tmp; + break; + } + } + base_video_encoder->force_key_unit = + g_list_remove (base_video_encoder->force_key_unit, fevt); + GST_OBJECT_UNLOCK (base_video_encoder); + + /* Should really be here */ + g_assert (fevt); + stream_time = gst_segment_to_stream_time (&GST_BASE_VIDEO_CODEC (base_video_encoder)->segment, GST_FORMAT_TIME, frame->presentation_timestamp); - /* FIXME: Use the correct count */ ev = gst_video_event_new_downstream_force_key_unit (frame->presentation_timestamp, stream_time, running_time, - base_video_encoder->force_keyframe_headers, 0); + fevt->all_headers, fevt->count); gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_encoder), ev); - if (base_video_encoder->force_keyframe_headers) { - GST_DEBUG_OBJECT (base_video_encoder, "force_keyframe_headers"); + if (fevt->all_headers) { if (base_video_encoder->headers) { headers = gst_buffer_ref (base_video_encoder->headers); headers = gst_buffer_make_writable (headers); } - base_video_encoder->force_keyframe_headers = FALSE; } - GST_LOG_OBJECT (base_video_encoder, "key frame, headers %p", headers); + + GST_DEBUG_OBJECT (base_video_encoder, + "Forced key unit: running-time %" GST_TIME_FORMAT + ", all_headers %d, count %u", + GST_TIME_ARGS (running_time), fevt->all_headers, fevt->count); + forced_key_unit_event_free (fevt); } if (frame->is_sync_point) { diff --git a/omx/gstbasevideoencoder.h b/omx/gstbasevideoencoder.h index 0410fec..de52102 100644 --- a/omx/gstbasevideoencoder.h +++ b/omx/gstbasevideoencoder.h @@ -84,8 +84,6 @@ struct _GstBaseVideoEncoder guint64 presentation_frame_number; int distance_from_sync; - gboolean force_keyframe; - /*< private >*/ /* FIXME move to real private part ? * (and introduce a context ?) */ @@ -99,8 +97,7 @@ struct _GstBaseVideoEncoder GstBuffer *headers; - gboolean force_keyframe_pending; - gboolean force_keyframe_headers; + GList *force_key_unit; /* List of pending forced keyunits */ void *padding[GST_PADDING_LARGE]; }; -- 2.7.4