GESTimelinePipeline: Use 'playsink', track added/removed pads.
authorEdward Hervey <edward.hervey@collabora.co.uk>
Tue, 8 Sep 2009 17:45:08 +0000 (19:45 +0200)
committerEdward Hervey <edward.hervey@collabora.co.uk>
Tue, 8 Sep 2009 17:45:08 +0000 (19:45 +0200)
Also add a method to set a GESTimeline on the pipeline.

ges/ges-timeline-pipeline.c
ges/ges-timeline-pipeline.h

index e91532c..7ec465f 100644 (file)
  *
  */
 
+/* Structure corresponding to a timeline - sink link */
+/* TODO : Don't forget we want to render also :) */
+
+typedef struct
+{
+  GESTimelinePipeline *pipeline;
+  GstPad *srcpad;
+  GstPad *sinkpad;
+} OutputChain;
+
 G_DEFINE_TYPE (GESTimelinePipeline, ges_timeline_pipeline, GST_TYPE_PIPELINE);
 
+static GstStateChangeReturn ges_timeline_pipeline_change_state (GstElement *
+    element, GstStateChange transition);
 static void
 ges_timeline_pipeline_get_property (GObject * object,
     guint property_id, GValue * value, GParamSpec * pspec)
@@ -55,6 +67,13 @@ ges_timeline_pipeline_dispose (GObject * object)
 static void
 ges_timeline_pipeline_finalize (GObject * object)
 {
+  GESTimelinePipeline *self = GES_TIMELINE_PIPELINE (object);
+
+  if (self->sink) {
+    gst_bin_remove (GST_BIN (object), self->sink);
+    gst_object_unref (self->sink);
+    self->sink = NULL;
+  }
   G_OBJECT_CLASS (ges_timeline_pipeline_parent_class)->finalize (object);
 }
 
@@ -62,16 +81,36 @@ static void
 ges_timeline_pipeline_class_init (GESTimelinePipelineClass * klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
   object_class->get_property = ges_timeline_pipeline_get_property;
   object_class->set_property = ges_timeline_pipeline_set_property;
   object_class->dispose = ges_timeline_pipeline_dispose;
   object_class->finalize = ges_timeline_pipeline_finalize;
+
+  element_class->change_state =
+      GST_DEBUG_FUNCPTR (ges_timeline_pipeline_change_state);
+
+  /* TODO : Add state_change handlers
+   * Don't change state if we don't have a timeline */
 }
 
 static void
 ges_timeline_pipeline_init (GESTimelinePipeline * self)
 {
+  GST_INFO_OBJECT (self, "Creating new 'playsink'");
+
+  self->sink = gst_element_factory_make ("playsink", "internal-sinks");
+
+  if (G_UNLIKELY (self->sink == NULL))
+    GST_ERROR_OBJECT (self, "Can't create playsink instance !");
+  else {
+    GST_INFO_OBJECT (self, "Adding playsink to self");
+
+    if (G_UNLIKELY (!gst_bin_add (GST_BIN (self), self->sink))) {
+      GST_ERROR_OBJECT (self, "Can't add playsink to ourselves !");
+    }
+  }
 }
 
 GESTimelinePipeline *
@@ -79,3 +118,121 @@ ges_timeline_pipeline_new (void)
 {
   return g_object_new (GES_TYPE_TIMELINE_PIPELINE, NULL);
 }
