diff options
-rw-r--r-- | omx/gstomxvideodec.c | 115 | ||||
-rw-r--r-- | omx/gstomxvideodec.h | 8 |
2 files changed, 122 insertions, 1 deletions
diff --git a/omx/gstomxvideodec.c b/omx/gstomxvideodec.c index 19cf4d7..ed7e090 100644 --- a/omx/gstomxvideodec.c +++ b/omx/gstomxvideodec.c @@ -43,6 +43,11 @@ buffer_identification_free (BufferIdentification * id) } /* prototypes */ +static void gst_omx_video_dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_omx_video_dec_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + static void gst_omx_video_dec_finalize (GObject * object); static GstStateChangeReturn @@ -71,7 +76,8 @@ static OMX_ERRORTYPE gst_omx_video_dec_deallocate_output_buffers (GstOMXVideoDec enum { - PROP_0 + PROP_0, + PROP_RATECTRL }; /* class initialization */ @@ -95,6 +101,14 @@ gst_omx_video_dec_class_init (GstOMXVideoDecClass * klass) GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstVideoDecoderClass *video_decoder_class = GST_VIDEO_DECODER_CLASS (klass); + gobject_class->set_property = gst_omx_video_dec_set_property; + gobject_class->get_property = gst_omx_video_dec_get_property; + + g_object_class_install_property (gobject_class, PROP_RATECTRL, + g_param_spec_int ("rate-control", "Rate control", + "Number of frames ahead feeded to decoder (0 unlimited)", 0, 1000, 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gobject_class->finalize = gst_omx_video_dec_finalize; element_class->change_state = @@ -123,6 +137,9 @@ gst_omx_video_dec_init (GstOMXVideoDec * self, GstOMXVideoDecClass * klass) self->drain_lock = g_mutex_new (); self->drain_cond = g_cond_new (); + + self->ratectrl_lock = g_mutex_new (); + self->ratectrl_cond = g_cond_new (); } static gboolean @@ -237,6 +254,9 @@ gst_omx_video_dec_finalize (GObject * object) g_mutex_free (self->drain_lock); g_cond_free (self->drain_cond); + g_mutex_free (self->ratectrl_lock); + g_cond_free (self->ratectrl_cond); + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -270,6 +290,13 @@ gst_omx_video_dec_change_state (GstElement * element, GstStateChange transition) self->draining = FALSE; g_cond_broadcast (self->drain_cond); g_mutex_unlock (self->drain_lock); + + g_mutex_lock (self->ratectrl_lock); + self->frames_in_decoding = 0; + self->output_started = FALSE; + g_cond_broadcast (self->ratectrl_cond); + g_mutex_unlock (self->ratectrl_lock); + break; default: break; @@ -798,6 +825,8 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) buf->omx_buf->nFlags, buf->omx_buf->nTimeStamp); GST_VIDEO_DECODER_STREAM_LOCK (self); + + frame = _find_nearest_frame (self, buf); is_eos = ! !(buf->omx_buf->nFlags & OMX_BUFFERFLAG_EOS); @@ -856,6 +885,23 @@ gst_omx_video_dec_loop (GstOMXVideoDec * self) GST_DEBUG_OBJECT (self, "Read frame from component"); + /* Wakeup the feeder */ + if (self->ratectrl) { + g_mutex_lock (self->ratectrl_lock); + if (self->output_started) { + self->frames_in_decoding--; + self->frames_in_decoding = MAX (0, self->frames_in_decoding); + if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) { + self->frames_in_decoding = 0; + self->output_started = FALSE; + } + g_cond_broadcast (self->ratectrl_cond); + } else { + self->output_started = TRUE; + } + g_mutex_unlock (self->ratectrl_lock); + } + if (is_eos || flow_ret == GST_FLOW_UNEXPECTED) { g_mutex_lock (self->drain_lock); if (self->draining) { @@ -1023,6 +1069,12 @@ gst_omx_video_dec_stop (GstVideoDecoder * decoder) g_cond_broadcast (self->drain_cond); g_mutex_unlock (self->drain_lock); + g_mutex_lock (self->ratectrl_lock); + self->frames_in_decoding = 0; + self->output_started = FALSE; + g_cond_broadcast (self->ratectrl_cond); + g_mutex_unlock (self->ratectrl_lock); + gst_omx_component_get_state (self->dec, 5 * GST_SECOND); gst_buffer_replace (&self->codec_data, NULL); @@ -1275,6 +1327,12 @@ gst_omx_video_dec_set_format (GstVideoDecoder * decoder, gst_pad_stop_task (GST_VIDEO_DECODER_SRC_PAD (decoder)); GST_VIDEO_DECODER_STREAM_LOCK (self); + if (self->ratectrl) { + /* Reset rate control state */ + self->frames_in_decoding = 0; + self->output_started = FALSE; + } + if (klass->cdata.hacks & GST_OMX_HACK_NO_COMPONENT_RECONFIGURE) { GST_VIDEO_DECODER_STREAM_UNLOCK (self); gst_omx_video_dec_stop (GST_VIDEO_DECODER (self)); @@ -1655,6 +1713,21 @@ gst_omx_video_dec_handle_frame (GstVideoDecoder * decoder, GST_DEBUG_OBJECT (self, "Passed frame to component"); + /* Control the speed at which decoder is feeded */ + if (self->ratectrl && self->downstream_flow_ret == GST_FLOW_OK && + self->output_started) { + g_mutex_lock (self->ratectrl_lock); + if ((self->frames_in_decoding++) >= self->ratectrl) { + /* Make sure to release the base class stream lock, otherwise + * _loop() can't call _finish_frame() and we might block forever */ + GST_VIDEO_DECODER_STREAM_UNLOCK (self); + /* Wait for a decoded frame or flush */ + g_cond_wait (self->ratectrl_cond, self->ratectrl_lock); + GST_VIDEO_DECODER_STREAM_LOCK (self); + } + g_mutex_unlock (self->ratectrl_lock); + } + return self->downstream_flow_ret; full_buffer: @@ -1814,3 +1887,43 @@ gst_omx_video_dec_drain (GstOMXVideoDec * self, gboolean is_eos) return GST_FLOW_OK; } + +static void +gst_omx_video_dec_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOMXVideoDec *self; + + g_return_if_fail (GST_IS_OMX_VIDEO_DEC (object)); + + self = GST_OMX_VIDEO_DEC (object); + + switch (prop_id) { + case PROP_RATECTRL: + self->ratectrl = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_omx_video_dec_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOMXVideoDec *self; + + g_return_if_fail (GST_IS_OMX_VIDEO_DEC (object)); + + self = GST_OMX_VIDEO_DEC (object); + + switch (prop_id) { + case PROP_RATECTRL: + g_value_set_int (value, self->ratectrl); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/omx/gstomxvideodec.h b/omx/gstomxvideodec.h index 6ae9453..3079843 100644 --- a/omx/gstomxvideodec.h +++ b/omx/gstomxvideodec.h @@ -80,6 +80,14 @@ struct _GstOMXVideoDec gboolean eos; GstFlowReturn downstream_flow_ret; + + /* Rate control state */ + gint ratectrl; + gint frames_in_decoding; + GMutex *ratectrl_lock; + GCond *ratectrl_cond; + gboolean output_started; + }; struct _GstOMXVideoDecClass |