summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosep Torra <n770galaxy@gmail.com>2013-03-09 16:54:31 +0100
committerJosep Torra <n770galaxy@gmail.com>2013-03-11 17:09:25 +0100
commite78a20377e75292c78ccdf72430ca8206ed220e8 (patch)
treeb9e2f9b7a0343496b214269d85bd645ec06fcab3
parent39972701baeb0f4284615f637978b6c265bed8b6 (diff)
omxvideodec: Implement a property to control the feeding speedratecontrol
-rw-r--r--omx/gstomxvideodec.c115
-rw-r--r--omx/gstomxvideodec.h8
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