1775db4ce03cfe8625cd9facc863e16accf72a06
[platform/upstream/gst-editing-services.git] / ges / ges-uri-source.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2020 Ubicast S.A
3  *     Author: Thibault Saunier <tsaunier@igalia.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "ges-internal.h"
26 #include "ges-uri-source.h"
27
28 GST_DEBUG_CATEGORY_STATIC (uri_source_debug);
29 #undef GST_CAT_DEFAULT
30 #define GST_CAT_DEFAULT uri_source_debug
31
32 #define DEFAULT_RAW_CAPS                        \
33   "video/x-raw; "                               \
34   "audio/x-raw; "                               \
35   "text/x-raw; "                                \
36   "subpicture/x-dvd; "                  \
37   "subpicture/x-pgs"
38
39 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
40
41 static inline gboolean
42 are_raw_caps (const GstCaps * caps)
43 {
44   GstCaps *raw = gst_static_caps_get (&default_raw_caps);
45   gboolean res = gst_caps_can_intersect (caps, raw);
46
47   gst_caps_unref (raw);
48   return res;
49 }
50
51 typedef enum
52 {
53   GST_AUTOPLUG_SELECT_TRY,
54   GST_AUTOPLUG_SELECT_EXPOSE,
55   GST_AUTOPLUG_SELECT_SKIP,
56 } GstAutoplugSelectResult;
57
58 static gint
59 autoplug_select_cb (GstElement * bin, GstPad * pad, GstCaps * caps,
60     GstElementFactory * factory, GESUriSource * self)
61 {
62   GstElement *nlesrc;
63   GstCaps *downstream_caps;
64   GstQuery *segment_query = NULL;
65   GstFormat segment_format;
66   GstAutoplugSelectResult res = GST_AUTOPLUG_SELECT_TRY;
67   gchar *stream_id = gst_pad_get_stream_id (pad);
68   const gchar *wanted_id =
69       gst_discoverer_stream_info_get_stream_id
70       (ges_uri_source_asset_get_stream_info (GES_URI_SOURCE_ASSET
71           (ges_extractable_get_asset (GES_EXTRACTABLE (self->element)))));
72   gboolean wanted = !g_strcmp0 (stream_id, wanted_id);
73
74   if (!ges_source_get_rendering_smartly (GES_SOURCE (self->element))) {
75     if (!are_raw_caps (caps))
76       goto done;
77
78     if (!wanted) {
79       GST_INFO_OBJECT (self->element, "Not matching stream id: %s -> SKIPPING",
80           stream_id);
81       res = GST_AUTOPLUG_SELECT_SKIP;
82     } else {
83       GST_INFO_OBJECT (self->element, "Using stream %s", stream_id);
84     }
85     goto done;
86   }
87
88   segment_query = gst_query_new_segment (GST_FORMAT_TIME);
89   if (!gst_pad_query (pad, segment_query)) {
90     GST_DEBUG_OBJECT (pad, "Could not query segment");
91
92     goto done;
93   }
94
95   gst_query_parse_segment (segment_query, NULL, &segment_format, NULL, NULL);
96   if (segment_format != GST_FORMAT_TIME) {
97     GST_DEBUG_OBJECT (pad,
98         "Segment not in %s != time for %" GST_PTR_FORMAT
99         "... continue plugin elements", gst_format_get_name (segment_format),
100         caps);
101
102     goto done;
103   }
104
105   nlesrc = ges_track_element_get_nleobject (self->element);
106   downstream_caps = gst_pad_peer_query_caps (nlesrc->srcpads->data, NULL);
107   if (downstream_caps && gst_caps_can_intersect (downstream_caps, caps)) {
108     if (wanted) {
109       res = GST_AUTOPLUG_SELECT_EXPOSE;
110       GST_INFO_OBJECT (self, "Exposing %" GST_PTR_FORMAT " with stream id: %s",
111           caps, stream_id);
112     } else {
113       res = GST_AUTOPLUG_SELECT_SKIP;
114       GST_DEBUG_OBJECT (self->element, "Totally skipping %s", stream_id);
115     }
116   }
117   gst_clear_caps (&downstream_caps);
118
119 done:
120   g_free (stream_id);
121   gst_clear_query (&segment_query);
122
123   return res;
124 }
125
126 GstElement *
127 ges_uri_source_create_source (GESUriSource * self)
128 {
129   GESTrack *track;
130   GstElement *decodebin;
131   const GstCaps *caps = NULL;
132
133   track = ges_track_element_get_track (self->element);
134
135   self->decodebin = decodebin = gst_element_factory_make ("uridecodebin", NULL);
136   GST_DEBUG_OBJECT (self->element,
137       "%" GST_PTR_FORMAT " - Track! %" GST_PTR_FORMAT, self->decodebin, track);
138
139   if (track)
140     caps = ges_track_get_caps (track);
141
142   g_object_set (decodebin, "caps", caps,
143       "expose-all-streams", FALSE, "uri", self->uri, NULL);
144   g_signal_connect (decodebin, "autoplug-select",
145       G_CALLBACK (autoplug_select_cb), self);
146
147   return decodebin;
148
149 }
150
151 static void
152 ges_uri_source_track_set_cb (GESTrackElement * element,
153     GParamSpec * arg G_GNUC_UNUSED, GESUriSource * self)
154 {
155   GESTrack *track;
156   const GstCaps *caps = NULL;
157
158   if (!self->decodebin)
159     return;
160
161   track = ges_track_element_get_track (GES_TRACK_ELEMENT (element));
162   if (!track)
163     return;
164
165   caps = ges_track_get_caps (track);
166
167   GST_INFO_OBJECT (element,
168       "Setting %" GST_PTR_FORMAT "caps to: %" GST_PTR_FORMAT, self->decodebin,
169       caps);
170   g_object_set (self->decodebin, "caps", caps, NULL);
171 }
172
173
174
175 void
176 ges_uri_source_init (GESTrackElement * element, GESUriSource * self)
177 {
178   static gsize once = 0;
179
180   if (g_once_init_enter (&once)) {
181     GST_DEBUG_CATEGORY_INIT (uri_source_debug, "gesurisource", 0,
182         "GES uri source");
183     g_once_init_leave (&once, 1);
184   }
185
186   self->element = element;
187   g_signal_connect (element, "notify::track",
188       G_CALLBACK (ges_uri_source_track_set_cb), self);
189 }
190
191 gboolean
192 ges_uri_source_select_pad (GESSource * self, GstPad * pad)
193 {
194   gboolean res = TRUE;
195   gboolean is_nested_timeline;
196   GESUriSourceAsset *asset =
197       GES_URI_SOURCE_ASSET (ges_extractable_get_asset (GES_EXTRACTABLE (self)));
198   const GESUriClipAsset *clip_asset =
199       ges_uri_source_asset_get_filesource_asset (asset);
200   const gchar *wanted_stream_id = ges_asset_get_id (GES_ASSET (asset));
201   gchar *stream_id;
202
203   if (clip_asset) {
204     g_object_get (G_OBJECT (clip_asset), "is-nested-timeline",
205         &is_nested_timeline, NULL);
206
207     if (is_nested_timeline) {
208       GST_DEBUG_OBJECT (self, "Nested timeline track selection is handled"
209           " by the timeline SELECT_STREAM events handling.");
210
211       return TRUE;
212     }
213   }
214
215   stream_id = gst_pad_get_stream_id (pad);
216   res = !g_strcmp0 (stream_id, wanted_stream_id);
217
218   GST_INFO_OBJECT (self, "%s pad with stream id: %s as %s wanted",
219       res ? "Using" : "Ignoring", stream_id, wanted_stream_id);
220   g_free (stream_id);
221
222   return res;
223 }