GESTimelinePipeline: Use 'playsink', track added/removed pads.

Also add a method to set a GESTimeline on the pipeline.
This commit is contained in:
Edward Hervey 2009-09-08 19:45:08 +02:00
parent 416323c649
commit de31b79ee4
2 changed files with 166 additions and 0 deletions

View file

@ -24,8 +24,20 @@
*
*/
/* 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;
}

View 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 */