Port to the new NLE API

Port the timeline, track and pipeline to the new NLE API where
all objects have static src pads.
This commit is contained in:
Thibault Saunier 2014-10-21 10:59:43 +02:00
parent 11f9c6e108
commit b3336fe26e
3 changed files with 110 additions and 145 deletions

View file

@ -37,6 +37,10 @@
#include "ges-audio-track.h"
#include "ges-video-track.h"
GST_DEBUG_CATEGORY_STATIC (ges_pipeline_debug);
#undef GST_CAT_DEFAULT
#define GST_CAT_DEFAULT ges_pipeline_debug
#define DEFAULT_TIMELINE_MODE GES_PIPELINE_MODE_PREVIEW
/* Structure corresponding to a timeline - sink link */
@ -48,8 +52,6 @@ typedef struct
GstPad *srcpad; /* Timeline source pad */
GstPad *playsinkpad;
GstPad *encodebinpad;
GstPad *blocked_pad;
gulong probe_id;
} OutputChain;
@ -88,6 +90,8 @@ static OutputChain *get_output_chain_for_track (GESPipeline * self,
GESTrack * track);
static OutputChain *new_output_chain_for_track (GESPipeline * self,
GESTrack * track);
static void _link_track (GESPipeline * self, GESTrack * track);
static void _unlink_track (GESPipeline * self, GESTrack * track);
/****************************************************
* Video Overlay vmethods implementation *
@ -234,6 +238,9 @@ ges_pipeline_class_init (GESPipelineClass * klass)
g_type_class_add_private (klass, sizeof (GESPipelinePrivate));
GST_DEBUG_CATEGORY_INIT (ges_pipeline_debug, "gespipeline",
GST_DEBUG_FG_YELLOW, "ges pipeline");
object_class->dispose = ges_pipeline_dispose;
object_class->get_property = ges_pipeline_get_property;
object_class->set_property = ges_pipeline_set_property;
@ -434,6 +441,39 @@ done:
return TRUE;
}
static void
_link_tracks (GESPipeline * pipeline)
{
GList *tmp;
GST_DEBUG_OBJECT (pipeline, "Linking tracks");
if (!pipeline->priv->timeline) {
GST_INFO_OBJECT (pipeline, "Not timeline set yet, doing nothing");
return;
}
for (tmp = pipeline->priv->timeline->tracks; tmp; tmp = tmp->next)
_link_track (pipeline, tmp->data);
}
static void
_unlink_tracks (GESPipeline * pipeline)
{
GList *tmp;
GST_DEBUG_OBJECT (pipeline, "Disconnecting all tracks");
if (!pipeline->priv->timeline) {
GST_INFO_OBJECT (pipeline, "Not timeline set yet, doing nothing");
return;
}
for (tmp = pipeline->priv->timeline->tracks; tmp; tmp = tmp->next)
_unlink_track (pipeline, tmp->data);
}
static GstStateChangeReturn
ges_pipeline_change_state (GstElement * element, GstStateChange transition)
{
@ -453,12 +493,13 @@ ges_pipeline_change_state (GstElement * element, GstStateChange transition)
if (self->priv->mode & (GES_PIPELINE_MODE_RENDER |
GES_PIPELINE_MODE_SMART_RENDER))
GST_DEBUG ("rendering => Updating pipeline caps");
/* Set caps on all tracks according to profile if present */
if (!ges_pipeline_update_caps (self)) {
GST_ERROR_OBJECT (element, "Error setting the caps for rendering");
ret = GST_STATE_CHANGE_FAILURE;
goto done;
}
/* Set caps on all tracks according to profile if present */
_link_tracks (self);
break;
default:
break;
@ -468,6 +509,14 @@ ges_pipeline_change_state (GstElement * element, GstStateChange transition)
GST_ELEMENT_CLASS (ges_pipeline_parent_class)->change_state
(element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
_unlink_tracks (self);
break;
default:
break;
}
done:
return ret;
}
@ -500,25 +549,21 @@ get_output_chain_for_track (GESPipeline * self, GESTrack * track)
/* Fetches a compatible pad on the target element which isn't already
* linked */
static GstPad *
get_compatible_unlinked_pad (GstElement * element, GstPad * pad)
get_compatible_unlinked_pad (GstElement * element, GESTrack * track)
{
GstPad *res = NULL;
GstIterator *pads;
gboolean done = FALSE;
GstCaps *srccaps;
const GstCaps *srccaps;
GValue paditem = { 0, };
if (G_UNLIKELY (pad == NULL))
goto no_pad;
if (G_UNLIKELY (track == NULL))
goto no_track;
GST_DEBUG ("element : %s, pad %s:%s",
GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));
GST_DEBUG_OBJECT (element, " track %" GST_PTR_FORMAT, track);
if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC)
pads = gst_element_iterate_sink_pads (element);
else
pads = gst_element_iterate_src_pads (element);
srccaps = gst_pad_query_caps (pad, NULL);
pads = gst_element_iterate_sink_pads (element);
srccaps = ges_track_get_caps (track);
GST_DEBUG ("srccaps %" GST_PTR_FORMAT, srccaps);
@ -553,34 +598,27 @@ get_compatible_unlinked_pad (GstElement * element, GstPad * pad)
}
g_value_reset (&paditem);
gst_iterator_free (pads);
gst_caps_unref (srccaps);
return res;
no_pad:
no_track:
{
GST_ERROR ("No pad to check against");
GST_ERROR ("No track to check against");
return NULL;
}
}
static GstPadProbeReturn
pad_blocked (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
/* no nothing */
GST_DEBUG_OBJECT (pad, "blocked callback, blocked");
return GST_PAD_PROBE_OK;
}
static void
pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
_link_track (GESPipeline * self, GESTrack * track)
{
GstPad *pad;
OutputChain *chain;
GESTrack *track;
GstPad *sinkpad;
GstCaps *caps;
GstPadLinkReturn lret;
gboolean reconfigured = FALSE;
pad = ges_timeline_get_pad_for_track (self->priv->timeline, track);
caps = gst_pad_query_caps (pad, NULL);
GST_DEBUG_OBJECT (self, "new pad %s:%s , caps:%" GST_PTR_FORMAT,
@ -588,8 +626,6 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
gst_caps_unref (caps);
track = ges_timeline_get_track_for_pad (self->priv->timeline, pad);
if (G_UNLIKELY (!track)) {
GST_WARNING_OBJECT (self, "Couldn't find coresponding track !");
return;
@ -613,15 +649,23 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
if (!(chain = get_output_chain_for_track (self, track)))
chain = new_output_chain_for_track (self, track);
chain->srcpad = pad;
gst_object_unref (pad);
/* Adding tee */
chain->tee = gst_element_factory_make ("tee", NULL);
gst_bin_add (GST_BIN_CAST (self), chain->tee);
gst_element_sync_state_with_parent (chain->tee);
if (!chain->tee) {
chain->tee = gst_element_factory_make ("tee", NULL);
gst_bin_add (GST_BIN_CAST (self), chain->tee);
gst_element_sync_state_with_parent (chain->tee);
}
/* Linking pad to tee */
sinkpad = gst_element_get_static_pad (chain->tee, "sink");
gst_pad_link_full (pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING);
lret = gst_pad_link (pad, sinkpad);
if (lret != GST_PAD_LINK_OK) {
GST_ERROR_OBJECT (self, "Could not link the tee (%i)", lret);
goto error;
}
gst_object_unref (sinkpad);
/* Connect playsink */
@ -658,14 +702,10 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
tmppad = gst_element_get_request_pad (chain->tee, "src_%u");
if (G_UNLIKELY (gst_pad_link_full (tmppad, sinkpad,
GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) {
GST_ERROR_OBJECT (self, "Couldn't link track pad to playsink");
GST_ERROR_OBJECT (self, "Couldn't link track pad to encodebin");
gst_object_unref (tmppad);
goto error;
}
chain->blocked_pad = tmppad;
GST_DEBUG_OBJECT (tmppad, "blocking pad");
chain->probe_id = gst_pad_add_probe (tmppad,
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, pad_blocked, NULL, NULL);
GST_DEBUG ("Reconfiguring playsink");
@ -685,7 +725,7 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
if (!chain->encodebinpad) {
/* Check for unused static pads */
sinkpad = get_compatible_unlinked_pad (self->priv->encodebin, pad);
sinkpad = get_compatible_unlinked_pad (self->priv->encodebin, track);
if (sinkpad == NULL) {
GstCaps *caps = gst_pad_query_caps (pad, NULL);
@ -704,10 +744,9 @@ pad_added_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
}
tmppad = gst_element_get_request_pad (chain->tee, "src_%u");
if (G_UNLIKELY (gst_pad_link_full (tmppad,
chain->encodebinpad,
if (G_UNLIKELY (gst_pad_link_full (tmppad, chain->encodebinpad,
GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) {
GST_WARNING_OBJECT (self, "Couldn't link track pad to playsink");
GST_ERROR_OBJECT (self, "Couldn't link track pad to encodebin");
goto error;
}
gst_object_unref (tmppad);
@ -733,25 +772,19 @@ error:
}
static void
pad_removed_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
_unlink_track (GESPipeline * self, GESTrack * track)
{
OutputChain *chain;
GESTrack *track;
GstPad *peer;
GstPad *pad, *peer;
GST_DEBUG_OBJECT (self, "pad removed %s:%s", GST_DEBUG_PAD_NAME (pad));
if (G_UNLIKELY (!(track =
ges_timeline_get_track_for_pad (self->priv->timeline, pad)))) {
GST_WARNING_OBJECT (self, "Couldn't find coresponding track !");
return;
}
GST_DEBUG_OBJECT (self, "Unlinking removed %" GST_PTR_FORMAT, track);
if (G_UNLIKELY (!(chain = get_output_chain_for_track (self, track)))) {
GST_DEBUG_OBJECT (self, "Pad wasn't used");
GST_DEBUG_OBJECT (self, "Track wasn't used");
return;
}
pad = ges_timeline_get_pad_for_track (self->priv->timeline, track);
/* Unlink encodebin */
if (chain->encodebinpad) {
peer = gst_pad_get_peer (chain->encodebinpad);
@ -771,14 +804,6 @@ pad_removed_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
gst_object_unref (chain->playsinkpad);
}
if (chain->blocked_pad) {
GST_DEBUG_OBJECT (chain->blocked_pad, "unblocking pad");
gst_pad_remove_probe (chain->blocked_pad, chain->probe_id);
gst_object_unref (chain->blocked_pad);
chain->blocked_pad = NULL;
chain->probe_id = 0;
}
/* Unlike/remove tee */
peer = gst_element_get_static_pad (chain->tee, "sink");
gst_pad_unlink (pad, peer);
@ -788,29 +813,11 @@ pad_removed_cb (GstElement * timeline, GstPad * pad, GESPipeline * self)
self->priv->chains = g_list_remove (self->priv->chains, chain);
g_free (chain);
gst_object_unref (pad);
GST_DEBUG ("done");
}
static void
no_more_pads_cb (GstElement * timeline, GESPipeline * self)
{
GList *tmp;
GST_DEBUG ("received no-more-pads");
for (tmp = self->priv->chains; tmp; tmp = g_list_next (tmp)) {
OutputChain *chain = (OutputChain *) tmp->data;
if (chain->blocked_pad) {
GST_DEBUG_OBJECT (chain->blocked_pad, "unblocking pad");
gst_pad_remove_probe (chain->blocked_pad, chain->probe_id);
gst_object_unref (chain->blocked_pad);
chain->blocked_pad = NULL;
chain->probe_id = 0;
}
}
}
/**
* ges_pipeline_set_timeline:
* @pipeline: a #GESPipeline
@ -826,6 +833,7 @@ no_more_pads_cb (GstElement * timeline, GESPipeline * self)
gboolean
ges_pipeline_set_timeline (GESPipeline * pipeline, GESTimeline * timeline)
{
g_return_val_if_fail (GES_IS_PIPELINE (pipeline), FALSE);
g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
g_return_val_if_fail (pipeline->priv->timeline == NULL, FALSE);
@ -838,13 +846,6 @@ ges_pipeline_set_timeline (GESPipeline * pipeline, GESTimeline * timeline)
}
pipeline->priv->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);
g_signal_connect (timeline, "no-more-pads", (GCallback) no_more_pads_cb,
pipeline);
/* FIXME Check if we should rollback if we can't sync state */
gst_element_sync_state_with_parent (GST_ELEMENT (timeline));

View file

@ -2400,19 +2400,18 @@ _pad_probe_cb (GstPad * mixer_pad, GstPadProbeInfo * info,
}
static void
pad_added_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
_ghost_track_srcpad (TrackPrivate * tr_priv)
{
GstPad *pad;
gchar *padname;
gboolean no_more;
GList *tmp;
GESTrack *track = tr_priv->track;
pad = gst_element_get_static_pad (GST_ELEMENT (track), "src");
GST_DEBUG ("track:%p, pad:%s:%s", track, GST_DEBUG_PAD_NAME (pad));
if (G_UNLIKELY (tr_priv->pad)) {
GST_WARNING ("We are already controlling a pad for this track");
return;
}
/* Remember the pad */
LOCK_DYN (tr_priv->timeline);
GST_OBJECT_LOCK (track);
@ -2449,28 +2448,6 @@ pad_added_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
UNLOCK_DYN (tr_priv->timeline);
}
static void
pad_removed_cb (GESTrack * track, GstPad * pad, TrackPrivate * tr_priv)
{
GST_DEBUG ("track:%p, pad:%s:%s", track, GST_DEBUG_PAD_NAME (pad));
if (G_UNLIKELY (tr_priv->pad != pad)) {
GST_WARNING ("Not the pad we're controlling");
return;
}
if (G_UNLIKELY (tr_priv->ghostpad == NULL)) {
GST_WARNING ("We don't have a ghostpad for this pad !");
return;
}
GST_DEBUG ("Removing ghostpad");
gst_pad_set_active (tr_priv->ghostpad, FALSE);
gst_element_remove_pad (GST_ELEMENT (tr_priv->timeline), tr_priv->ghostpad);
tr_priv->ghostpad = NULL;
tr_priv->pad = NULL;
}
gboolean
timeline_add_element (GESTimeline * timeline, GESTimelineElement * element)
{
@ -2809,10 +2786,6 @@ ges_timeline_add_track (GESTimeline * timeline, GESTrack * track)
UNLOCK_DYN (timeline);
timeline->tracks = g_list_append (timeline->tracks, track);
/* Listen to pad-added/-removed */
g_signal_connect (track, "pad-added", (GCallback) pad_added_cb, tr_priv);
g_signal_connect (track, "pad-removed", (GCallback) pad_removed_cb, tr_priv);
/* Inform the track that it's currently being used by ourself */
ges_track_set_timeline (track, timeline);
@ -2843,6 +2816,8 @@ ges_timeline_add_track (GESTimeline * timeline, GESTrack * track)
g_list_free (objects);
}
_ghost_track_srcpad (tr_priv);
/* FIXME Check if we should rollback if we can't sync state */
gst_element_sync_state_with_parent (GST_ELEMENT (track));
g_object_set (track, "message-forward", TRUE, NULL);
@ -2904,8 +2879,6 @@ ges_timeline_remove_track (GESTimeline * timeline, GESTrack * track)
}
/* Remove pad-added/-removed handlers */
g_signal_handlers_disconnect_by_func (track, pad_added_cb, tr_priv);
g_signal_handlers_disconnect_by_func (track, pad_removed_cb, tr_priv);
g_signal_handlers_disconnect_by_func (track, track_element_added_cb,
timeline);
g_signal_handlers_disconnect_by_func (track, track_element_removed_cb,

View file

@ -37,6 +37,12 @@
G_DEFINE_TYPE_WITH_CODE (GESTrack, ges_track, GST_TYPE_BIN,
G_IMPLEMENT_INTERFACE (GES_TYPE_META_CONTAINER, NULL));
static GstStaticPadTemplate ges_track_src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
/* Structure that represents gaps and keep knowledge
* of the gaps filled in the track */
typedef struct
@ -92,9 +98,6 @@ static guint ges_track_signals[LAST_SIGNAL] = { 0 };
static GParamSpec *properties[ARG_LAST];
static void pad_added_cb (GstElement * element, GstPad * pad, GESTrack * track);
static void
pad_removed_cb (GstElement * element, GstPad * pad, GESTrack * track);
static void composition_duration_cb (GstElement * composition, GParamSpec * arg
G_GNUC_UNUSED, GESTrack * obj);
@ -256,9 +259,10 @@ sort_track_elements_cb (GESTrackElement * child,
static void
_ghost_nlecomposition_srcpad (GESTrack * track)
{
GESTrackPrivate *priv = track->priv;
GstPad *capsfilter_sink;
GstPad *capsfilter_src;
GESTrackPrivate *priv = track->priv;
GstPad *pad = gst_element_get_static_pad (priv->composition, "src");
capsfilter_sink = gst_element_get_static_pad (priv->capsfilter, "sink");
@ -277,22 +281,6 @@ _ghost_nlecomposition_srcpad (GESTrack * track)
GST_DEBUG ("done");
}
static void
pad_removed_cb (GstElement * element, GstPad * pad, GESTrack * track)
{
GESTrackPrivate *priv = track->priv;
GST_DEBUG ("track:%p, pad %s:%s", track, GST_DEBUG_PAD_NAME (pad));
if (G_LIKELY (priv->srcpad)) {
gst_pad_set_active (priv->srcpad, FALSE);
gst_element_remove_pad (GST_ELEMENT (track), priv->srcpad);
priv->srcpad = NULL;
}
GST_DEBUG ("done");
}
static void
composition_duration_cb (GstElement * composition,
GParamSpec * arg G_GNUC_UNUSED, GESTrack * track)
@ -423,6 +411,7 @@ ges_track_dispose (GObject * object)
{
GESTrack *track = (GESTrack *) object;
GESTrackPrivate *priv = track->priv;
gboolean ret;
/* Remove all TrackElements and drop our reference */
g_hash_table_unref (priv->trackelements_iter);
@ -430,11 +419,13 @@ ges_track_dispose (GObject * object)
(GFunc) dispose_trackelements_foreach, track);
g_sequence_free (priv->trackelements_by_start);
g_list_free_full (priv->gaps, (GDestroyNotify) free_gap);
g_signal_emit_by_name (track->priv->composition, "commit", TRUE, &ret);
if (priv->mixing_operation)
gst_object_unref (priv->mixing_operation);
if (priv->composition) {
gst_element_remove_pad (GST_ELEMENT (track), priv->srcpad);
gst_bin_remove (GST_BIN (object), priv->composition);
priv->composition = NULL;
}
@ -508,6 +499,7 @@ static void
ges_track_class_init (GESTrackClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *gstelement_class = (GstElementClass *) klass;
g_type_class_add_private (klass, sizeof (GESTrackPrivate));
@ -586,6 +578,9 @@ ges_track_class_init (GESTrackClass * klass)
g_object_class_install_property (object_class, ARG_MIXING,
properties[ARG_MIXING]);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&ges_track_src_pad_template));
/**
* GESTrack::track-element-added:
* @object: the #GESTrack
@ -632,10 +627,6 @@ ges_track_init (GESTrack * self)
g_signal_connect (G_OBJECT (self->priv->composition), "notify::duration",
G_CALLBACK (composition_duration_cb), self);
g_signal_connect (self->priv->composition, "pad-added",
(GCallback) pad_added_cb, self);
g_signal_connect (self->priv->composition, "pad-removed",
(GCallback) pad_removed_cb, self);
}
/**