summaryrefslogtreecommitdiffstats
path: root/gst/shapewipe/gstshapewipe.c
diff options
context:
space:
mode:
authorDave Robillard <dave@drobilla.net>2009-06-19 21:01:54 -0400
committerDave Robillard <dave@drobilla.net>2009-06-19 21:01:54 -0400
commit925e83ee60c5406b2e5f0f39b0da0f90370efc27 (patch)
treece01d298ed0c5d31853fa43aedc2af0779417816 /gst/shapewipe/gstshapewipe.c
parent7f3bcd484b465d8216ac419754450adf07e9b0d2 (diff)
parentc70dbe94b5ff9a0993d852605d40c21020c59552 (diff)
downloadgst-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.c204
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, &timestamp);
+
+ gst_shape_wipe_update_qos (self, proportion, diff, timestamp);
+ }
+ /* fall through */
default:
ret = gst_pad_push_event (self->video_sinkpad, event);
break;