+
+static GstStateChangeReturn
+ges_timeline_pipeline_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GESTimelinePipeline *self;
+  GstStateChangeReturn ret;
+
+  self = GES_TIMELINE_PIPELINE (element);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      if (G_UNLIKELY (self->timeline == NULL)) {
+        GST_ERROR_OBJECT (element,
+            "No GESTimeline set on the pipeline, cannot play !");
+        ret = GST_STATE_CHANGE_FAILURE;
+        goto done;
+      }
+      break;
+    default:
+      break;
+  }
+
+  ret =
+      GST_ELEMENT_CLASS (ges_timeline_pipeline_parent_class)->
+      change_state (element, transition);
+
+done:
+  return ret;
+}
+
+static void
+pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
+{
+  OutputChain *chain;
+  GESTrack *track;
+  const gchar *sinkpad_name;
+  GstPad *sinkpad;
+
+  GST_DEBUG_OBJECT (self, "new pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+
+  if (G_UNLIKELY (!(track =
+              ges_timeline_get_track_for_pad (self->timeline, pad)))) {
+    GST_WARNING_OBJECT (self, "Couldn't find coresponding track !");
+    return;
+  }
+
+  switch (track->type) {
+    case GES_TRACK_TYPE_VIDEO:
+      sinkpad_name = "video_sink";
+      break;
+    case GES_TRACK_TYPE_AUDIO:
+      sinkpad_name = "audio_sink";
+      break;
+    case GES_TRACK_TYPE_TEXT:
+      sinkpad_name = "text_sink";
+      break;
+    default:
+      GST_WARNING_OBJECT (self, "Can't handle tracks of type %d yet",
+          track->type);
+      return;
+  }
+
+  if (G_UNLIKELY (!(sinkpad =
+              gst_element_get_request_pad (self->sink, sinkpad_name)))) {
+    GST_WARNING_OBJECT (self, "Couldn't get a pad from the playsink !");
+    return;
+  }
+
+  if (G_UNLIKELY (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) {
+    GST_WARNING_OBJECT (self, "Couldn't link track pad to playsink");
+    gst_object_unref (sinkpad);
+    return;
+  }
+
+  /* Create a new chain */
+  chain = g_new0 (OutputChain, 1);
+  chain->pipeline = self;
+  chain->srcpad = pad;
+  chain->sinkpad = sinkpad;
+
+  self->chains = g_list_append (self->chains, chain);
+
+  /* Request a sinkpad from playsink */
+  GST_DEBUG ("done");
+}
+
+static void
+pad_removed_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self)
+{
+  GST_DEBUG ("pad %s:%s", GST_DEBUG_PAD_NAME (pad));
+
+  GST_DEBUG ("done");
+}
+
+
+gboolean
+ges_timeline_pipeline_add_timeline (GESTimelinePipeline * pipeline,
+    GESTimeline * timeline)
+{
+  g_return_val_if_fail (pipeline->timeline == NULL, FALSE);
+  g_return_val_if_fail (timeline != NULL, FALSE);
+
+  GST_DEBUG ("pipeline:%p, timeline:%p", timeline, pipeline);
+
+  if (G_UNLIKELY (!gst_bin_add (GST_BIN (pipeline), GST_ELEMENT (timeline)))) {
+    return FALSE;
+  }
+  pipeline->timeline = timeline;
+
+  /* Connect to pipeline */
+  g_signal_connect (timeline, "pad-added", (GCallback) pad_added_cb, pipeline);
+  g_signal_connect (timeline, "pad-removed", (GCallback) pad_removed_cb,
+      pipeline);
+
+  return TRUE;
+}
index 501dd2b..69e47cf 100644 (file)
@@ -44,6 +44,12 @@ G_BEGIN_DECLS
 
 struct _GESTimelinePipeline {
   GstPipeline parent;
+
+  /* <private> */
+  GESTimeline * timeline;
+  GstElement * sink;
+
+  GList *chains;
 };
 
 struct _GESTimelinePipelineClass {
@@ -54,6 +60,9 @@ GType ges_timeline_pipeline_get_type (void);
 
 GESTimelinePipeline* ges_timeline_pipeline_new (void);
 
+gboolean ges_timeline_pipeline_add_timeline (GESTimelinePipeline * pipeline,
+                                            GESTimeline * timeline);
+
 G_END_DECLS
 
 #endif /* _GES_TIMELINE_PIPELINE */