* #encodebin:avoid-reencoding property set to %FALSE)
* @GES_PIPELINE_MODE_SMART_RENDER: Render the #GESPipeline:timeline,
* avoiding decoding/reencoding (the underlying #encodebin has its
- * #encodebin:avoid-reencoding property set to %TRUE)
+ * #encodebin:avoid-reencoding property set to %TRUE).
+ * > NOTE: Smart rendering can not work in tracks where #GESTrack:mixing
+ * > is enabled.
*
* The various modes a #GESPipeline can be configured to.
*/
ges_timeline_remove_clip (GESTimeline * timeline, GESClip * clip);
G_GNUC_INTERNAL void
+ges_timeline_set_smart_rendering (GESTimeline * timeline, gboolean rendering_smartly);
+
+G_GNUC_INTERNAL gboolean
+ges_timeline_get_smart_rendering (GESTimeline *timeline);
+
+G_GNUC_INTERNAL void
ges_auto_transition_set_previous_source (GESAutoTransition * self, GESTrackElement * source);
const gchar* bin_name,
GstElement* sub_element,
GPtrArray* elements);
+G_GNUC_INTERNAL void ges_source_set_rendering_smartly (GESSource *source,
+ gboolean rendering_smartly);
+G_GNUC_INTERNAL gboolean
+ges_source_get_rendering_smartly (GESSource *source);
+
+G_GNUC_INTERNAL void ges_track_set_smart_rendering (GESTrack* track, gboolean rendering_smartly);
G_GNUC_INTERNAL GstElement * ges_track_get_composition (GESTrack *track);
pipeline->priv->urisink, "sink", GST_PAD_LINK_CHECK_NOTHING);
}
+ if (pipeline->priv->timeline) {
+ ges_timeline_set_smart_rendering (pipeline->priv->timeline,
+ (mode & GES_PIPELINE_MODE_SMART_RENDER) != 0);
+ }
+
/* FIXUPS */
/* FIXME
* If we are rendering, set playsink to sync=False,
GstElement *last_converter;
GstPad *ghostpad;
+ gboolean is_rendering_smartly;
};
G_DEFINE_TYPE_WITH_PRIVATE (GESSource, ges_source, GES_TYPE_TRACK_ELEMENT);
static void
_set_ghost_pad_target (GESSource * self, GstPad * srcpad, GstElement * element)
{
- GESSourcePrivate *priv = self->priv;
- gboolean use_converter = FALSE;
GstPadLinkReturn link_return;
+ GESSourcePrivate *priv = self->priv;
+ gboolean use_converter = ! !priv->first_converter;
- if (priv->first_converter) {
+ if (use_converter && priv->is_rendering_smartly) {
GstPad *pad = gst_element_get_static_pad (priv->first_converter, "sink");
use_converter = gst_pad_can_link (srcpad, pad);
gst_object_unref (pad);
}
+void
+ges_source_set_rendering_smartly (GESSource * source,
+ gboolean is_rendering_smartly)
+{
+
+ if (is_rendering_smartly) {
+ GESTrack *track = ges_track_element_get_track (GES_TRACK_ELEMENT (source));
+
+ if (track && ges_track_get_mixing (track)) {
+ GST_DEBUG_OBJECT (source, "Not rendering smartly as track is mixing!");
+
+ source->priv->is_rendering_smartly = FALSE;
+ return;
+ }
+ }
+ source->priv->is_rendering_smartly = is_rendering_smartly;
+}
+
+gboolean
+ges_source_get_rendering_smartly (GESSource * source)
+{
+ return source->priv->is_rendering_smartly;
+}
+
static void
ges_source_dispose (GObject * object)
{
g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_LEAFS, -1,
(GNodeTraverseFunc) reset_layer_activness, layer);
}
+
+static gboolean
+set_is_smart_rendering (GNode * node, gboolean * is_rendering_smartly)
+{
+ if (!GES_IS_SOURCE (node->data))
+ return FALSE;
+
+ ges_source_set_rendering_smartly (GES_SOURCE (node->data),
+ *is_rendering_smartly);
+ return FALSE;
+}
+
+void
+timeline_tree_set_smart_rendering (GNode * root, gboolean rendering_smartly)
+{
+ g_node_traverse (root, G_PRE_ORDER, G_TRAVERSE_LEAFS, -1,
+ (GNodeTraverseFunc) set_is_smart_rendering, &rendering_smartly);
+}
timeline_update_duration (GESTimeline * timeline);
void timeline_tree_reset_layer_active (GNode *root, GESLayer *layer);
+void timeline_tree_set_smart_rendering (GNode * root, gboolean rendering_smartly);
void timeline_tree_init_debug (void);
gboolean disposed;
GstStreamCollection *stream_collection;
+
+ gboolean rendering_smartly;
};
/* private structure to contain our track-related information */
ges_timeline_element_get_name (element), gst_object_ref (element));
timeline_tree_track_element (timeline->priv->tree, element);
+ if (GES_IS_SOURCE (element)) {
+ ges_source_set_rendering_smartly (GES_SOURCE (element),
+ timeline->priv->rendering_smartly);
+ }
return TRUE;
}
return timeline->priv->tree;
}
+void
+ges_timeline_set_smart_rendering (GESTimeline * timeline,
+ gboolean rendering_smartly)
+{
+ if (rendering_smartly) {
+ GList *tmp;
+
+ for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
+ if (ges_track_get_mixing (tmp->data)) {
+ GST_INFO_OBJECT (timeline, "Smart rendering will not"
+ " work as track %" GST_PTR_FORMAT " is doing mixing", tmp->data);
+ } else {
+ ges_track_set_smart_rendering (tmp->data, rendering_smartly);
+ }
+ }
+ }
+ timeline_tree_set_smart_rendering (timeline->priv->tree, rendering_smartly);
+ timeline->priv->rendering_smartly = rendering_smartly;
+}
+
+gboolean
+ges_timeline_get_smart_rendering (GESTimeline * timeline)
+{
+ return timeline->priv->rendering_smartly;
+}
+
/**** API *****/
/**
* ges_timeline_new:
return track->priv->composition;
}
+void
+ges_track_set_smart_rendering (GESTrack * track, gboolean rendering_smartly)
+{
+ GESTrackPrivate *priv = track->priv;
+
+ g_object_set (priv->capsfilter, "caps",
+ rendering_smartly ? NULL : priv->restriction_caps, NULL);
+}
+
/* FIXME: Find out how to avoid doing this "hack" using the GDestroyNotify
* function pointer in the trackelements_by_start GSequence
*
* @caps: The new restriction-caps for @track
*
* Sets the #GESTrack:restriction-caps for the track.
+ *
+ * > **NOTE**: Restriction caps are **not** taken into account when
+ * > using #GESPipeline:mode=#GES_PIPELINE_MODE_SMART_RENDER.
*/
void
ges_track_set_restriction_caps (GESTrack * track, const GstCaps * caps)
gst_caps_unref (priv->restriction_caps);
priv->restriction_caps = gst_caps_copy (caps);
- g_object_set (priv->capsfilter, "caps", caps, NULL);
+ if (!track->priv->timeline ||
+ !ges_timeline_get_smart_rendering (track->priv->timeline))
+ g_object_set (priv->capsfilter, "caps", caps, NULL);
g_object_notify (G_OBJECT (track), "restriction-caps");
}
notify:
track->priv->mixing = mixing;
+ if (track->priv->timeline)
+ ges_timeline_set_smart_rendering (track->priv->timeline,
+ ges_timeline_get_smart_rendering (track->priv->timeline));
g_object_notify_by_pspec (G_OBJECT (track), properties[ARG_MIXING]);
GST_DEBUG_OBJECT (track, "The track has been set to mixing = %d", mixing);
#undef GST_CAT_DEFAULT
#define GST_CAT_DEFAULT uri_source_debug
+typedef enum
+{
+ GST_AUTOPLUG_SELECT_TRY,
+ GST_AUTOPLUG_SELECT_EXPOSE,
+ GST_AUTOPLUG_SELECT_SKIP,
+} GstAutoplugSelectResult;
+
+static gint
+autoplug_select_cb (GstElement * bin, GstPad * pad, GstCaps * caps,
+ GstElementFactory * factory, GESUriSource * self)
+{
+ GstElement *nlesrc;
+ GstCaps *downstream_caps;
+ GstAutoplugSelectResult res = GST_AUTOPLUG_SELECT_TRY;
+
+ if (!ges_source_get_rendering_smartly (GES_SOURCE (self->element))) {
+ GST_LOG_OBJECT (self->element, "Not being smart here");
+ return res;
+ }
+
+ nlesrc = ges_track_element_get_nleobject (self->element);
+ downstream_caps = gst_pad_peer_query_caps (nlesrc->srcpads->data, NULL);
+ if (downstream_caps && gst_caps_can_intersect (downstream_caps, caps)) {
+ GST_DEBUG_OBJECT (self, "Exposing %s", GST_OBJECT_NAME (factory));
+ res = GST_AUTOPLUG_SELECT_EXPOSE;
+ }
+ gst_clear_caps (&downstream_caps);
+
+ return res;
+}
GstElement *
ges_uri_source_create_source (GESUriSource * self)
g_object_set (decodebin, "caps", caps,
"expose-all-streams", FALSE, "uri", self->uri, NULL);
+ g_signal_connect (decodebin, "autoplug-select",
+ G_CALLBACK (autoplug_select_cb), self);
return decodebin;