gstframepositionner: Install width and height properties.
authorSimon Corsin <simoncorsin@gmail.com>
Wed, 21 Aug 2013 09:32:45 +0000 (11:32 +0200)
committerThibault Saunier <thibault.saunier@collabora.com>
Wed, 4 Sep 2013 00:57:31 +0000 (20:57 -0400)
  + And manage them properly.

ges/ges-video-source.c
ges/gstframepositionner.c
ges/gstframepositionner.h

index cfdac94..981eaf2 100644 (file)
@@ -35,6 +35,7 @@ G_DEFINE_TYPE (GESVideoSource, ges_video_source, GES_TYPE_SOURCE);
 struct _GESVideoSourcePrivate
 {
   GstFramePositionner *positionner;
+  GstElement *capsfilter;
 };
 
 static void
@@ -61,8 +62,8 @@ ges_video_source_create_element (GESTrackElement * trksrc)
   GstElement *sub_element;
   GESVideoSourceClass *source_class = GES_VIDEO_SOURCE_GET_CLASS (trksrc);
   GESVideoSource *self;
-  GstElement *positionner;
-  const gchar *props[] = { "alpha", "posx", "posy", NULL };
+  GstElement *positionner, *videoscale, *capsfilter;
+  const gchar *props[] = { "alpha", "posx", "posy", "width", "height", NULL };
   GESTimelineElement *parent;
 
   if (!source_class->create_source)
@@ -76,9 +77,18 @@ ges_video_source_create_element (GESTrackElement * trksrc)
      properties, acting like a proxy for our smart-mixer dynamic pads. */
   positionner = gst_element_factory_make ("framepositionner", "frame_tagger");
 
+  videoscale =
+      gst_element_factory_make ("videoscale", "track-element-videoscale");
+  capsfilter =
+      gst_element_factory_make ("capsfilter", "track-element-capsfilter");
+
+  ges_frame_positionner_set_source_and_filter (GST_FRAME_POSITIONNER
+      (positionner), trksrc, capsfilter);
+
   ges_track_element_add_children_props (trksrc, positionner, NULL, NULL, props);
   topbin =
-      ges_source_create_topbin ("videosrcbin", sub_element, positionner, NULL);
+      ges_source_create_topbin ("videosrcbin", sub_element, positionner,
+      videoscale, capsfilter, NULL);
   parent = ges_timeline_element_get_parent (GES_TIMELINE_ELEMENT (trksrc));
   if (parent) {
     self->priv->positionner = GST_FRAME_POSITIONNER (positionner);
@@ -90,6 +100,8 @@ ges_video_source_create_element (GESTrackElement * trksrc)
     GST_ERROR ("No parent timeline element, SHOULD NOT HAPPEN");
   }
 
+  self->priv->capsfilter = capsfilter;
+
   return topbin;
 }
 
@@ -112,4 +124,5 @@ ges_video_source_init (GESVideoSource * self)
   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
       GES_TYPE_VIDEO_SOURCE, GESVideoSourcePrivate);
   self->priv->positionner = NULL;
+  self->priv->capsfilter = NULL;
 }
index 97496da..22a6431 100644 (file)
@@ -42,7 +42,9 @@ enum
   PROP_ALPHA,
   PROP_POSX,
   PROP_POSY,
-  PROP_ZORDER
+  PROP_ZORDER,
+  PROP_WIDTH,
+  PROP_HEIGHT
 };
 
 static GstStaticPadTemplate gst_frame_positionner_src_template =
@@ -63,6 +65,154 @@ G_DEFINE_TYPE (GstFramePositionner, gst_frame_positionner,
     GST_TYPE_BASE_TRANSFORM);
 
 static void
