summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLionel Landwerlin <llandwerlin@gmail.com>2014-05-29 19:47:10 +0100
committerLionel Landwerlin <llandwerlin@gmail.com>2014-06-03 23:47:54 +0100
commit6c23a5fe8d7e2433184f249394e043836ea2f302 (patch)
treeda4e8da677ebe89356abca153232d60ec7906799
parent3c3f0ab8907bf971905c6f6fa2b87887e3b48af9 (diff)
downloadclutter-gst-wip/overlays.tar.gz
untested/uncompiled overlay support starting pointwip/overlays
-rw-r--r--clutter-gst/clutter-gst-aspectratio.c102
-rw-r--r--clutter-gst/clutter-gst-content.c221
-rw-r--r--clutter-gst/clutter-gst-content.h4
-rw-r--r--clutter-gst/clutter-gst-private.h8
-rw-r--r--clutter-gst/clutter-gst-types.c91
-rw-r--r--clutter-gst/clutter-gst-types.h55
-rw-r--r--clutter-gst/clutter-gst-util.c11
-rw-r--r--clutter-gst/clutter-gst-video-sink.c142
-rw-r--r--clutter-gst/clutter-gst-video-sink.h3
9 files changed, 576 insertions, 61 deletions
diff --git a/clutter-gst/clutter-gst-aspectratio.c b/clutter-gst/clutter-gst-aspectratio.c
index 21b3802..f426802 100644
--- a/clutter-gst/clutter-gst-aspectratio.c
+++ b/clutter-gst/clutter-gst-aspectratio.c
@@ -133,6 +133,35 @@ clutter_gst_aspectratio_get_frame_box (ClutterGstAspectratio *self,
}
}
+static void
+clutter_gst_aspectratio_get_overlay_box (ClutterGstAspectratio *self,
+ ClutterGstBox *input_box,
+ ClutterGstBox *paint_box,
+ const ClutterGstBox *frame_input,
+ const ClutterGstBox *frame_box,
+ ClutterGstFrame *frame,
+ ClutterGstOverlay *overlay)
+{
+ gfloat box_width = frame_box->x2 - frame_box->x1,
+ box_height = frame_box->y2 - frame_box->y1;
+
+ /* texturing input */
+ input_box->x1 = (overlay->position.x1 - MAX (frame_input->x1 * frame->resolution.width, overlay->position.x1))
+ / (overlay->position.x2 - overlay->position.x1);
+ input_box->y1 = (overlay->position.y1 - MAX (frame_input->y1 * frame->resolution.height, overlay->position.y1))
+ / (overlay->position.y2 - overlay->position.y1);
+ input_box->x2 = 1 - (overlay->position.x2 - MIN (frame_input->x2 * frame->resolution.width, overlay->position.x2))
+ / (overlay->position.x2 - overlay->position.x1);
+ input_box->y2 = 1 - (overlay->position.y2 - MIN (frame_input->y2 * frame->resolution.height, overlay->position.y2))
+ / (overlay->position.y2 - overlay->position.y1);
+
+ /* vertex output */
+ paint_box->x1 = frame_box->x1 + overlay->position.x1 * box_width / frame->resolution.width;
+ paint_box->y1 = frame_box->y1 + overlay->position.y1 * box_height / frame->resolution.height;
+ paint_box->x2 = frame_box->x1 + overlay->position.x2 * box_width / frame->resolution.width;
+ paint_box->y2 = frame_box->y1 + overlay->position.y2 * box_height / frame->resolution.height;
+}
+
/**/
static gboolean
@@ -161,8 +190,8 @@ clutter_gst_aspectratio_paint_content (ClutterContent *content,
{
ClutterGstAspectratio *self = CLUTTER_GST_ASPECTRATIO (content);
ClutterGstAspectratioPrivate *priv = self->priv;
- ClutterGstFrame *frame =
- clutter_gst_content_get_frame (CLUTTER_GST_CONTENT (content));
+ ClutterGstContent *gst_content = CLUTTER_GST_CONTENT (content);
+ ClutterGstFrame *frame = clutter_gst_content_get_frame (gst_content);
ClutterGstBox input_box, paint_box;
ClutterActorBox content_box;
ClutterPaintNode *node;
@@ -228,21 +257,66 @@ clutter_gst_aspectratio_paint_content (ClutterContent *content,
clutter_paint_node_unref (node);
}
- cogl_pipeline_set_color4ub (frame->pipeline,
- paint_opacity, paint_opacity,
- paint_opacity, paint_opacity);
+ if (clutter_gst_content_get_paint_frame (gst_content))
+ {
+ cogl_pipeline_set_color4ub (frame->pipeline,
+ paint_opacity, paint_opacity,
+ paint_opacity, paint_opacity);
+
+ node = clutter_pipeline_node_new (frame->pipeline);
+ clutter_paint_node_set_name (node, "AspectRatioVideoFrame");
- node = clutter_pipeline_node_new (frame->pipeline);
- clutter_paint_node_set_name (node, "AspectRatioVideoFrame");
+ clutter_paint_node_add_texture_rectangle_custom (node,
+ paint_box.x1, paint_box.y1,
+ paint_box.x2, paint_box.y2,
+ input_box.x1, input_box.y1,
+ input_box.x2, input_box.y2);
- clutter_paint_node_add_texture_rectangle_custom (node,
- paint_box.x1, paint_box.y1,
- paint_box.x2, paint_box.y2,
- input_box.x1, input_box.y1,
- input_box.x2, input_box.y2);
+ clutter_paint_node_add_child (root, node);
+ clutter_paint_node_unref (node);
+ }
+
+ if (clutter_gst_content_get_paint_overlays (gst_content))
+ {
+ ClutterGstOverlays *overlays = clutter_gst_content_get_overlays (gst_content);
- clutter_paint_node_add_child (root, node);
- clutter_paint_node_unref (node);
+ if (overlays)
+ {
+ guint i;
+
+ for (i = 0; i < overlays->overlays->len; i++)
+ {
+ ClutterGstOverlay *overlay =
+ g_ptr_array_index (overlays->overlays, i);
+ ClutterGstBox overlay_box;
+ ClutterGstBox overlay_input_box;
+
+ clutter_gst_aspectratio_get_overlay_box (self,
+ &overlay_input_box,
+ &overlay_box,
+ &input_box,
+ &paint_box,
+ frame,
+ overlay);
+
+ cogl_pipeline_set_color4ub (overlay->pipeline,
+ paint_opacity, paint_opacity,
+ paint_opacity, paint_opacity);
+
+ node = clutter_pipeline_node_new (overlay->pipeline);
+ clutter_paint_node_set_name (node, "AspectRatioVideoOverlay");
+
+ clutter_paint_node_add_texture_rectangle_custom (node,
+ overlay_box.x1, overlay_box.y1,
+ overlay_box.x2, overlay_box.y2,
+ overlay_input_box.x1, overlay_input_box.y1,
+ overlay_input_box.x2, overlay_input_box.y2);
+
+ clutter_paint_node_add_child (root, node);
+ clutter_paint_node_unref (node);
+ }
+ }
+ }
}
static void
diff --git a/clutter-gst/clutter-gst-content.c b/clutter-gst/clutter-gst-content.c
index e23a31c..83405a0 100644
--- a/clutter-gst/clutter-gst-content.c
+++ b/clutter-gst/clutter-gst-content.c
@@ -57,7 +57,12 @@ struct _ClutterGstContentPrivate
{
ClutterGstVideoSink *sink;
ClutterGstPlayer *player;
+
ClutterGstFrame *current_frame;
+ ClutterGstOverlays *overlays;
+
+ gboolean paint_frame;
+ gboolean paint_overlays;
};
enum
@@ -66,6 +71,8 @@ enum
PROP_VIDEO_SINK,
PROP_PLAYER,
+ PROP_PAINT_FRAME,
+ PROP_PAINT_OVERLAYS,
PROP_LAST
};
@@ -82,6 +89,56 @@ enum
static guint signals[LAST_SIGNAL];
+/**/
+
+gboolean
+clutter_gst_content_get_paint_frame (ClutterGstContent *self)
+{
+ return self->priv->paint_frame;
+}
+
+static void
+clutter_gst_content_set_paint_frame (ClutterGstContent *self, gboolean value)
+{
+ if (self->priv->paint_frame == value)
+ return;
+
+ self->priv->paint_frame = value;
+ clutter_content_invalidate (CLUTTER_CONTENT (self));
+}
+
+gboolean
+clutter_gst_content_get_paint_overlays (ClutterGstContent *self)
+{
+ return self->priv->paint_overlays;
+}
+
+static void
+clutter_gst_content_set_paint_overlays (ClutterGstContent *self, gboolean value)
+{
+ if (self->priv->paint_overlays == value)
+ return;
+
+ self->priv->paint_overlays = value;
+ clutter_content_invalidate (CLUTTER_CONTENT (self));
+}
+
+static gboolean
+clutter_gst_content_has_painting_content (ClutterGstContent *self)
+{
+ ClutterGstContentPrivate *priv = self->priv;
+
+ if (priv->paint_frame && priv->current_frame)
+ return TRUE;
+
+ if (priv->paint_overlays && priv->overlays && priv->overlays->overlays->len > 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+/**/
+
static void
update_frame (ClutterGstContent *self,
ClutterGstFrame *new_frame)
@@ -112,12 +169,38 @@ update_frame (ClutterGstContent *self,
}
static void
+update_overlays (ClutterGstContent *self,
+ ClutterGstOverlays *new_overlays)
+{
+ ClutterGstContentPrivate *priv = self->priv;
+
+ if (priv->overlays != NULL)
+ {
+ g_boxed_free (CLUTTER_GST_TYPE_OVERLAYS, priv->overlays);
+ priv->overlays = NULL;
+ }
+ if (new_overlays != NULL)
+ priv->overlays = g_boxed_copy (CLUTTER_GST_TYPE_OVERLAYS, new_overlays);
+}
+
+static void
_new_frame_from_pipeline (ClutterGstVideoSink *sink,
ClutterGstContent *self)
{
update_frame (self, clutter_gst_video_sink_get_frame (sink));
- clutter_content_invalidate (CLUTTER_CONTENT (self));
+ if (CLUTTER_GST_CONTENT_GET_CLASS (self)->has_painting_content (self))
+ clutter_content_invalidate (CLUTTER_CONTENT (self));
+}
+
+static void
+_new_overlays_from_pipeline (ClutterGstVideoSink *sink,
+ ClutterGstContent *self)
+{
+ update_overlays (self, clutter_gst_video_sink_get_overlays (sink));
+
+ if (CLUTTER_GST_CONTENT_GET_CLASS (self)->has_painting_content (self))
+ clutter_content_invalidate (CLUTTER_CONTENT (self));
}
static void
@@ -183,14 +266,15 @@ content_set_sink (ClutterGstContent *self,
priv->sink = g_object_ref_sink (sink);
g_signal_connect (priv->sink, "new-frame",
G_CALLBACK (_new_frame_from_pipeline), self);
+ g_signal_connect (priv->sink, "new-overlays",
+ G_CALLBACK (_new_overlays_from_pipeline), self);
g_signal_connect (priv->sink, "notify::pixel-aspect-ratio",
G_CALLBACK (_pixel_aspect_ratio_changed), self);
if (clutter_gst_video_sink_is_ready (priv->sink))
{
- ClutterGstFrame *frame = clutter_gst_video_sink_get_frame (priv->sink);
- if (frame)
- update_frame (self, frame);
+ update_frame (self, clutter_gst_video_sink_get_frame (priv->sink));
+ update_overlays (self, clutter_gst_video_sink_get_overlays (priv->sink));
}
}
@@ -220,46 +304,82 @@ clutter_gst_content_paint_content (ClutterContent *content,
ClutterActor *actor,
ClutterPaintNode *root)
{
- ClutterGstContentPrivate *priv = CLUTTER_GST_CONTENT (content)->priv;
+ ClutterGstContent *self = CLUTTER_GST_CONTENT (content);
+ ClutterGstContentPrivate *priv = self->priv;
ClutterActorBox box;
ClutterPaintNode *node;
ClutterContentRepeat repeat;
guint8 paint_opacity;
- if (!priv->current_frame)
+ if (!CLUTTER_GST_CONTENT_GET_CLASS (self)->has_painting_content (self))
return;
clutter_actor_get_content_box (actor, &box);
paint_opacity = clutter_actor_get_paint_opacity (actor);
repeat = clutter_actor_get_content_repeat (actor);
+ if (priv->paint_frame && priv->current_frame)
+ {
+ cogl_pipeline_set_color4ub (priv->current_frame->pipeline,
+ paint_opacity, paint_opacity,
+ paint_opacity, paint_opacity);
- cogl_pipeline_set_color4ub (priv->current_frame->pipeline,
- paint_opacity, paint_opacity,
- paint_opacity, paint_opacity);
+ node = clutter_pipeline_node_new (priv->current_frame->pipeline);
+ clutter_paint_node_set_name (node, "Video");
- node = clutter_pipeline_node_new (priv->current_frame->pipeline);
- clutter_paint_node_set_name (node, "Video");
+ if (repeat == CLUTTER_REPEAT_NONE)
+ clutter_paint_node_add_rectangle (node, &box);
+ else
+ {
+ float t_w = 1.f, t_h = 1.f;
- if (repeat == CLUTTER_REPEAT_NONE)
- clutter_paint_node_add_rectangle (node, &box);
- else
- {
- float t_w = 1.f, t_h = 1.f;
+ if ((repeat & CLUTTER_REPEAT_X_AXIS) != FALSE)
+ t_w = (box.x2 - box.x1) / priv->current_frame->resolution.width;
- if ((repeat & CLUTTER_REPEAT_X_AXIS) != FALSE)
- t_w = (box.x2 - box.x1) / priv->current_frame->resolution.width;
+ if ((repeat & CLUTTER_REPEAT_Y_AXIS) != FALSE)
+ t_h = (box.y2 - box.y1) / priv->current_frame->resolution.height;
- if ((repeat & CLUTTER_REPEAT_Y_AXIS) != FALSE)
- t_h = (box.y2 - box.y1) / priv->current_frame->resolution.height;
+ clutter_paint_node_add_texture_rectangle (node, &box,
+ 0.f, 0.f,
+ t_w, t_h);
+ }
- clutter_paint_node_add_texture_rectangle (node, &box,
- 0.f, 0.f,
- t_w, t_h);
+ clutter_paint_node_add_child (root, node);
+ clutter_paint_node_unref (node);
}
- clutter_paint_node_add_child (root, node);
- clutter_paint_node_unref (node);
+ if (priv->paint_overlays && priv->overlays)
+ {
+ guint i;
+
+ for (i = 0; i < priv->overlays->overlays->len; i++)
+ {
+ ClutterGstOverlay *overlay =
+ g_ptr_array_index (priv->overlays->overlays, i);
+ gfloat box_width = clutter_actor_box_get_width (&box),
+ box_height = clutter_actor_box_get_height (&box);
+ ClutterActorBox obox = {
+ overlay->position.x1 * box_width / priv->current_frame->resolution.width,
+ overlay->position.y1 * box_height / priv->current_frame->resolution.height,
+ overlay->position.x2 * box_width / priv->current_frame->resolution.width,
+ overlay->position.y2 * box_height / priv->current_frame->resolution.height
+ };
+
+ cogl_pipeline_set_color4ub (overlay->pipeline,
+ paint_opacity, paint_opacity,
+ paint_opacity, paint_opacity);
+
+ node = clutter_pipeline_node_new (overlay->pipeline);
+ clutter_paint_node_set_name (node, "AspectRatioVideoOverlay");
+
+ clutter_paint_node_add_texture_rectangle (node, &obox,
+ 0, 0,
+ 1, 1);
+
+ clutter_paint_node_add_child (root, node);
+ clutter_paint_node_unref (node);
+ }
+ }
}
static void
@@ -288,6 +408,14 @@ clutter_gst_content_set_property (GObject *object,
CLUTTER_GST_PLAYER (g_value_get_object (value)));
break;
+ case PROP_PAINT_FRAME:
+ clutter_gst_content_set_paint_frame (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_PAINT_OVERLAYS:
+ clutter_gst_content_set_paint_overlays (self, g_value_get_boolean (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -312,6 +440,14 @@ clutter_gst_content_get_property (GObject *object,
g_value_set_object (value, priv->player);
break;
+ case PROP_PAINT_FRAME:
+ g_value_set_boolean (value, priv->paint_frame);
+ break;
+
+ case PROP_PAINT_OVERLAYS:
+ g_value_set_boolean (value, priv->paint_overlays);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -350,6 +486,8 @@ clutter_gst_content_class_init (ClutterGstContentClass *klass)
gobject_class->dispose = clutter_gst_content_dispose;
gobject_class->finalize = clutter_gst_content_finalize;
+ klass->has_painting_content = clutter_gst_content_has_painting_content;
+
g_type_class_add_private (klass, sizeof (ClutterGstContentPrivate));
props[PROP_PLAYER] =
@@ -365,6 +503,20 @@ clutter_gst_content_class_init (ClutterGstContentClass *klass)
"Cogl Video Sink",
CLUTTER_GST_TYPE_VIDEO_SINK,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+
+ props[PROP_PAINT_FRAME] =
+ g_param_spec_boolean ("paint-frame",
+ "Paint Video Overlays",
+ "Paint Video Overlays",
+ TRUE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+
+ props[PROP_PAINT_OVERLAYS] =
+ g_param_spec_boolean ("paint-overlays",
+ "Paint Video Overlays",
+ "Paint Video Overlays",
+ TRUE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
g_object_class_install_properties (gobject_class, PROP_LAST, props);
@@ -398,6 +550,9 @@ clutter_gst_content_init (ClutterGstContent *self)
content_set_sink (self,
CLUTTER_GST_VIDEO_SINK (clutter_gst_create_video_sink ()),
FALSE);
+
+ priv->paint_frame = TRUE;
+ priv->paint_overlays = TRUE;
}
@@ -445,6 +600,22 @@ clutter_gst_content_get_frame (ClutterGstContent *self)
}
/**
+ * clutter_gst_content_get_overlays:
+ * @self: A #ClutterGstContent
+ *
+ * Returns: (transfer none) (element-type ClutterGst.Overlay): The #ClutterGstFrame currently attached to @self.
+ *
+ * Since: 3.0
+ */
+ClutterGstOverlays *
+clutter_gst_content_get_overlays (ClutterGstContent *self)
+{
+ g_return_val_if_fail (CLUTTER_GST_IS_CONTENT (self), NULL);
+
+ return self->priv->overlays;
+}
+
+/**
* clutter_gst_content_get_sink:
* @self: A #ClutterGstContent
*
diff --git a/clutter-gst/clutter-gst-content.h b/clutter-gst/clutter-gst-content.h
index 124b2a8..dfd0633 100644
--- a/clutter-gst/clutter-gst-content.h
+++ b/clutter-gst/clutter-gst-content.h
@@ -74,6 +74,8 @@ struct _ClutterGstContentClass
/*< private >*/
GObjectClass parent_class;
+ gboolean (* has_painting_content) (ClutterGstContent *self);
+
void *_padding_dummy[10];
};
@@ -85,6 +87,8 @@ ClutterContent * clutter_gst_content_new_with_sink (ClutterGstVideoSink
ClutterGstFrame * clutter_gst_content_get_frame (ClutterGstContent *self);
+ClutterGstOverlays * clutter_gst_content_get_overlays (ClutterGstContent *self);
+
void clutter_gst_content_set_sink (ClutterGstContent *self,
ClutterGstVideoSink *sink);
diff --git a/clutter-gst/clutter-gst-private.h b/clutter-gst/clutter-gst-private.h
index 25dcf5c..c1bbeac 100644
--- a/clutter-gst/clutter-gst-private.h
+++ b/clutter-gst/clutter-gst-private.h
@@ -70,6 +70,10 @@ ClutterGstFrame *clutter_gst_frame_new (void);
ClutterGstFrame *clutter_gst_create_blank_frame (const ClutterColor *color);
+ClutterGstOverlay *clutter_gst_overlay_new (void);
+
+ClutterGstOverlays *clutter_gst_overlays_new (void);
+
void clutter_gst_player_update_frame (ClutterGstPlayer *player,
ClutterGstFrame **frame,
ClutterGstFrame *new_frame);
@@ -80,6 +84,10 @@ void clutter_gst_frame_update_pixel_aspect_ratio (ClutterGstFrame *frame,
void clutter_gst_video_resolution_from_video_info (ClutterGstVideoResolution *resolution,
GstVideoInfo *info);
+
+gboolean clutter_gst_content_get_paint_frame (ClutterGstContent *content);
+gboolean clutter_gst_content_get_paint_overlays (ClutterGstContent *content);
+
G_END_DECLS
#endif /* __CLUTTER_GST_PRIVATE_H__ */
diff --git a/clutter-gst/clutter-gst-types.c b/clutter-gst/clutter-gst-types.c
index bdfd827..a4ec6f4 100644
--- a/clutter-gst/clutter-gst-types.c
+++ b/clutter-gst/clutter-gst-types.c
@@ -70,6 +70,97 @@ G_DEFINE_BOXED_TYPE (ClutterGstFrame,
clutter_gst_frame_copy,
clutter_gst_frame_free);
+
+ClutterGstOverlay *
+clutter_gst_overlay_new (void)
+{
+ return g_slice_new0 (ClutterGstOverlay);
+}
+
+static gpointer
+clutter_gst_overlay_copy (gpointer data)
+{
+ if (G_LIKELY (data))
+ {
+ ClutterGstOverlay *overlay = g_slice_dup (ClutterGstOverlay, data);
+
+ if (overlay->pipeline != COGL_INVALID_HANDLE)
+ overlay->pipeline = cogl_object_ref (overlay->pipeline);
+
+ return overlay;
+ }
+
+ return NULL;
+}
+
+static void
+clutter_gst_overlay_free (gpointer data)
+{
+ if (G_LIKELY (data))
+ {
+ ClutterGstOverlay *overlay = (ClutterGstOverlay *) data;
+
+ if (overlay->pipeline != COGL_INVALID_HANDLE)
+ {
+ cogl_object_unref (overlay->pipeline);
+ overlay->pipeline = COGL_INVALID_HANDLE;
+ }
+ g_slice_free (ClutterGstOverlay, overlay);
+ }
+}
+
+G_DEFINE_BOXED_TYPE (ClutterGstOverlay,
+ clutter_gst_overlay,
+ clutter_gst_overlay_copy,
+ clutter_gst_overlay_free);
+
+ClutterGstOverlays *
+clutter_gst_overlays_new (void)
+{
+ ClutterGstOverlays *overlays = g_slice_new0 (ClutterGstOverlays);
+
+ overlays->overlays = g_ptr_array_new_with_free_func (clutter_gst_overlay_free);
+
+ return overlays;
+}
+
+static gpointer
+clutter_gst_overlays_copy (gpointer data)
+{
+ if (G_LIKELY (data))
+ {
+ ClutterGstOverlays *overlays = clutter_gst_overlays_new ();
+ GPtrArray *src_overlays = ((ClutterGstOverlays *) data)->overlays;
+ guint i;
+
+ for (i = 0; i < src_overlays->len; i++)
+ g_ptr_array_add (overlays->overlays,
+ clutter_gst_overlay_copy (g_ptr_array_index (src_overlays,
+ i)));
+ return overlays;
+ }
+
+ return NULL;
+}
+
+static void
+clutter_gst_overlays_free (gpointer data)
+{
+ if (G_LIKELY (data))
+ {
+ ClutterGstOverlays *overlays = (ClutterGstOverlays *) data;
+
+ g_ptr_array_unref (overlays->overlays);
+
+ g_slice_free (ClutterGstOverlays, overlays);
+ }
+}
+
+G_DEFINE_BOXED_TYPE (ClutterGstOverlays,
+ clutter_gst_overlays,
+ clutter_gst_overlays_copy,
+ clutter_gst_overlays_free);
+
static ClutterGstBox *
clutter_gst_box_copy (const ClutterGstBox *box)
{
diff --git a/clutter-gst/clutter-gst-types.h b/clutter-gst/clutter-gst-types.h
index 7124d90..f958161 100644
--- a/clutter-gst/clutter-gst-types.h
+++ b/clutter-gst/clutter-gst-types.h
@@ -36,9 +36,13 @@
#define CLUTTER_GST_TYPE_FRAME (clutter_gst_frame_get_type ())
#define CLUTTER_GST_TYPE_BOX (clutter_gst_box_get_type ())
+#define CLUTTER_GST_TYPE_OVERLAY (clutter_gst_overlay_get_type ())
+#define CLUTTER_GST_TYPE_OVERLAYS (clutter_gst_overlays_get_type ())
typedef struct _ClutterGstBox ClutterGstBox;
typedef struct _ClutterGstFrame ClutterGstFrame;
+typedef struct _ClutterGstOverlay ClutterGstOverlay;
+typedef struct _ClutterGstOverlays ClutterGstOverlays;
typedef struct _ClutterGstVideoResolution ClutterGstVideoResolution;
/**
@@ -72,6 +76,25 @@ typedef enum _ClutterGstBufferingMode
} ClutterGstBufferingMode;
/**
+ * ClutterGstBox:
+ * @x1: X coordinate of the top left corner
+ * @y1: Y coordinate of the top left corner
+ * @x2: X coordinate of the bottom right corner
+ * @y2: Y coordinate of the bottom right corner
+ *
+ * Bounding box of an area in a video texture or actor's allocation.
+ * Coordinates are usually expressed in the [0, 1] interval.
+ */
+struct _ClutterGstBox
+{
+ gfloat x1;
+ gfloat y1;
+
+ gfloat x2;
+ gfloat y2;
+};
+
+/**
* ClutterGstVideoResolution:
* @width: the width, in pixels
* @height: the height, in pixels
@@ -90,7 +113,7 @@ struct _ClutterGstVideoResolution
/**
* ClutterGstFrame:
* @resolution: a #ClutterGstVideoResolution
- * @pipeline: a #CoglHandle to the pipeline to paint a frame
+ * @pipeline: a #CoglPipeline to paint a frame
*
* Represents a frame outputted by the #ClutterGstVideoSink.
*/
@@ -100,29 +123,27 @@ struct _ClutterGstFrame
CoglPipeline *pipeline;
};
-
/**
- * ClutterGstBox:
- * @x1: X coordinate of the top left corner
- * @y1: Y coordinate of the top left corner
- * @x2: X coordinate of the bottom right corner
- * @y2: Y coordinate of the bottom right corner
+ * ClutterGstOverlay:
+ * @position:
+ * @pipeline: a #CoglPipeline to paint an overlay
*
- * Bounding box of an area in a video texture or actor's allocation.
- * Coordinates are usually expressed in the [0, 1] interval.
*/
-struct _ClutterGstBox
+struct _ClutterGstOverlay
{
- gfloat x1;
- gfloat y1;
-
- gfloat x2;
- gfloat y2;
+ ClutterGstBox position;
+ CoglPipeline *pipeline;
};
+struct _ClutterGstOverlays
+{
+ GPtrArray *overlays;
+};
-GType clutter_gst_frame_get_type (void) G_GNUC_CONST;
-GType clutter_gst_box_get_type (void) G_GNUC_CONST;
+GType clutter_gst_frame_get_type (void) G_GNUC_CONST;
+GType clutter_gst_box_get_type (void) G_GNUC_CONST;
+GType clutter_gst_overlay_get_type (void) G_GNUC_CONST;
+GType clutter_gst_overlays_get_type (void) G_GNUC_CONST;
gfloat clutter_gst_box_get_width (const ClutterGstBox *box);
gfloat clutter_gst_box_get_height (const ClutterGstBox *box);
diff --git a/clutter-gst/clutter-gst-util.c b/clutter-gst/clutter-gst-util.c
index fb25abb..c045142 100644
--- a/clutter-gst/clutter-gst-util.c
+++ b/clutter-gst/clutter-gst-util.c
@@ -271,11 +271,12 @@ clutter_gst_create_blank_frame (const ClutterColor *color)
const guint8 *color_ptr = color != NULL ?
(const guint8 *) color : (const guint8 *) &black_color;
- texture = cogl_texture_new_from_data (1, 1, COGL_TEXTURE_NONE,
- COGL_PIXEL_FORMAT_RGBA_8888,
- COGL_PIXEL_FORMAT_RGBA_8888,
- 1,
- color_ptr);
+ texture = cogl_texture_2d_new_from_data (clutter_gst_get_cogl_context (),
+ 1, 1,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ 1,
+ color_ptr,
+ NULL);
frame->pipeline = cogl_pipeline_new (clutter_gst_get_cogl_context ());
cogl_pipeline_set_layer_texture (frame->pipeline, 0, texture);
diff --git a/clutter-gst/clutter-gst-video-sink.c b/clutter-gst/clutter-gst-video-sink.c
index 1959c4e..539319d 100644
--- a/clutter-gst/clutter-gst-video-sink.c
+++ b/clutter-gst/clutter-gst-video-sink.c
@@ -130,6 +130,8 @@ enum
PIPELINE_READY,
NEW_FRAME,
+ NEW_OVERLAYS,
+
LAST_SIGNAL
};
@@ -231,8 +233,111 @@ struct _ClutterGstVideoSinkPrivate
guint8 *tabley;
guint8 *tableu;
guint8 *tablev;
+
+ /**/
+ GstVideoOverlayComposition *last_composition;
+ ClutterGstOverlays *overlays;
};
+/* Overlays */
+
+static void
+clutter_gst_video_sink_upload_overlay (ClutterGstVideoSink *sink, GstBuffer *buffer)
+{
+ ClutterGstVideoSinkPrivate *priv = sink->priv;
+
+ GstVideoOverlayComposition *composition = NULL;
+ GstVideoOverlayCompositionMeta *composition_meta;
+ guint i, nb_rectangle;
+
+ composition_meta = gst_buffer_get_video_overlay_composition_meta (buffer);
+ if (composition_meta)
+ composition = composition_meta->overlay;
+
+ if (composition == NULL)
+ {
+ if (priv->last_composition != NULL)
+ {
+ gst_video_overlay_composition_unref (priv->last_composition);
+ priv->last_composition = NULL;
+
+ if (priv->overlays)
+ g_boxed_free (CLUTTER_GST_TYPE_OVERLAYS, priv->overlays);
+ priv->overlays = clutter_gst_overlays_new ();
+
+ g_signal_emit (sink, video_sink_signals[NEW_OVERLAYS], 0);
+ }
+ return;
+ }
+
+ g_clear_pointer (&priv->last_composition, gst_video_overlay_composition_unref);
+ priv->last_composition = gst_video_overlay_composition_ref (composition);
+ if (priv->overlays)
+ g_boxed_free (CLUTTER_GST_TYPE_OVERLAYS, priv->overlays);
+ priv->overlays = clutter_gst_overlays_new ();
+
+ nb_rectangle = gst_video_overlay_composition_n_rectangles (composition);
+ for (i = 0; i < nb_rectangle; i++)
+ {
+ GstVideoOverlayRectangle *rectangle;
+ GstBuffer *comp_buffer;
+ GstMapInfo info;
+ GstVideoMeta *vmeta;
+ gpointer data;
+ gint comp_x, comp_y, stride;
+ guint comp_width, comp_height;
+ CoglTexture *tex;
+ CoglError *error;
+
+ rectangle = gst_video_overlay_composition_get_rectangle (composition, i);
+ comp_buffer =
+ gst_video_overlay_rectangle_get_pixels_unscaled_argb (rectangle,
+ GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
+
+ gst_video_overlay_rectangle_get_render_rectangle (rectangle,
+ &comp_x, &comp_y, &comp_width, &comp_height);
+
+ vmeta = gst_buffer_get_video_meta (comp_buffer);
+ gst_video_meta_map (vmeta, 0, &info, &data, &stride, GST_MAP_READ);
+
+ tex =
+ cogl_texture_2d_new_from_data (priv->ctx,
+ comp_width,
+ comp_height,
+ COGL_PIXEL_FORMAT_BGRA_8888,
+ stride, data,
+ &error);
+
+ gst_video_meta_unmap (vmeta, 0, &info);
+
+ if (tex != NULL)
+ {
+ ClutterGstOverlay *overlay = clutter_gst_overlay_new ();
+
+ overlay->position.x1 = comp_x;
+ overlay->position.y1 = comp_y;
+ overlay->position.x2 = comp_x + comp_width;
+ overlay->position.y2 = comp_y + comp_height;
+
+ overlay->pipeline = cogl_pipeline_new (priv->ctx);
+ cogl_pipeline_set_layer_texture (overlay->pipeline, 0, tex);
+
+ cogl_object_unref (tex);
+
+ g_ptr_array_add (priv->overlays->overlays, overlay);
+ }
+ else
+ {
+ GST_WARNING_OBJECT (sink,
+ "Cannot upload overlay texture : %s",
+ error->message);
+ cogl_error_free (error);
+ }
+ }
+
+ g_signal_emit (sink, video_sink_signals[NEW_OVERLAYS], 0);
+}
+
/* Snippet cache */
static SnippetCacheEntry *
@@ -1822,6 +1927,8 @@ clutter_gst_source_dispatch (GSource *source,
if (buffer)
{
+ clutter_gst_video_sink_upload_overlay (gst_source->sink, buffer);
+
if (gst_buffer_get_video_gl_texture_upload_meta (buffer) != NULL) {
if (!priv->renderer->upload_gl (gst_source->sink, buffer)) {
goto fail_upload;
@@ -1919,6 +2026,7 @@ clutter_gst_video_sink_init (ClutterGstVideoSink *sink)
priv->ctx = clutter_gst_get_cogl_context ();
priv->renderers = clutter_gst_build_renderers_list (priv->ctx);
priv->caps = clutter_gst_build_caps (priv->renderers);
+ priv->overlays = clutter_gst_overlays_new ();
}
static GstFlowReturn
@@ -2092,6 +2200,8 @@ clutter_gst_video_sink_propose_allocation (GstBaseSink *base_sink, GstQuery *que
GST_VIDEO_META_API_TYPE, NULL);
gst_query_add_allocation_meta (query,
GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
+ gst_query_add_allocation_meta (query,
+ GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
return TRUE;
}
@@ -2194,6 +2304,29 @@ clutter_gst_video_sink_class_init (ClutterGstVideoSinkClass *klass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0 /* n_params */);
+
+ /**
+ * ClutterGstVideoSink::new-overlays:
+ * @sink: the #ClutterGstVideoSink
+ *
+ * The sink will emit this signal whenever there are new textures
+ * available for set of overlays on the video. After this signal is
+ * emitted, an application can call
+ * clutter_gst_video_sink_get_overlays() to get a set of pipelines
+ * suitable for rendering overlays on a video frame.
+ *
+ * Since: 3.0
+ */
+ video_sink_signals[NEW_OVERLAYS] =
+ g_signal_new ("new-overlays",
+ CLUTTER_GST_TYPE_VIDEO_SINK,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterGstVideoSinkClass, new_overlays),
+ NULL, /* accumulator */
+ NULL, /* accu_data */
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0 /* n_params */);
}
/**
@@ -2395,3 +2528,12 @@ clutter_gst_video_sink_setup_pipeline (ClutterGstVideoSink *sink,
priv->renderer->setup_pipeline (sink, priv->pipeline);
}
}
+
+
+ClutterGstOverlays *
+clutter_gst_video_sink_get_overlays (ClutterGstVideoSink *sink)
+{
+ g_return_val_if_fail (CLUTTER_GST_IS_VIDEO_SINK (sink), NULL);
+
+ return sink->priv->overlays;
+}
diff --git a/clutter-gst/clutter-gst-video-sink.h b/clutter-gst/clutter-gst-video-sink.h
index 505a6cd..692d3ad 100644
--- a/clutter-gst/clutter-gst-video-sink.h
+++ b/clutter-gst/clutter-gst-video-sink.h
@@ -97,6 +97,7 @@ struct _ClutterGstVideoSinkClass
/*< public >*/
void (* new_frame) (ClutterGstVideoSink *sink);
void (* pipeline_ready) (ClutterGstVideoSink *sink);
+ void (* new_overlays) (ClutterGstVideoSink *sink);
/*< private >*/
void *_padding_dummy[8];
@@ -116,6 +117,8 @@ CoglPipeline * clutter_gst_video_sink_get_pipeline (ClutterGstVideoSink
void clutter_gst_video_sink_setup_pipeline (ClutterGstVideoSink *sink,
CoglPipeline *pipeline);
+ClutterGstOverlays * clutter_gst_video_sink_get_overlays (ClutterGstVideoSink *sink);
+
G_END_DECLS
#endif