*
*/
+/* 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)
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);
}
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 *
{
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;
+}