+_weak_notify_cb (GstFramePositionner * pos, GObject * old)
+{
+  pos->current_track = NULL;
+}
+
+static void
+gst_frame_positionner_update_size (GstFramePositionner * pos)
+{
+  GstCaps *size_caps;
+  gint final_width;
+  gint final_height;
+
+  if (pos->capsfilter == NULL)
+    return;
+
+  final_width = (pos->width > 0) ? pos->width : pos->track_width;
+  final_height = (pos->height > 0) ? pos->height : pos->track_height;
+
+  if (final_width == 0 && final_height == 0)
+    size_caps = gst_caps_new_empty_simple ("video/x-raw");
+  else if (final_width == 0)
+    size_caps =
+        gst_caps_new_simple ("video/x-raw", "height", G_TYPE_INT, final_height,
+        NULL);
+  else if (final_height == 0)
+    size_caps =
+        gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, final_width,
+        NULL);
+  else
+    size_caps =
+        gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT,
+        final_width, "height", G_TYPE_INT, final_height, NULL);
+
+  GST_DEBUG_OBJECT (pos, "updated size to : %d %d", final_width, final_height);
+
+  g_object_set (pos->capsfilter, "caps", size_caps, NULL);
+
+  g_object_notify (G_OBJECT (pos), "width");
+  g_object_notify (G_OBJECT (pos), "height");
+}
+
+static void
+sync_size_from_caps (GstFramePositionner * pos, GstCaps * caps)
+{
+  gint width, height;
+
+  width = height = 0;
+
+  if (caps && gst_caps_get_size (caps) > 0) {
+    GstStructure *structure;
+
+    structure = gst_caps_get_structure (caps, 0);
+    if (!gst_structure_get_int (structure, "width", &width))
+      width = 0;
+    if (!gst_structure_get_int (structure, "height", &height))
+      width = 0;
+  }
+
+  pos->track_width = width;
+  pos->track_height = height;
+
+  GST_DEBUG_OBJECT (pos, "syncing size from caps : %d %d", width, height);
+
+  gst_frame_positionner_update_size (pos);
+}
+
+static void
+sync_size_with_track (GstFramePositionner * pos, GESTrack * track)
+{
+  GstCaps *caps;
+
+  g_object_get (track, "restriction-caps", &caps, NULL);
+  sync_size_from_caps (pos, caps);
+}
+
+static void
+_track_restriction_changed_cb (GESTrack * track, GParamSpec * arg G_GNUC_UNUSED,
+    GstFramePositionner * pos)
+{
+  sync_size_with_track (pos, track);
+}
+
+static void
+_track_changed_cb (GESTrackElement * trksrc, GParamSpec * arg G_GNUC_UNUSED,
+    GstFramePositionner * pos)
+{
+  GESTrack *new_track;
+
+  if (pos->current_track) {
+    g_signal_handlers_disconnect_by_func (pos->current_track,
+        (GCallback) _track_restriction_changed_cb, pos);
+    g_object_weak_unref (G_OBJECT (pos->current_track),
+        (GWeakNotify) _weak_notify_cb, pos);
+  }
+
+  new_track = ges_track_element_get_track (trksrc);
+  if (new_track) {
+    pos->current_track = new_track;
+    g_object_weak_ref (G_OBJECT (new_track), (GWeakNotify) _weak_notify_cb,
+        pos);
+    GST_DEBUG_OBJECT (pos, "connecting to track : %p", pos->current_track);
+    g_signal_connect (pos->current_track, "notify::restriction-caps",
+        (GCallback) _track_restriction_changed_cb, pos);
+    sync_size_with_track (pos, pos->current_track);
+  } else
+    pos->current_track = NULL;
+}
+
+void
+ges_frame_positionner_set_source_and_filter (GstFramePositionner * pos,
+    GESTrackElement * trksrc, GstElement * capsfilter)
+{
+  pos->track_source = trksrc;
+  pos->capsfilter = capsfilter;
+  pos->current_track = ges_track_element_get_track (trksrc);
+  g_object_weak_ref (G_OBJECT (pos->current_track),
+      (GWeakNotify) _weak_notify_cb, pos);
+
+  GST_DEBUG_OBJECT (pos, "connecting to track : %p", pos->current_track);
+
+  g_signal_connect (pos->current_track, "notify::restriction-caps",
+      (GCallback) _track_restriction_changed_cb, pos);
+  g_signal_connect (trksrc, "notify::track", (GCallback) _track_changed_cb,
+      pos);
+  sync_size_with_track (pos, pos->current_track);
+}
+
+static void
+gst_frame_positionner_dispose (GObject * object)
+{
+  GstFramePositionner *pos = GST_FRAME_POSITIONNER (object);
+
+  if (pos->track_source) {
+    g_signal_handlers_disconnect_by_func (pos->track_source, _track_changed_cb,
+        pos);
+    pos->track_source = NULL;
+  }
+
+  if (pos->current_track) {
+    g_signal_handlers_disconnect_by_func (pos->current_track,
+        _track_restriction_changed_cb, pos);
+    g_object_weak_unref (G_OBJECT (pos->current_track),
+        (GWeakNotify) _weak_notify_cb, pos);
+    pos->current_track = NULL;
+  }
+}
+
+static void
 gst_frame_positionner_class_init (GstFramePositionnerClass * klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
@@ -76,6 +226,7 @@ gst_frame_positionner_class_init (GstFramePositionnerClass * klass)
 
   gobject_class->set_property = gst_frame_positionner_set_property;
   gobject_class->get_property = gst_frame_positionner_get_property;
+  gobject_class->dispose = gst_frame_positionner_dispose;
   base_transform_class->transform_ip =
       GST_DEBUG_FUNCPTR (gst_frame_positionner_transform_ip);
 
@@ -115,6 +266,26 @@ gst_frame_positionner_class_init (GstFramePositionnerClass * klass)
       g_param_spec_uint ("zorder", "zorder", "z order of the stream",
           0, 10000, 0, G_PARAM_READWRITE));
 
