diff options
author | Dave Robillard <dave@drobilla.net> | 2009-06-19 21:01:54 -0400 |
---|---|---|
committer | Dave Robillard <dave@drobilla.net> | 2009-06-19 21:01:54 -0400 |
commit | 925e83ee60c5406b2e5f0f39b0da0f90370efc27 (patch) | |
tree | ce01d298ed0c5d31853fa43aedc2af0779417816 /gst/shapewipe/gstshapewipe.c | |
parent | 7f3bcd484b465d8216ac419754450adf07e9b0d2 (diff) | |
parent | c70dbe94b5ff9a0993d852605d40c21020c59552 (diff) | |
download | gst-plugins-bad-925e83ee60c5406b2e5f0f39b0da0f90370efc27.tar.gz gst-plugins-bad-925e83ee60c5406b2e5f0f39b0da0f90370efc27.tar.bz2 gst-plugins-bad-925e83ee60c5406b2e5f0f39b0da0f90370efc27.zip |
Merge branch 'master' of git://anongit.freedesktop.org/gstreamer/gst-plugins-bad into fdo
Diffstat (limited to 'gst/shapewipe/gstshapewipe.c')
-rw-r--r-- | gst/shapewipe/gstshapewipe.c | 204 |
1 files changed, 197 insertions, 7 deletions
diff --git a/gst/shapewipe/gstshapewipe.c b/gst/shapewipe/gstshapewipe.c index c2c4ce2b..95218801 100644 --- a/gst/shapewipe/gstshapewipe.c +++ b/gst/shapewipe/gstshapewipe.c @@ -56,6 +56,11 @@ static void gst_shape_wipe_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_shape_wipe_reset (GstShapeWipe * self); +static void gst_shape_wipe_update_qos (GstShapeWipe * self, gdouble proportion, + GstClockTimeDiff diff, GstClockTime time); +static void gst_shape_wipe_reset_qos (GstShapeWipe * self); +static void gst_shape_wipe_read_qos (GstShapeWipe * self, gdouble * proportion, + GstClockTime * time); static GstStateChangeReturn gst_shape_wipe_change_state (GstElement * element, GstStateChange transition); @@ -67,6 +72,10 @@ static gboolean gst_shape_wipe_video_sink_event (GstPad * pad, static gboolean gst_shape_wipe_video_sink_setcaps (GstPad * pad, GstCaps * caps); static GstCaps *gst_shape_wipe_video_sink_getcaps (GstPad * pad); +static GstFlowReturn gst_shape_wipe_video_sink_bufferalloc (GstPad * pad, + guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf); +static gboolean gst_shape_wipe_video_sink_query (GstPad * pad, + GstQuery * query); static GstFlowReturn gst_shape_wipe_mask_sink_chain (GstPad * pad, GstBuffer * buffer); static gboolean gst_shape_wipe_mask_sink_event (GstPad * pad, GstEvent * event); @@ -74,6 +83,7 @@ static gboolean gst_shape_wipe_mask_sink_setcaps (GstPad * pad, GstCaps * caps); static GstCaps *gst_shape_wipe_mask_sink_getcaps (GstPad * pad); static gboolean gst_shape_wipe_src_event (GstPad * pad, GstEvent * event); static GstCaps *gst_shape_wipe_src_getcaps (GstPad * pad); +static gboolean gst_shape_wipe_src_query (GstPad * pad, GstQuery * query); enum { @@ -165,6 +175,10 @@ gst_shape_wipe_init (GstShapeWipe * self, GstShapeWipeClass * g_class) GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_setcaps)); gst_pad_set_getcaps_function (self->video_sinkpad, GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_getcaps)); + gst_pad_set_bufferalloc_function (self->video_sinkpad, + GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_bufferalloc)); + gst_pad_set_query_function (self->video_sinkpad, + GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_query)); gst_element_add_pad (GST_ELEMENT (self), self->video_sinkpad); self->mask_sinkpad = @@ -184,6 +198,8 @@ gst_shape_wipe_init (GstShapeWipe * self, GstShapeWipeClass * g_class) GST_DEBUG_FUNCPTR (gst_shape_wipe_src_event)); gst_pad_set_getcaps_function (self->srcpad, GST_DEBUG_FUNCPTR (gst_shape_wipe_src_getcaps)); + gst_pad_set_query_function (self->srcpad, + GST_DEBUG_FUNCPTR (gst_shape_wipe_src_query)); gst_element_add_pad (GST_ELEMENT (self), self->srcpad); self->mask_mutex = g_mutex_new (); @@ -263,6 +279,28 @@ gst_shape_wipe_reset (GstShapeWipe * self) self->mask_bpp = 0; gst_segment_init (&self->segment, GST_FORMAT_TIME); + + gst_shape_wipe_reset_qos (self); + self->frame_duration = 0; +} + +static GstFlowReturn +gst_shape_wipe_video_sink_bufferalloc (GstPad * pad, guint64 offset, guint size, + GstCaps * caps, GstBuffer ** buf) +{ + GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad)); + GstFlowReturn ret = GST_FLOW_OK; + + GST_DEBUG_OBJECT (pad, "Allocating buffer with offset 0x%" G_GINT64_MODIFIER + "x and size %u with caps: %" GST_PTR_FORMAT, offset, size, caps); + + *buf = NULL; + + ret = gst_pad_alloc_buffer (self->srcpad, offset, size, caps, buf); + + gst_object_unref (self); + + return ret; } static gboolean @@ -272,13 +310,15 @@ gst_shape_wipe_video_sink_setcaps (GstPad * pad, GstCaps * caps) gboolean ret = TRUE; GstStructure *s; gint width, height; + gint fps_n, fps_d; GST_DEBUG_OBJECT (pad, "Setting caps: %" GST_PTR_FORMAT, caps); s = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (s, "width", &width) || - !gst_structure_get_int (s, "height", &height)) { + !gst_structure_get_int (s, "height", &height) || + !gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d)) { ret = FALSE; goto done; } @@ -294,6 +334,8 @@ gst_shape_wipe_video_sink_setcaps (GstPad * pad, GstCaps * caps) g_mutex_unlock (self->mask_mutex); } + self->frame_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n); + ret = gst_pad_set_caps (self->srcpad, caps); done: @@ -567,6 +609,123 @@ gst_shape_wipe_src_getcaps (GstPad * pad) return ret; } +static gboolean +gst_shape_wipe_video_sink_query (GstPad * pad, GstQuery * query) +{ + GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad)); + gboolean ret; + GstPad *peer = gst_pad_get_peer (self->srcpad); + + GST_DEBUG_OBJECT (pad, "Handling query of type '%s'", + gst_query_type_get_name (GST_QUERY_TYPE (query))); + + if (!peer) { + GST_INFO_OBJECT (pad, "No peer yet"); + ret = FALSE; + } else { + ret = gst_pad_query (peer, query); + gst_object_unref (peer); + } + + gst_object_unref (self); + return ret; +} + +static gboolean +gst_shape_wipe_src_query (GstPad * pad, GstQuery * query) +{ + GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad)); + gboolean ret; + GstPad *peer = gst_pad_get_peer (self->video_sinkpad); + + GST_DEBUG_OBJECT (pad, "Handling query of type '%s'", + gst_query_type_get_name (GST_QUERY_TYPE (query))); + + if (!peer) { + GST_INFO_OBJECT (pad, "No peer yet"); + ret = FALSE; + } else { + ret = gst_pad_query (peer, query); + gst_object_unref (peer); + } + + gst_object_unref (self); + return ret; +} + +static void +gst_shape_wipe_update_qos (GstShapeWipe * self, gdouble proportion, + GstClockTimeDiff diff, GstClockTime timestamp) +{ + GST_OBJECT_LOCK (self); + self->proportion = proportion; + if (G_LIKELY (timestamp != GST_CLOCK_TIME_NONE)) { + if (G_UNLIKELY (diff > 0)) + self->earliest_time = timestamp + 2 * diff + self->frame_duration; + else + self->earliest_time = timestamp + diff; + } else { + self->earliest_time = GST_CLOCK_TIME_NONE; + } + GST_OBJECT_UNLOCK (self); +} + +static void +gst_shape_wipe_reset_qos (GstShapeWipe * self) +{ + gst_shape_wipe_update_qos (self, 0.5, 0, GST_CLOCK_TIME_NONE); +} + +static void +gst_shape_wipe_read_qos (GstShapeWipe * self, gdouble * proportion, + GstClockTime * time) +{ + GST_OBJECT_LOCK (self); + *proportion = self->proportion; + *time = self->earliest_time; + GST_OBJECT_UNLOCK (self); +} + +/* Perform qos calculations before processing the next frame. Returns TRUE if + * the frame should be processed, FALSE if the frame can be dropped entirely */ +static gboolean +gst_shape_wipe_do_qos (GstShapeWipe * self, GstClockTime timestamp) +{ + GstClockTime qostime, earliest_time; + gdouble proportion; + + /* no timestamp, can't do QoS => process frame */ + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp))) { + GST_LOG_OBJECT (self, "invalid timestamp, can't do QoS, process frame"); + return TRUE; + } + + /* get latest QoS observation values */ + gst_shape_wipe_read_qos (self, &proportion, &earliest_time); + + /* skip qos if we have no observation (yet) => process frame */ + if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (earliest_time))) { + GST_LOG_OBJECT (self, "no observation yet, process frame"); + return TRUE; + } + + /* qos is done on running time */ + qostime = gst_segment_to_running_time (&self->segment, GST_FORMAT_TIME, + timestamp); + + /* see how our next timestamp relates to the latest qos timestamp */ + GST_LOG_OBJECT (self, "qostime %" GST_TIME_FORMAT ", earliest %" + GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time)); + + if (qostime != GST_CLOCK_TIME_NONE && qostime <= earliest_time) { + GST_DEBUG_OBJECT (self, "we are late, drop frame"); + return FALSE; + } + + GST_LOG_OBJECT (self, "process frame"); + return TRUE; +} + static GstFlowReturn gst_shape_wipe_blend_16 (GstShapeWipe * self, GstBuffer * inbuf, GstBuffer * maskbuf, GstBuffer * outbuf) @@ -686,6 +845,7 @@ gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer) GstFlowReturn ret = GST_FLOW_OK; GstBuffer *mask = NULL, *outbuf = NULL; GstClockTime timestamp; + gboolean new_outbuf = FALSE; timestamp = GST_BUFFER_TIMESTAMP (buffer); timestamp = @@ -711,13 +871,28 @@ gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer) } g_mutex_unlock (self->mask_mutex); - ret = - gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, - GST_BUFFER_SIZE (buffer), GST_PAD_CAPS (self->srcpad), &outbuf); - if (G_UNLIKELY (ret != GST_FLOW_OK)) { + if (!gst_shape_wipe_do_qos (self, GST_BUFFER_TIMESTAMP (buffer))) { gst_buffer_unref (buffer); gst_buffer_unref (mask); - return ret; + return GST_FLOW_OK; + } + + /* Try to blend inplace, if it's not possible + * get a new buffer from downstream. + */ + if (!gst_buffer_is_writable (buffer)) { + ret = + gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE, + GST_BUFFER_SIZE (buffer), GST_PAD_CAPS (self->srcpad), &outbuf); + if (G_UNLIKELY (ret != GST_FLOW_OK)) { + gst_buffer_unref (buffer); + gst_buffer_unref (mask); + return ret; + } + gst_buffer_copy_metadata (outbuf, buffer, GST_BUFFER_COPY_ALL); + new_outbuf = TRUE; + } else { + outbuf = buffer; } if (self->mask_bpp == 16) @@ -726,7 +901,9 @@ gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer) ret = gst_shape_wipe_blend_8 (self, buffer, mask, outbuf); gst_buffer_unref (mask); - gst_buffer_unref (buffer); + if (new_outbuf) + gst_buffer_unref (buffer); + if (ret != GST_FLOW_OK) { gst_buffer_unref (outbuf); return ret; @@ -813,6 +990,9 @@ gst_shape_wipe_video_sink_event (GstPad * pad, GstEvent * event) } } /* fall through */ + case GST_EVENT_FLUSH_STOP: + gst_shape_wipe_reset_qos (self); + /* fall through */ default: ret = gst_pad_push_event (self->srcpad, event); break; @@ -839,6 +1019,16 @@ gst_shape_wipe_src_event (GstPad * pad, GstEvent * event) gboolean ret; switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_QOS:{ + GstClockTimeDiff diff; + GstClockTime timestamp; + gdouble proportion; + + gst_event_parse_qos (event, &proportion, &diff, ×tamp); + + gst_shape_wipe_update_qos (self, proportion, diff, timestamp); + } + /* fall through */ default: ret = gst_pad_push_event (self->video_sinkpad, event); break; |