mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
Implement and use the GstStream API
This commit is contained in:
parent
5be359cf7f
commit
5ea4667be6
5 changed files with 170 additions and 11 deletions
|
@ -135,6 +135,8 @@ struct _GESTimelinePrivate
|
|||
GCond commited_cond;
|
||||
|
||||
GThread *valid_thread;
|
||||
|
||||
GstStreamCollection *stream_collection;
|
||||
};
|
||||
|
||||
/* private structure to contain our track-related information */
|
||||
|
@ -147,6 +149,7 @@ typedef struct
|
|||
GstPad *ghostpad;
|
||||
|
||||
gulong probe_id;
|
||||
GstStream *stream;
|
||||
} TrackPrivate;
|
||||
|
||||
enum
|
||||
|
@ -302,6 +305,7 @@ ges_timeline_dispose (GObject * object)
|
|||
g_list_free_full (priv->auto_transitions, gst_object_unref);
|
||||
|
||||
g_hash_table_unref (priv->all_elements);
|
||||
gst_object_unref (priv->stream_collection);
|
||||
|
||||
G_OBJECT_CLASS (ges_timeline_parent_class)->dispose (object);
|
||||
}
|
||||
|
@ -374,6 +378,63 @@ forward:
|
|||
gst_element_post_message (GST_ELEMENT_CAST (bin), message);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
ges_timeline_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn res;
|
||||
GESTimeline *timeline = GES_TIMELINE (element);
|
||||
|
||||
res = GST_ELEMENT_CLASS (ges_timeline_parent_class)->change_state (element,
|
||||
transition);
|
||||
|
||||
if (transition == GST_STATE_CHANGE_READY_TO_PAUSED)
|
||||
gst_element_post_message ((GstElement *) timeline,
|
||||
gst_message_new_stream_collection ((GstObject *) timeline,
|
||||
timeline->priv->stream_collection));
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ges_timeline_send_event (GstElement * element, GstEvent * event)
|
||||
{
|
||||
GESTimeline *timeline = GES_TIMELINE (element);
|
||||
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_SELECT_STREAMS) {
|
||||
GList *stream_ids = NULL, *tmp, *to_remove =
|
||||
ges_timeline_get_tracks (timeline);
|
||||
|
||||
gst_event_parse_select_streams (event, &stream_ids);
|
||||
for (tmp = stream_ids; tmp; tmp = tmp->next) {
|
||||
GList *trackit;
|
||||
gchar *stream_id = tmp->data;
|
||||
|
||||
LOCK_DYN (timeline);
|
||||
for (trackit = timeline->priv->priv_tracks; trackit;
|
||||
trackit = trackit->next) {
|
||||
TrackPrivate *tr_priv = trackit->data;
|
||||
|
||||
if (!g_strcmp0 (gst_stream_get_stream_id (tr_priv->stream), stream_id)) {
|
||||
to_remove = g_list_remove (to_remove, tr_priv->track);
|
||||
}
|
||||
}
|
||||
UNLOCK_DYN (timeline);
|
||||
}
|
||||
for (tmp = to_remove; tmp; tmp = tmp->next) {
|
||||
GST_INFO_OBJECT (timeline, "Removed unselected track: %" GST_PTR_FORMAT,
|
||||
tmp->data);
|
||||
ges_timeline_remove_track (timeline, tmp->data);
|
||||
}
|
||||
|
||||
g_list_free_full (stream_ids, g_free);
|
||||
g_list_free (to_remove);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return GST_ELEMENT_CLASS (ges_timeline_parent_class)->send_event (element,
|
||||
event);
|
||||
}
|
||||
|
||||
/* we collect the first result */
|
||||
static gboolean
|
||||
_gst_array_accumulator (GSignalInvocationHint * ihint,
|
||||
|
@ -392,6 +453,7 @@ static void
|
|||
ges_timeline_class_init (GESTimelineClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *element_class = (GstElementClass *) klass;
|
||||
GstBinClass *bin_class = GST_BIN_CLASS (klass);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (ges_timeline_debug, "gestimeline",
|
||||
|
@ -405,6 +467,9 @@ ges_timeline_class_init (GESTimelineClass * klass)
|
|||
object_class->dispose = ges_timeline_dispose;
|
||||
object_class->finalize = ges_timeline_finalize;
|
||||
|
||||
element_class->change_state = GST_DEBUG_FUNCPTR (ges_timeline_change_state);
|
||||
element_class->send_event = GST_DEBUG_FUNCPTR (ges_timeline_send_event);
|
||||
|
||||
bin_class->handle_message = GST_DEBUG_FUNCPTR (ges_timeline_handle_message);
|
||||
|
||||
/**
|
||||
|
@ -597,6 +662,7 @@ ges_timeline_init (GESTimeline * self)
|
|||
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, gst_object_unref);
|
||||
|
||||
priv->stream_start_group_id = -1;
|
||||
priv->stream_collection = gst_stream_collection_new (NULL);
|
||||
|
||||
g_signal_connect_after (self, "select-tracks-for-object",
|
||||
G_CALLBACK (select_tracks_for_object_default), NULL);
|
||||
|
@ -1405,6 +1471,34 @@ layer_object_removed_cb (GESLayer * layer, GESClip * clip,
|
|||
GST_DEBUG ("Done");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_stream_object (TrackPrivate * tr_priv)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
GstStreamType type = GST_STREAM_TYPE_UNKNOWN;
|
||||
gchar *stream_id;
|
||||
|
||||
g_object_get (tr_priv->track, "id", &stream_id, NULL);
|
||||
if (tr_priv->track->type == GES_TRACK_TYPE_VIDEO)
|
||||
type = GST_STREAM_TYPE_VIDEO;
|
||||
if (tr_priv->track->type == GES_TRACK_TYPE_AUDIO)
|
||||
type = GST_STREAM_TYPE_AUDIO;
|
||||
|
||||
if (!tr_priv->stream ||
|
||||
g_strcmp0 (stream_id, gst_stream_get_stream_id (tr_priv->stream))) {
|
||||
res = TRUE;
|
||||
gst_object_replace ((GstObject **) & tr_priv->stream,
|
||||
(GstObject *) gst_stream_new (stream_id,
|
||||
(GstCaps *) ges_track_get_caps (tr_priv->track),
|
||||
type, GST_STREAM_FLAG_NONE)
|
||||
);
|
||||
}
|
||||
|
||||
g_free (stream_id);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
trackelement_start_changed_cb (GESTrackElement * child,
|
||||
GParamSpec * arg G_GNUC_UNUSED, GESTimeline * timeline)
|
||||
|
@ -1436,7 +1530,6 @@ _pad_probe_cb (GstPad * mixer_pad, GstPadProbeInfo * info,
|
|||
{
|
||||
GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
|
||||
GESTimeline *timeline = tr_priv->timeline;
|
||||
gchar *stream_id;
|
||||
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START) {
|
||||
LOCK_DYN (timeline);
|
||||
|
@ -1447,10 +1540,10 @@ _pad_probe_cb (GstPad * mixer_pad, GstPadProbeInfo * info,
|
|||
}
|
||||
|
||||
gst_event_unref (event);
|
||||
g_object_get (tr_priv->track, "id", &stream_id, NULL);
|
||||
info->data = gst_event_new_stream_start (stream_id);
|
||||
gst_event_set_group_id (GST_PAD_PROBE_INFO_EVENT (info),
|
||||
timeline->priv->stream_start_group_id);
|
||||
event = info->data =
|
||||
gst_event_new_stream_start (gst_stream_get_stream_id (tr_priv->stream));
|
||||
gst_event_set_stream (event, tr_priv->stream);
|
||||
gst_event_set_group_id (event, timeline->priv->stream_start_group_id);
|
||||
UNLOCK_DYN (timeline);
|
||||
|
||||
return GST_PAD_PROBE_REMOVE;
|
||||
|
@ -1898,6 +1991,10 @@ ges_timeline_add_track (GESTimeline * timeline, GESTrack * track)
|
|||
tr_priv->timeline = timeline;
|
||||
tr_priv->track = track;
|
||||
|
||||
update_stream_object (tr_priv);
|
||||
gst_stream_collection_add_stream (timeline->priv->stream_collection,
|
||||
gst_object_ref (tr_priv->stream));
|
||||
|
||||
/* Add the track to the list of tracks we track */
|
||||
LOCK_DYN (timeline);
|
||||
timeline->priv->priv_tracks = g_list_append (timeline->priv->priv_tracks,
|
||||
|
@ -2174,12 +2271,24 @@ ges_timeline_commit_unlocked (GESTimeline * timeline)
|
|||
if (timeline->priv->expected_commited == 0) {
|
||||
g_signal_emit (timeline, ges_timeline_signals[COMMITED], 0);
|
||||
} else {
|
||||
GstStreamCollection *collection = gst_stream_collection_new (NULL);
|
||||
|
||||
for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
|
||||
TrackPrivate *tr_priv =
|
||||
g_list_find_custom (timeline->priv->priv_tracks, tmp->data,
|
||||
(GCompareFunc) custom_find_track)->data;
|
||||
|
||||
update_stream_object (tr_priv);
|
||||
gst_stream_collection_add_stream (collection,
|
||||
gst_object_ref (tr_priv->stream));
|
||||
g_signal_connect (tmp->data, "commited", G_CALLBACK (track_commited_cb),
|
||||
timeline);
|
||||
if (!ges_track_commit (GES_TRACK (tmp->data)))
|
||||
res = FALSE;
|
||||
}
|
||||
|
||||
gst_object_unref (timeline->priv->stream_collection);
|
||||
timeline->priv->stream_collection = collection;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -2218,6 +2327,7 @@ gboolean
|
|||
ges_timeline_commit (GESTimeline * timeline)
|
||||
{
|
||||
gboolean ret;
|
||||
GstStreamCollection *pcollection = timeline->priv->stream_collection;
|
||||
|
||||
g_return_val_if_fail (GES_IS_TIMELINE (timeline), FALSE);
|
||||
|
||||
|
@ -2225,6 +2335,12 @@ ges_timeline_commit (GESTimeline * timeline)
|
|||
ret = ges_timeline_commit_unlocked (timeline);
|
||||
UNLOCK_DYN (timeline);
|
||||
|
||||
if (pcollection != timeline->priv->stream_collection) {
|
||||
gst_element_post_message ((GstElement *) timeline,
|
||||
gst_message_new_stream_collection ((GstObject *) timeline,
|
||||
timeline->priv->stream_collection));
|
||||
}
|
||||
|
||||
ges_timeline_emit_snapping (timeline, NULL, NULL, GST_CLOCK_TIME_NONE);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -402,6 +402,43 @@ ges_track_change_state (GstElement * element, GstStateChange transition)
|
|||
transition);
|
||||
}
|
||||
|
||||
static void
|
||||
ges_track_handle_message (GstBin * bin, GstMessage * message)
|
||||
{
|
||||
GESTrack *track = GES_TRACK (bin);
|
||||
|
||||
if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STREAM_COLLECTION) {
|
||||
gint i;
|
||||
GList *selected_streams = NULL;
|
||||
GstStreamCollection *collection;
|
||||
|
||||
gst_message_parse_stream_collection (message, &collection);
|
||||
|
||||
for (i = 0; i < gst_stream_collection_get_size (collection); i++) {
|
||||
GstStream *stream = gst_stream_collection_get_stream (collection, i);
|
||||
GstStreamType stype = gst_stream_get_stream_type (stream);
|
||||
|
||||
if ((track->type == GES_TRACK_TYPE_VIDEO
|
||||
&& stype == GST_STREAM_TYPE_VIDEO)
|
||||
|| (track->type == GES_TRACK_TYPE_AUDIO
|
||||
&& stype == GST_STREAM_TYPE_AUDIO)
|
||||
|| (stype == GST_STREAM_TYPE_UNKNOWN)) {
|
||||
|
||||
selected_streams =
|
||||
g_list_append (selected_streams,
|
||||
(gchar *) gst_stream_get_stream_id (stream));
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_streams) {
|
||||
gst_element_send_event (GST_ELEMENT (GST_MESSAGE_SRC (message)),
|
||||
gst_event_new_select_streams (selected_streams));
|
||||
g_list_free (selected_streams);
|
||||
}
|
||||
}
|
||||
gst_element_post_message (GST_ELEMENT_CAST (bin), message);
|
||||
}
|
||||
|
||||
/* GObject virtual methods */
|
||||
static void
|
||||
ges_track_get_property (GObject * object, guint property_id,
|
||||
|
@ -567,9 +604,12 @@ ges_track_class_init (GESTrackClass * klass)
|
|||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
||||
GstBinClass *bin_class = GST_BIN_CLASS (klass);
|
||||
|
||||
gstelement_class->change_state = GST_DEBUG_FUNCPTR (ges_track_change_state);
|
||||
|
||||
bin_class->handle_message = GST_DEBUG_FUNCPTR (ges_track_handle_message);
|
||||
|
||||
object_class->get_property = ges_track_get_property;
|
||||
object_class->set_property = ges_track_set_property;
|
||||
object_class->dispose = ges_track_dispose;
|
||||
|
|
|
@ -144,7 +144,7 @@ ges_base_bin_init (GESBaseBin * self)
|
|||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_bin_src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||
ges_base_bin_src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
|
||||
{
|
||||
GstFlowReturn result, chain_result;
|
||||
GESBaseBin *self = GES_BASE_BIN (GST_OBJECT_PARENT (parent));
|
||||
|
@ -186,6 +186,7 @@ ges_base_bin_set_timeline (GESBaseBin * self, GESTimeline * timeline)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
ges_timeline_commit (timeline);
|
||||
for (tmp = timeline->tracks; tmp; tmp = tmp->next) {
|
||||
GstPad *gpad;
|
||||
gchar *name = NULL;
|
||||
|
@ -238,7 +239,7 @@ ges_base_bin_set_timeline (GESBaseBin * self, GESTimeline * timeline)
|
|||
|
||||
proxy_pad = GST_PAD (gst_proxy_pad_get_internal (GST_PROXY_PAD (gpad)));
|
||||
gst_flow_combiner_add_pad (priv->flow_combiner, proxy_pad);
|
||||
gst_pad_set_chain_function (proxy_pad, gst_bin_src_chain);
|
||||
gst_pad_set_chain_function (proxy_pad, ges_base_bin_src_chain);
|
||||
gst_object_unref (proxy_pad);
|
||||
GST_DEBUG_OBJECT (sbin, "Adding pad: %" GST_PTR_FORMAT, gpad);
|
||||
}
|
||||
|
|
|
@ -142,6 +142,7 @@ typedef struct
|
|||
GCond cond;
|
||||
gulong loaded_sigid;
|
||||
gulong error_sigid;
|
||||
GESDemux *self;
|
||||
} TimelineConstructionData;
|
||||
|
||||
static void
|
||||
|
@ -237,6 +238,9 @@ done:
|
|||
|
||||
gst_clear_object (&project);
|
||||
|
||||
GST_INFO_OBJECT (data->self, "Timeline properly loaded: %" GST_PTR_FORMAT,
|
||||
data->timeline);
|
||||
ges_base_bin_set_timeline (GES_BASE_BIN (data->self), data->timeline);
|
||||
g_cond_broadcast (&data->cond);
|
||||
g_mutex_unlock (&data->lock);
|
||||
|
||||
|
@ -290,6 +294,7 @@ ges_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
|
||||
uri = gst_filename_to_uri (filename, NULL);
|
||||
data.uri = uri;
|
||||
data.self = self;
|
||||
|
||||
g_main_context_invoke (main_context,
|
||||
(GSourceFunc) ges_timeline_new_from_uri_from_main_thread, &data);
|
||||
|
@ -309,9 +314,6 @@ ges_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
|||
goto error;
|
||||
}
|
||||
|
||||
GST_INFO_OBJECT (self, "Timeline properly loaded: %" GST_PTR_FORMAT,
|
||||
data.timeline);
|
||||
ges_base_bin_set_timeline (GES_BASE_BIN (self), data.timeline);
|
||||
done:
|
||||
g_free (filename);
|
||||
g_free (uri);
|
||||
|
|
|
@ -1325,7 +1325,7 @@ ghost_event_probe_handler (GstPad * ghostpad G_GNUC_UNUSED,
|
|||
FALSE)) {
|
||||
|
||||
gst_event_unref (event);
|
||||
event = info->data = gst_event_new_stream_start (g_strdup (priv->id));
|
||||
event = info->data = gst_event_new_stream_start (priv->id);
|
||||
GST_INFO_OBJECT (comp, "forward stream-start %p (%s)", event, priv->id);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (comp, "dropping stream-start %p", event);
|
||||
|
|
Loading…
Reference in a new issue