+  /**
+   * gesframepositionner:width:
+   *
+   * The desired width for that source.
+   * Set to 0 if size is not mandatory, will be set to width of the current track.
+   */
+  g_object_class_install_property (gobject_class, PROP_WIDTH,
+      g_param_spec_int ("width", "width", "width of the source",
+          0, G_MAXSHORT, 0, G_PARAM_READWRITE));
+
+  /**
+   * gesframepositionner:height:
+   *
+   * The desired height for that source.
+   * Set to 0 if size is not mandatory, will be set to height of the current track.
+   */
+  g_object_class_install_property (gobject_class, PROP_HEIGHT,
+      g_param_spec_int ("height", "height", "height of the source",
+          0, G_MAXSHORT, 0, G_PARAM_READWRITE));
+
   gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
       "frame positionner", "Metadata",
       "This element provides with tagging facilities",
@@ -128,6 +299,13 @@ gst_frame_positionner_init (GstFramePositionner * framepositionner)
   framepositionner->posx = 0.0;
   framepositionner->posy = 0.0;
   framepositionner->zorder = 0;
+  framepositionner->width = 0;
+  framepositionner->height = 0;
+  framepositionner->track_width = 0;
+  framepositionner->track_height = 0;
+  framepositionner->capsfilter = NULL;
+  framepositionner->track_source = NULL;
+  framepositionner->current_track = NULL;
 }
 
 void
@@ -151,6 +329,14 @@ gst_frame_positionner_set_property (GObject * object, guint property_id,
     case PROP_ZORDER:
       framepositionner->zorder = g_value_get_uint (value);
       break;
+    case PROP_WIDTH:
+      framepositionner->width = g_value_get_int (value);
+      gst_frame_positionner_update_size (framepositionner);
+      break;
+    case PROP_HEIGHT:
+      framepositionner->height = g_value_get_int (value);
+      gst_frame_positionner_update_size (framepositionner);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -162,22 +348,31 @@ void
 gst_frame_positionner_get_property (GObject * object, guint property_id,
     GValue * value, GParamSpec * pspec)
 {
-  GstFramePositionner *framepositionner = GST_FRAME_POSITIONNER (object);
+  GstFramePositionner *pos = GST_FRAME_POSITIONNER (object);
+  gint real_width, real_height;
 
-  GST_DEBUG_OBJECT (framepositionner, "get_property");
+  GST_DEBUG_OBJECT (pos, "get_property");
 
   switch (property_id) {
     case PROP_ALPHA:
-      g_value_set_double (value, framepositionner->alpha);
+      g_value_set_double (value, pos->alpha);
       break;
     case PROP_POSX:
-      g_value_set_int (value, framepositionner->posx);
+      g_value_set_int (value, pos->posx);
       break;
     case PROP_POSY:
-      g_value_set_int (value, framepositionner->posy);
+      g_value_set_int (value, pos->posy);
       break;
     case PROP_ZORDER:
-      g_value_set_uint (value, framepositionner->zorder);
+      g_value_set_uint (value, pos->zorder);
+      break;
+    case PROP_WIDTH:
+      real_width = (pos->width > 0) ? pos->width : pos->track_width;
+      g_value_set_int (value, real_width);
+      break;
+    case PROP_HEIGHT:
+      real_height = (pos->height > 0) ? pos->height : pos->track_height;
+      g_value_set_int (value, real_height);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
index 502c9ef..10cf606 100644 (file)
@@ -21,6 +21,8 @@
 #define _GST_FRAME_POSITIONNER_H_
 
 #include <gst/base/gstbasetransform.h>
+#include <ges/ges-track-element.h>
+#include <ges/ges-track.h>
 
 G_BEGIN_DECLS
 
@@ -38,10 +40,19 @@ struct _GstFramePositionner
 {
   GstBaseTransform base_framepositionner;
 
+  GstElement *capsfilter;
+
+  GESTrackElement *track_source;
+  GESTrack *current_track;
+
   gdouble alpha;
   gint posx;
   gint posy;
   guint zorder;
+  gint width;
+  gint height;
+  gint track_width;
+  gint track_height;
 };
 
 struct _GstFramePositionnerClass
@@ -58,6 +69,9 @@ struct _GstFramePositionnerMeta {
   guint zorder;
 };
 
+void ges_frame_positionner_set_source_and_filter (GstFramePositionner *pos,
+                                                 GESTrackElement *trksrc,
+                                                 GstElement *capsfilter);
 GType gst_frame_positionner_get_type (void);
 GType
 gst_frame_positionner_meta_api_get_type (void);