Line data Source code
1 : /*
2 : * If not stated otherwise in this file or this component's LICENSE file the
3 : * following copyright and licenses apply:
4 : *
5 : * Copyright 2022 Sky UK
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : #include <stdexcept>
21 :
22 : #include "GstSrc.h"
23 : #include "GstTextTrackSinkFactory.h"
24 : #include "RialtoServerLogging.h"
25 : #include <MediaCommon.h>
26 :
27 : static void gstRialtoSrcUriHandlerInit(gpointer gIface, gpointer ifaceData);
28 :
29 : static GstStaticPadTemplate rialto_src_template =
30 : GST_STATIC_PAD_TEMPLATE("src_%u", GST_PAD_SRC, GST_PAD_SOMETIMES, GST_STATIC_CAPS_ANY);
31 :
32 : GST_DEBUG_CATEGORY(rialto_gst_player_debug);
33 : #define GST_CAT_DEFAULT rialto_gst_player_debug
34 : #define gst_rialto_src_parent_class parent_class
35 : #define RIALTO_SRC_CATEGORY_INIT \
36 : GST_DEBUG_CATEGORY_INIT(rialto_gst_player_debug, "rialtosrc", 0, "Rialto source element");
37 14 : G_DEFINE_TYPE_WITH_CODE(GstRialtoSrc, gst_rialto_src, GST_TYPE_BIN,
38 : G_ADD_PRIVATE(GstRialtoSrc)
39 : G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, gstRialtoSrcUriHandlerInit)
40 : RIALTO_SRC_CATEGORY_INIT)
41 :
42 0 : static void gstRialtoSrcDispose(GObject *object)
43 : {
44 0 : GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object));
45 : }
46 :
47 0 : static void gstRialtoSrcFinalize(GObject *object)
48 : {
49 0 : GstRialtoSrc *src = GST_RIALTO_SRC(object);
50 0 : GstRialtoSrcPrivate *priv = src->priv;
51 0 : g_free(priv->uri);
52 0 : priv->~GstRialtoSrcPrivate();
53 0 : GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
54 : }
55 :
56 0 : static void gstRialtoSrcSetProperty(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
57 : {
58 0 : GST_CALL_PARENT(G_OBJECT_CLASS, set_property, (object, prop_id, value, pspec));
59 : }
60 :
61 0 : static void gstRialtoSrcGetProperty(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
62 : {
63 0 : GST_CALL_PARENT(G_OBJECT_CLASS, get_property, (object, prop_id, value, pspec));
64 : }
65 :
66 0 : static GstURIType gstRialtoSrcUriGetType(GType)
67 : {
68 0 : return GST_URI_SRC;
69 : }
70 :
71 0 : const gchar *const *gstRialtoSrcGetProtocols(GType)
72 : {
73 : static const char *protocols[] = {"rialto", 0};
74 0 : return protocols;
75 : }
76 :
77 0 : static gchar *gstRialtoSrcGetUri(GstURIHandler *handler)
78 : {
79 0 : GstRialtoSrc *src = GST_RIALTO_SRC(handler);
80 : gchar *ret;
81 0 : GST_OBJECT_LOCK(src);
82 0 : ret = g_strdup(src->priv->uri);
83 0 : GST_OBJECT_UNLOCK(src);
84 0 : return ret;
85 : }
86 :
87 0 : static gboolean gstRialtoSrcSetUri(GstURIHandler *handler, const gchar *uri, GError **error)
88 : {
89 0 : GstRialtoSrc *src = GST_RIALTO_SRC(handler);
90 0 : GstRialtoSrcPrivate *priv = src->priv;
91 0 : if (GST_STATE(src) >= GST_STATE_PAUSED)
92 : {
93 0 : GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED");
94 0 : return FALSE;
95 : }
96 0 : GST_OBJECT_LOCK(src);
97 0 : g_free(priv->uri);
98 0 : priv->uri = 0;
99 0 : if (!uri)
100 : {
101 0 : GST_OBJECT_UNLOCK(src);
102 0 : return TRUE;
103 : }
104 0 : priv->uri = g_strdup(uri);
105 0 : GST_OBJECT_UNLOCK(src);
106 0 : return TRUE;
107 : }
108 :
109 0 : static void gstRialtoSrcUriHandlerInit(gpointer gIface, gpointer)
110 : {
111 0 : GstURIHandlerInterface *iface = reinterpret_cast<GstURIHandlerInterface *>(gIface);
112 0 : iface->get_type = gstRialtoSrcUriGetType;
113 0 : iface->get_protocols = gstRialtoSrcGetProtocols;
114 0 : iface->get_uri = gstRialtoSrcGetUri;
115 0 : iface->set_uri = gstRialtoSrcSetUri;
116 : }
117 :
118 0 : static gboolean gstRialtoSrcQueryWithParent(GstPad *pad, GstObject *parent, GstQuery *query)
119 : {
120 0 : gboolean result = FALSE;
121 0 : switch (GST_QUERY_TYPE(query))
122 : {
123 : default:
124 : {
125 0 : GstPad *target = gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(pad));
126 : // Forward the query to the proxy target pad.
127 0 : if (target)
128 0 : result = gst_pad_query(target, query);
129 0 : gst_object_unref(target);
130 0 : break;
131 : }
132 : }
133 0 : return result;
134 : }
135 :
136 0 : void gstRialtoSrcHandleMessage(GstBin *bin, GstMessage *message)
137 : {
138 0 : GstRialtoSrc *src = GST_RIALTO_SRC(GST_ELEMENT(bin));
139 0 : switch (GST_MESSAGE_TYPE(message))
140 : {
141 0 : case GST_MESSAGE_EOS:
142 : {
143 0 : gboolean emit_eos = TRUE;
144 0 : GstPad *pad = gst_element_get_static_pad(GST_ELEMENT(GST_MESSAGE_SRC(message)), "src");
145 0 : GST_DEBUG_OBJECT(src, "EOS received from %s", GST_MESSAGE_SRC_NAME(message));
146 0 : g_object_set_data(G_OBJECT(pad), "is-eos", GINT_TO_POINTER(1));
147 0 : gst_object_unref(pad);
148 0 : for (guint i = 0; i < src->priv->appsrc_count; i++)
149 : {
150 0 : gchar *name = g_strdup_printf("src_%u", i);
151 0 : GstPad *src_pad = gst_element_get_static_pad(GST_ELEMENT(src), name);
152 0 : GstPad *target = gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(src_pad));
153 0 : gint is_eos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(target), "is-eos"));
154 0 : gst_object_unref(target);
155 0 : gst_object_unref(src_pad);
156 0 : g_free(name);
157 0 : if (!is_eos)
158 : {
159 0 : emit_eos = FALSE;
160 0 : break;
161 : }
162 : }
163 0 : gst_message_unref(message);
164 0 : if (emit_eos)
165 : {
166 0 : GST_DEBUG_OBJECT(src, "All appsrc elements are EOS, emitting event now.");
167 0 : gst_element_send_event(GST_ELEMENT(bin), gst_event_new_eos());
168 : }
169 0 : break;
170 : }
171 0 : default:
172 0 : GST_BIN_CLASS(parent_class)->handle_message(bin, message);
173 0 : break;
174 : }
175 : }
176 :
177 0 : static void gstRialtoSrcDoAsyncStart(GstRialtoSrc *rialtoSrc)
178 : {
179 0 : GstRialtoSrcPrivate *privateData = rialtoSrc->priv;
180 0 : if (privateData->async_done)
181 : {
182 0 : GST_DEBUG_OBJECT(rialtoSrc, "Rialto src already done");
183 0 : return;
184 : }
185 :
186 0 : GstMessage *message = gst_message_new_async_start(GST_OBJECT(rialtoSrc));
187 0 : GstBin *bin = GST_BIN(rialtoSrc);
188 :
189 0 : privateData->async_start = TRUE;
190 0 : GST_BIN_CLASS(parent_class)->handle_message(bin, message);
191 : }
192 :
193 1 : static void gstRialtoSrcDoAsyncDone(GstRialtoSrc *rialtoSrc)
194 : {
195 1 : GstRialtoSrcPrivate *privateData = rialtoSrc->priv;
196 1 : if (!privateData->async_start)
197 : {
198 1 : GST_DEBUG_OBJECT(rialtoSrc, "Rialto src not started");
199 1 : return;
200 : }
201 :
202 0 : GstMessage *message = gst_message_new_async_done(GST_OBJECT(rialtoSrc), GST_CLOCK_TIME_NONE);
203 0 : GstBin *bin = GST_BIN(rialtoSrc);
204 :
205 0 : GST_BIN_CLASS(parent_class)->handle_message(bin, message);
206 :
207 0 : privateData->async_done = TRUE;
208 0 : privateData->async_start = FALSE;
209 : }
210 :
211 0 : static GstStateChangeReturn gstRialtoSrcChangeState(GstElement *element, GstStateChange transition)
212 : {
213 0 : GstRialtoSrc *rialtoSrc = GST_RIALTO_SRC(element);
214 0 : GstRialtoSrcPrivate *privateData = rialtoSrc->priv;
215 0 : GstStateChangeReturn status = GST_STATE_CHANGE_SUCCESS;
216 :
217 0 : if (transition == GST_STATE_CHANGE_READY_TO_PAUSED)
218 : {
219 0 : gstRialtoSrcDoAsyncStart(rialtoSrc);
220 : }
221 :
222 0 : status = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
223 0 : if (G_UNLIKELY(status == GST_STATE_CHANGE_FAILURE))
224 : {
225 0 : gstRialtoSrcDoAsyncDone(rialtoSrc);
226 0 : return status;
227 : }
228 :
229 0 : switch (transition)
230 : {
231 0 : case GST_STATE_CHANGE_READY_TO_PAUSED:
232 : {
233 0 : if (!privateData->async_done)
234 0 : status = GST_STATE_CHANGE_ASYNC;
235 0 : break;
236 : }
237 0 : case GST_STATE_CHANGE_PAUSED_TO_READY:
238 : {
239 0 : gstRialtoSrcDoAsyncDone(rialtoSrc);
240 0 : break;
241 : }
242 0 : default:
243 0 : break;
244 : }
245 :
246 0 : return status;
247 : }
248 :
249 0 : static void gst_rialto_src_init(GstRialtoSrc *src) // NOLINT(build/function_format)
250 : {
251 0 : GstRialtoSrcPrivate *priv = reinterpret_cast<GstRialtoSrcPrivate *>(gst_rialto_src_get_instance_private(src));
252 0 : src->priv = priv;
253 0 : src->priv->appsrc_count = 0;
254 0 : src->priv->async_start = FALSE;
255 0 : src->priv->async_done = FALSE;
256 0 : g_object_set(GST_BIN(src), "message-forward", TRUE, nullptr);
257 : }
258 :
259 0 : static void gst_rialto_src_class_init(GstRialtoSrcClass *klass) // NOLINT(build/function_format)
260 : {
261 0 : GObjectClass *oklass = G_OBJECT_CLASS(klass);
262 0 : GstElementClass *eklass = GST_ELEMENT_CLASS(klass);
263 0 : GstBinClass *bklass = GST_BIN_CLASS(klass);
264 0 : oklass->dispose = gstRialtoSrcDispose;
265 0 : oklass->finalize = gstRialtoSrcFinalize;
266 0 : oklass->set_property = gstRialtoSrcSetProperty;
267 0 : oklass->get_property = gstRialtoSrcGetProperty;
268 0 : GstPadTemplate *templ = gst_static_pad_template_get(&rialto_src_template);
269 0 : gst_element_class_add_pad_template(eklass, templ);
270 0 : gst_element_class_set_metadata(eklass, "Rialto source element", "Source",
271 : "Handles data incoming from the Rialto player", "POC <poc@sky.uk>");
272 0 : g_object_class_install_property(oklass, PROP_LOCATION,
273 : g_param_spec_string("location", "location", "Location to read from", 0,
274 : (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
275 0 : bklass->handle_message = GST_DEBUG_FUNCPTR(gstRialtoSrcHandleMessage);
276 0 : eklass->change_state = GST_DEBUG_FUNCPTR(gstRialtoSrcChangeState);
277 : }
278 :
279 : namespace firebolt::rialto::server
280 : {
281 : std::weak_ptr<IGstSrcFactory> GstSrcFactory::m_factory;
282 : std::weak_ptr<IGstSrc> GstSrcFactory::m_gstSrc;
283 : std::mutex GstSrcFactory::m_creationMutex;
284 :
285 3 : std::shared_ptr<IGstSrcFactory> IGstSrcFactory::getFactory()
286 : {
287 3 : std::shared_ptr<IGstSrcFactory> factory = GstSrcFactory::m_factory.lock();
288 :
289 3 : if (!factory)
290 : {
291 : try
292 : {
293 3 : factory = std::make_shared<GstSrcFactory>();
294 : }
295 0 : catch (const std::exception &e)
296 : {
297 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the gstreamer src factory, reason: %s", e.what());
298 : }
299 :
300 3 : GstSrcFactory::m_factory = factory;
301 : }
302 :
303 3 : return factory;
304 : }
305 :
306 3 : std::shared_ptr<IGstSrc> GstSrcFactory::getGstSrc()
307 : {
308 3 : std::lock_guard<std::mutex> lock{m_creationMutex};
309 :
310 3 : std::shared_ptr<IGstSrc> gstSrc = GstSrcFactory::m_gstSrc.lock();
311 :
312 3 : if (!gstSrc)
313 : {
314 : try
315 : {
316 6 : gstSrc = std::make_shared<GstSrc>(firebolt::rialto::wrappers::IGstWrapperFactory::getFactory(),
317 6 : firebolt::rialto::wrappers::IGlibWrapperFactory::getFactory(),
318 9 : IGstDecryptorElementFactory::createFactory());
319 : }
320 0 : catch (const std::exception &e)
321 : {
322 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the gstreamer src, reason: %s", e.what());
323 : }
324 :
325 3 : GstSrcFactory::m_gstSrc = gstSrc;
326 : }
327 :
328 6 : return gstSrc;
329 3 : }
330 :
331 17 : GstSrc::GstSrc(const std::shared_ptr<firebolt::rialto::wrappers::IGstWrapperFactory> &gstWrapperFactory,
332 : const std::shared_ptr<firebolt::rialto::wrappers::IGlibWrapperFactory> &glibWrapperFactory,
333 17 : const std::shared_ptr<IGstDecryptorElementFactory> &decryptorFactory)
334 17 : : m_decryptorFactory(decryptorFactory)
335 : {
336 17 : if ((!gstWrapperFactory) || (!(m_gstWrapper = gstWrapperFactory->getGstWrapper())))
337 : {
338 0 : throw std::runtime_error("Cannot create GstWrapper");
339 : }
340 17 : if ((!glibWrapperFactory) || (!(m_glibWrapper = glibWrapperFactory->getGlibWrapper())))
341 : {
342 0 : throw std::runtime_error("Cannot create GlibWrapper");
343 : }
344 17 : if (!m_decryptorFactory)
345 : {
346 0 : throw std::runtime_error("No decryptor factory provided");
347 : }
348 17 : }
349 :
350 4 : void GstSrc::initSrc()
351 : {
352 4 : GstElementFactory *src_factory = m_gstWrapper->gstElementFactoryFind("rialtosrc");
353 4 : if (!src_factory)
354 : {
355 3 : m_gstWrapper->gstElementRegister(0, "rialtosrc", GST_RANK_PRIMARY + 100, GST_RIALTO_TYPE_SRC);
356 : }
357 : else
358 : {
359 1 : m_gstWrapper->gstObjectUnref(src_factory);
360 1 : src_factory = nullptr;
361 : }
362 4 : }
363 :
364 6 : void GstSrc::setDefaultStreamFormatIfNeeded(GstElement *appSrc)
365 : {
366 6 : GstCaps *currentCaps = m_gstWrapper->gstAppSrcGetCaps(GST_APP_SRC(appSrc));
367 6 : if (currentCaps)
368 : {
369 6 : GstStructure *structure = m_gstWrapper->gstCapsGetStructure(currentCaps, 0);
370 7 : if (structure && (m_gstWrapper->gstStructureHasName(structure, "video/x-h264") ||
371 1 : m_gstWrapper->gstStructureHasName(structure, "video/x-h265")))
372 : {
373 5 : bool hasStreamFormat = m_gstWrapper->gstStructureHasField(structure, "stream-format");
374 5 : bool hasCodecData = m_gstWrapper->gstStructureHasField(structure, "codec_data");
375 :
376 5 : if (!hasStreamFormat && !hasCodecData)
377 : {
378 3 : GstCaps *newCaps = m_gstWrapper->gstCapsCopy(currentCaps);
379 3 : if (newCaps)
380 : {
381 3 : m_gstWrapper->gstCapsSetSimple(newCaps, "stream-format", G_TYPE_STRING, "byte-stream", nullptr);
382 3 : m_gstWrapper->gstAppSrcSetCaps(GST_APP_SRC(appSrc), newCaps);
383 3 : GST_INFO("Added stream-format=byte-stream to caps %" GST_PTR_FORMAT, newCaps);
384 3 : m_gstWrapper->gstCapsUnref(newCaps);
385 : }
386 : }
387 : }
388 : }
389 6 : m_gstWrapper->gstCapsUnref(currentCaps);
390 : }
391 :
392 9 : void GstSrc::setupAndAddAppArc(IDecryptionService *decryptionService, GstElement *source, StreamInfo &streamInfo,
393 : GstAppSrcCallbacks *callbacks, gpointer userData, firebolt::rialto::MediaSourceType type)
394 : {
395 : // Configure and add appsrc
396 9 : m_glibWrapper->gObjectSet(streamInfo.appSrc, "block", FALSE, "format", GST_FORMAT_TIME, "stream-type",
397 : GST_APP_STREAM_TYPE_STREAM, "min-percent", 20, "handle-segment-change", TRUE, nullptr);
398 9 : m_gstWrapper->gstAppSrcSetCallbacks(GST_APP_SRC(streamInfo.appSrc), callbacks, userData, nullptr);
399 :
400 : const std::unordered_map<firebolt::rialto::MediaSourceType, uint32_t> queueSize =
401 : {{firebolt::rialto::MediaSourceType::VIDEO, 8 * 1024 * 1024},
402 : {firebolt::rialto::MediaSourceType::AUDIO, 512 * 1024},
403 9 : {firebolt::rialto::MediaSourceType::SUBTITLE, 256 * 1024}};
404 :
405 9 : auto sizeIt = queueSize.find(type);
406 9 : if (sizeIt != queueSize.end())
407 : {
408 9 : m_gstWrapper->gstAppSrcSetMaxBytes(GST_APP_SRC(streamInfo.appSrc), sizeIt->second);
409 : }
410 : else
411 : {
412 0 : GST_WARNING_OBJECT(source, "Could not find max-bytes value for appsrc");
413 : }
414 :
415 9 : m_gstWrapper->gstAppSrcSetStreamType(GST_APP_SRC(streamInfo.appSrc), GST_APP_STREAM_TYPE_SEEKABLE);
416 :
417 9 : GstRialtoSrc *src = GST_RIALTO_SRC(source);
418 9 : guint id = src->priv->appsrc_count;
419 9 : src->priv->appsrc_count++;
420 9 : gchar *name = m_glibWrapper->gStrdupPrintf("src_%u", id);
421 9 : m_gstWrapper->gstBinAdd(GST_BIN(source), streamInfo.appSrc);
422 :
423 9 : GstElement *src_elem = streamInfo.appSrc;
424 :
425 : // Configure and add decryptor
426 9 : if (streamInfo.hasDrm)
427 : {
428 : gchar *decryptorName =
429 16 : m_glibWrapper->gStrdupPrintf("rialtodecryptor%s_%u",
430 8 : (type == firebolt::rialto::MediaSourceType::VIDEO) ? "video" : "audio", id);
431 : GstElement *decryptor =
432 8 : m_decryptorFactory->createDecryptorElement(decryptorName, decryptionService, m_gstWrapper);
433 8 : m_glibWrapper->gFree(decryptorName);
434 8 : if (decryptor)
435 : {
436 7 : GST_DEBUG_OBJECT(src, "Injecting decryptor element %" GST_PTR_FORMAT, decryptor);
437 :
438 7 : m_gstWrapper->gstBinAdd(GST_BIN(source), decryptor);
439 7 : m_gstWrapper->gstElementSyncStateWithParent(decryptor);
440 7 : m_gstWrapper->gstElementLink(src_elem, decryptor);
441 7 : src_elem = decryptor;
442 : }
443 : else
444 : {
445 1 : GST_WARNING_OBJECT(src, "Could not create decryptor element");
446 : }
447 :
448 8 : if (type == firebolt::rialto::MediaSourceType::VIDEO)
449 : {
450 : // Configure and add payloader
451 7 : GstElement *payloader = createPayloader();
452 7 : if (payloader)
453 : {
454 : /*
455 : h264secparse and h265secparse have problems with parsing blank caps (with no stream-format nor
456 : codec_data defined). This is a workaround to set the stream-format to byte-stream if needed.
457 : */
458 6 : setDefaultStreamFormatIfNeeded(streamInfo.appSrc);
459 :
460 6 : if (GST_IS_BASE_TRANSFORM(payloader))
461 : {
462 0 : m_gstWrapper->gstBaseTransformSetInPlace(GST_BASE_TRANSFORM(payloader), TRUE);
463 : }
464 6 : m_gstWrapper->gstBinAdd(GST_BIN(source), payloader);
465 6 : m_gstWrapper->gstElementSyncStateWithParent(payloader);
466 6 : m_gstWrapper->gstElementLink(src_elem, payloader);
467 6 : src_elem = payloader;
468 : }
469 : else
470 : {
471 1 : GST_WARNING_OBJECT(src, "Could not create payloader element");
472 : }
473 : }
474 :
475 : // Configure and add buffer queue
476 8 : GstElement *queue = m_gstWrapper->gstElementFactoryMake("queue", nullptr);
477 8 : if (queue)
478 : {
479 7 : m_glibWrapper->gObjectSet(G_OBJECT(queue), "max-size-buffers", 10, "max-size-bytes", 0, "max-size-time",
480 : (gint64)0, "silent", TRUE, nullptr);
481 7 : m_gstWrapper->gstBinAdd(GST_BIN(source), queue);
482 7 : m_gstWrapper->gstElementSyncStateWithParent(queue);
483 7 : m_gstWrapper->gstElementLink(src_elem, queue);
484 7 : src_elem = queue;
485 : }
486 : else
487 : {
488 1 : GST_WARNING_OBJECT(src, "Could not create buffer queue element");
489 : }
490 : }
491 :
492 : // Setup pad
493 9 : GstPad *target = m_gstWrapper->gstElementGetStaticPad(src_elem, "src");
494 9 : GstPad *pad = m_gstWrapper->gstGhostPadNew(name, target);
495 9 : m_gstWrapper->gstPadSetQueryFunction(pad, gstRialtoSrcQueryWithParent);
496 9 : m_gstWrapper->gstPadSetActive(pad, TRUE);
497 :
498 9 : m_gstWrapper->gstElementAddPad(source, pad);
499 9 : GST_OBJECT_FLAG_SET(pad, GST_PAD_FLAG_NEED_PARENT);
500 :
501 9 : m_gstWrapper->gstElementSyncStateWithParent(streamInfo.appSrc);
502 :
503 9 : m_glibWrapper->gFree(name);
504 9 : m_gstWrapper->gstObjectUnref(target);
505 : }
506 :
507 1 : void GstSrc::allAppSrcsAdded(GstElement *element)
508 : {
509 1 : GstRialtoSrc *src = GST_RIALTO_SRC(element);
510 1 : m_gstWrapper->gstElementNoMorePads(element);
511 1 : gstRialtoSrcDoAsyncDone(src);
512 : }
513 :
514 7 : GstElement *GstSrc::createPayloader()
515 : {
516 : static GstElementFactory *factory = nullptr;
517 : static gsize init = 0;
518 7 : if (m_glibWrapper->gOnceInitEnter(&init))
519 : {
520 7 : factory = m_gstWrapper->gstElementFactoryFind("svppay");
521 7 : m_glibWrapper->gOnceInitLeave(&init, 1);
522 : }
523 7 : if (!factory)
524 : {
525 0 : GST_WARNING("svppay not found");
526 0 : return nullptr;
527 : }
528 7 : return m_gstWrapper->gstElementFactoryCreate(factory, nullptr);
529 : }
530 :
531 : }; // namespace firebolt::rialto::server
|