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 2024 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 "GstProtectionMetadataHelperFactory.h"
21 : #include "GstRialtoTextTrackSinkPrivate.h"
22 : #include "GstTextTrackSinkFactory.h"
23 : #include "RialtoServerLogging.h"
24 : #include <atomic>
25 : #include <cinttypes>
26 : #include <cstdlib>
27 : #include <gst/base/gstbasetransform.h>
28 : #include <gst/gst.h>
29 : #include <stdexcept>
30 : G_BEGIN_DECLS
31 :
32 : enum
33 : {
34 : PROP_0,
35 : PROP_MUTE,
36 : PROP_TEXT_TRACK_IDENTIFIER,
37 : PROP_VIDEO_DECODER,
38 : PROP_POSITION,
39 : PROP_OFFSET,
40 : PROP_LAST
41 : };
42 :
43 : #define GST_RIALTO_TEXT_TRACK_SINK_TYPE (gst_rialto_text_track_sink_get_type())
44 : #define GST_RIALTO_TEXT_TRACK_SINK(obj) \
45 : (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_RIALTO_TEXT_TRACK_SINK_TYPE, GstRialtoTextTrackSink))
46 : #define GST_RIALTO_TEXT_TRACK_SINK_CLASS(klass) \
47 : (G_TYPE_CHECK_CLASS_CAST((klass), GST_RIALTO_TEXT_TRACK_SINK_TYPE, GstRialtoTextTrackSinkClass))
48 :
49 : typedef struct _GstRialtoTextTrackSink GstRialtoTextTrackSink;
50 : typedef struct _GstRialtoTextTrackSinkClass GstRialtoTextTrackSinkClass;
51 : typedef struct firebolt::rialto::server::GstRialtoTextTrackSinkPrivate GstRialtoTextTrackSinkPrivate;
52 :
53 : GType gst_rialto_text_track_sink_get_type(void); // NOLINT(build/function_format)
54 :
55 : struct _GstRialtoTextTrackSink
56 : {
57 : GstBaseSink parent;
58 : GstRialtoTextTrackSinkPrivate *priv;
59 : };
60 :
61 : struct _GstRialtoTextTrackSinkClass
62 : {
63 : GstBaseSink parentClass;
64 : };
65 :
66 : G_END_DECLS
67 :
68 : static GstStaticPadTemplate sinkTemplate =
69 : GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
70 : GST_STATIC_CAPS("application/ttml+xml; text/vtt; application/x-subtitle-vtt; text/x-raw; "
71 : "subtitle/x-subtitle-cc"));
72 :
73 : GST_DEBUG_CATEGORY(gst_rialto_text_track_sink_debug_category);
74 : #define GST_CAT_DEFAULT gst_rialto_text_track_sink_debug_category
75 :
76 : #define gst_rialto_text_track_sink_parent_class parent_class
77 0 : G_DEFINE_TYPE_WITH_PRIVATE(GstRialtoTextTrackSink, gst_rialto_text_track_sink, GST_TYPE_BASE_SINK);
78 :
79 : static void gst_rialto_text_track_sink_finalize(GObject *object); // NOLINT(build/function_format)
80 : static GstFlowReturn gst_rialto_text_track_sink_render(GstBaseSink *sink, // NOLINT(build/function_format)
81 : GstBuffer *buffer);
82 : static gboolean gst_rialto_text_track_sink_set_caps(GstBaseSink *sink, GstCaps *caps); // NOLINT(build/function_format)
83 : static gboolean gst_rialto_text_track_sink_start(GstBaseSink *sink); // NOLINT(build/function_format)
84 : static gboolean gst_rialto_text_track_sink_stop(GstBaseSink *sink); // NOLINT(build/function_format)
85 : static gboolean gst_rialto_text_track_sink_event(GstBaseSink *sink, GstEvent *event); // NOLINT(build/function_format)
86 : static GstStateChangeReturn
87 : gst_rialto_text_track_sink_change_state(GstElement *element, GstStateChange transition); // NOLINT(build/function_format)
88 : static void gst_rialto_text_track_sink_get_property(GObject *object, guint propId, // NOLINT(build/function_format)
89 : GValue *value, GParamSpec *pspec);
90 : static void gst_rialto_text_track_sink_set_property(GObject *object, guint propId, // NOLINT(build/function_format)
91 : const GValue *value, GParamSpec *pspec);
92 : static gboolean gst_rialto_text_track_sink_query(GstElement *element, GstQuery *query); // NOLINT(build/function_format)
93 :
94 0 : static void gst_rialto_text_track_sink_class_init(GstRialtoTextTrackSinkClass *klass) // NOLINT(build/function_format)
95 : {
96 0 : GST_DEBUG_CATEGORY_INIT(gst_rialto_text_track_sink_debug_category, "rialto_text_track_sink", 0,
97 : "TextTrack Sink for Rialto");
98 :
99 0 : GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
100 0 : GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
101 0 : GstBaseSinkClass *baseSinkClass = GST_BASE_SINK_CLASS(klass);
102 :
103 0 : gobjectClass->finalize = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_finalize);
104 0 : gobjectClass->get_property = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_get_property);
105 0 : gobjectClass->set_property = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_set_property);
106 0 : baseSinkClass->start = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_start);
107 0 : baseSinkClass->stop = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_stop);
108 0 : baseSinkClass->render = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_render);
109 0 : baseSinkClass->set_caps = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_set_caps);
110 0 : baseSinkClass->event = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_event);
111 0 : elementClass->change_state = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_change_state);
112 0 : elementClass->query = GST_DEBUG_FUNCPTR(gst_rialto_text_track_sink_query);
113 :
114 0 : g_object_class_install_property(gobjectClass, PROP_MUTE,
115 : g_param_spec_boolean("mute", "Mute", "Mute subtitles", FALSE, G_PARAM_READWRITE));
116 :
117 0 : g_object_class_install_property(gobjectClass, PROP_TEXT_TRACK_IDENTIFIER,
118 : g_param_spec_string("text-track-identifier", "Text Track Identifier",
119 : "Identifier of text track", nullptr,
120 : GParamFlags(G_PARAM_READWRITE)));
121 :
122 0 : g_object_class_install_property(gobjectClass, PROP_VIDEO_DECODER,
123 : g_param_spec_uint64("video-decoder", "Video Decoder", "Video Decoder", 0,
124 : G_MAXUINT64, 0, GParamFlags(G_PARAM_WRITABLE)));
125 :
126 0 : g_object_class_install_property(gobjectClass, PROP_POSITION,
127 : g_param_spec_uint64("position", "Position", "Position", 0, G_MAXUINT64, 0,
128 : GParamFlags(G_PARAM_READWRITE)));
129 :
130 0 : g_object_class_install_property(gobjectClass, PROP_OFFSET,
131 : g_param_spec_uint64("offset", "Offset", "Offset", 0, G_MAXUINT64, 0,
132 : GParamFlags(G_PARAM_WRITABLE)));
133 :
134 0 : gst_element_class_add_pad_template(elementClass, gst_static_pad_template_get(&sinkTemplate));
135 0 : gst_element_class_set_static_metadata(elementClass, "Rialto TextTrack Sink", "Sink/Parser/Subtitle",
136 : "Rialto TextTrack Sink", "SKY");
137 : }
138 :
139 0 : static void gst_rialto_text_track_sink_init(GstRialtoTextTrackSink *self) // NOLINT(build/function_format)
140 : {
141 : GstRialtoTextTrackSinkPrivate *priv =
142 0 : reinterpret_cast<GstRialtoTextTrackSinkPrivate *>(gst_rialto_text_track_sink_get_instance_private(self));
143 :
144 0 : self->priv = new (priv) GstRialtoTextTrackSinkPrivate();
145 :
146 0 : gst_base_sink_set_async_enabled(GST_BASE_SINK(self), FALSE);
147 : }
148 :
149 0 : static void gst_rialto_text_track_sink_finalize(GObject *object) // NOLINT(build/function_format)
150 : {
151 0 : GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(object);
152 : GstRialtoTextTrackSinkPrivate *priv =
153 0 : reinterpret_cast<GstRialtoTextTrackSinkPrivate *>(gst_rialto_text_track_sink_get_instance_private(self));
154 :
155 0 : priv->~GstRialtoTextTrackSinkPrivate();
156 :
157 0 : GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
158 : }
159 :
160 0 : static gboolean gst_rialto_text_track_sink_start(GstBaseSink *sink) // NOLINT(build/function_format)
161 : {
162 0 : const char *wayland_display = std::getenv("WAYLAND_DISPLAY");
163 0 : if (!wayland_display)
164 : {
165 0 : GST_ERROR_OBJECT(sink, "Failed to get WAYLAND_DISPLAY env variable");
166 0 : return false;
167 : }
168 :
169 0 : std::string display{wayland_display};
170 0 : GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(sink);
171 : try
172 : {
173 0 : self->priv->m_textTrackSession =
174 0 : firebolt::rialto::server::ITextTrackSessionFactory::getFactory().createTextTrackSession(display);
175 : }
176 0 : catch (const std::exception &e)
177 : {
178 0 : GST_ERROR_OBJECT(sink, "Failed to create TextTrackSession. Reason '%s'", e.what());
179 0 : return false;
180 : }
181 :
182 0 : GST_INFO_OBJECT(sink, "Successfully started TextTrack sink");
183 0 : return true;
184 : }
185 :
186 0 : static gboolean gst_rialto_text_track_sink_stop(GstBaseSink *sink) // NOLINT(build/function_format)
187 : {
188 0 : GstRialtoTextTrackSink *self = GST_RIALTO_TEXT_TRACK_SINK(sink);
189 0 : self->priv->m_textTrackSession.reset();
190 :
191 0 : GST_INFO_OBJECT(sink, "Successfully stopped TextTrack sink");
192 0 : return true;
193 : }
194 :
195 0 : static GstFlowReturn gst_rialto_text_track_sink_render(GstBaseSink *sink, GstBuffer *buffer) // NOLINT(build/function_format)
196 : {
197 0 : GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
198 :
199 : GstMapInfo info;
200 0 : if (gst_buffer_map(buffer, &info, GST_MAP_READ))
201 : {
202 0 : std::string data(reinterpret_cast<char *>(info.data), info.size);
203 0 : int64_t displayOffset{0};
204 0 : if (GST_BUFFER_OFFSET_NONE != GST_BUFFER_OFFSET(buffer))
205 : {
206 0 : displayOffset = static_cast<int64_t>(GST_BUFFER_OFFSET(buffer));
207 : }
208 0 : textTrackSink->priv->m_textTrackSession->sendData(data, 0 - displayOffset);
209 :
210 0 : gst_buffer_unmap(buffer, &info);
211 : }
212 : else
213 : {
214 0 : GST_ERROR_OBJECT(textTrackSink, "Failed to map buffer");
215 0 : return GST_FLOW_ERROR;
216 : }
217 :
218 0 : return GST_FLOW_OK;
219 : }
220 :
221 0 : static gboolean gst_rialto_text_track_sink_set_position(GstRialtoTextTrackSink *textTrackSink) // NOLINT(build/function_format)
222 : {
223 0 : if (!textTrackSink->priv->m_textTrackSession)
224 : {
225 0 : GST_ERROR_OBJECT(textTrackSink, "Session is NULL");
226 0 : return FALSE;
227 : }
228 :
229 0 : uint64_t positionWithOffset = textTrackSink->priv->m_position.value_or(0) + textTrackSink->priv->m_offset.value_or(0);
230 :
231 0 : GST_DEBUG_OBJECT(textTrackSink,
232 : "Setting position to %" GST_TIME_FORMAT " (pts %" GST_TIME_FORMAT ", offset %" GST_TIME_FORMAT ")",
233 : GST_TIME_ARGS(positionWithOffset), GST_TIME_ARGS(textTrackSink->priv->m_position.value_or(0)),
234 : GST_TIME_ARGS(textTrackSink->priv->m_offset.value_or(0)));
235 :
236 0 : textTrackSink->priv->m_textTrackSession->setPosition(positionWithOffset / GST_MSECOND);
237 0 : return TRUE;
238 : }
239 :
240 0 : static gboolean gst_rialto_text_track_sink_set_caps(GstBaseSink *sink, GstCaps *caps) // NOLINT(build/function_format)
241 : {
242 0 : GST_INFO_OBJECT(sink, "Setting caps %" GST_PTR_FORMAT, caps);
243 0 : GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
244 :
245 0 : GstStructure *structure = gst_caps_get_structure(caps, 0);
246 0 : const gchar *mimeName = gst_structure_get_name(structure);
247 :
248 0 : if (g_str_has_prefix(mimeName, "text/vtt") || g_str_has_prefix(mimeName, "application/x-subtitle-vtt"))
249 : {
250 0 : GST_INFO_OBJECT(sink, "Setting session to WebVTT");
251 0 : textTrackSink->priv->m_textTrackSession->setSessionWebVTTSelection();
252 : }
253 0 : else if (g_str_has_prefix(mimeName, "application/ttml+xml"))
254 : {
255 0 : GST_INFO_OBJECT(sink, "Setting session to TTML");
256 0 : textTrackSink->priv->m_textTrackSession->setSessionTTMLSelection();
257 : }
258 0 : else if (g_str_has_prefix(mimeName, "subtitle/x-subtitle-cc"))
259 : {
260 0 : GST_INFO_OBJECT(sink, "Setting session to CC");
261 0 : std::string identifier = "CC1";
262 0 : if (textTrackSink->priv->m_textTrackIdentifier.empty())
263 : {
264 0 : GST_WARNING_OBJECT(sink, "No text track identifier set, defaulting to %s", identifier.c_str());
265 : }
266 : else
267 : {
268 0 : identifier = textTrackSink->priv->m_textTrackIdentifier;
269 : }
270 0 : textTrackSink->priv->m_textTrackSession->setSessionCCSelection(identifier);
271 :
272 0 : if (textTrackSink->priv->m_videoDecoderIdentifier)
273 : {
274 0 : textTrackSink->priv->m_textTrackSession->associateVideoDecoder(textTrackSink->priv->m_videoDecoderIdentifier);
275 : }
276 : }
277 : else
278 : {
279 0 : GST_ERROR_OBJECT(sink, "Invalid mime name '%s'", mimeName);
280 0 : return FALSE;
281 : }
282 :
283 0 : textTrackSink->priv->m_textTrackSession->mute(textTrackSink->priv->m_isMuted);
284 :
285 0 : std::unique_lock lock{textTrackSink->priv->m_mutex};
286 0 : textTrackSink->priv->m_capsSet = true;
287 0 : bool wasAnyQueued = textTrackSink->priv->m_queuedPosition.has_value() ||
288 0 : textTrackSink->priv->m_queuedOffset.has_value();
289 0 : if (textTrackSink->priv->m_queuedPosition.has_value())
290 : {
291 0 : textTrackSink->priv->m_position = textTrackSink->priv->m_queuedPosition;
292 0 : textTrackSink->priv->m_queuedPosition.reset();
293 : }
294 0 : if (textTrackSink->priv->m_queuedOffset.has_value())
295 : {
296 0 : textTrackSink->priv->m_offset = textTrackSink->priv->m_queuedOffset;
297 0 : textTrackSink->priv->m_queuedOffset.reset();
298 : }
299 0 : if (wasAnyQueued)
300 : {
301 0 : gst_rialto_text_track_sink_set_position(textTrackSink);
302 : }
303 :
304 0 : return TRUE;
305 : }
306 :
307 0 : static gboolean gst_rialto_text_track_sink_event(GstBaseSink *sink, GstEvent *event) // NOLINT(build/function_format)
308 : {
309 0 : GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(sink);
310 0 : GST_DEBUG_OBJECT(textTrackSink, "handling event %" GST_PTR_FORMAT, event);
311 :
312 0 : switch (GST_EVENT_TYPE(event))
313 : {
314 0 : case GST_EVENT_FLUSH_START:
315 : {
316 0 : if (!textTrackSink->priv->m_textTrackSession->resetSession(textTrackSink->priv->m_isMuted))
317 : {
318 0 : GST_ERROR_OBJECT(textTrackSink, "Failed to reset TextTrack session");
319 : }
320 0 : break;
321 : }
322 0 : case GST_EVENT_FLUSH_STOP:
323 : {
324 0 : break;
325 : }
326 0 : case GST_EVENT_CUSTOM_DOWNSTREAM:
327 : case GST_EVENT_CUSTOM_DOWNSTREAM_OOB:
328 : {
329 0 : if (gst_event_has_name(event, "current-pts"))
330 : {
331 0 : uint64_t pts = 0;
332 0 : const GstStructure *structure = gst_event_get_structure(event);
333 0 : if (structure)
334 : {
335 0 : if (gst_structure_get_uint64(structure, "pts", &pts))
336 : {
337 0 : if (pts == GST_CLOCK_TIME_NONE)
338 : {
339 0 : GST_ERROR_OBJECT(textTrackSink, "Invalid PTS value");
340 0 : return FALSE;
341 : }
342 :
343 0 : std::unique_lock lock{textTrackSink->priv->m_mutex};
344 0 : textTrackSink->priv->m_position = pts;
345 :
346 0 : gst_rialto_text_track_sink_set_position(textTrackSink);
347 : }
348 : else
349 : {
350 0 : GST_ERROR_OBJECT(textTrackSink, "Failed to get PTS from structure");
351 0 : return FALSE;
352 : }
353 : }
354 : else
355 : {
356 0 : GST_ERROR_OBJECT(textTrackSink, "Failed to get structure from event");
357 0 : return FALSE;
358 : }
359 : }
360 0 : break;
361 : }
362 0 : default:
363 : {
364 0 : break;
365 : }
366 : }
367 :
368 0 : return GST_BASE_SINK_CLASS(parent_class)->event(sink, event);
369 : }
370 :
371 : static GstStateChangeReturn
372 0 : gst_rialto_text_track_sink_change_state(GstElement *element, GstStateChange transition) // NOLINT(build/function_format)
373 : {
374 0 : GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(element);
375 :
376 0 : GstState current_state = GST_STATE_TRANSITION_CURRENT(transition);
377 0 : GstState next_state = GST_STATE_TRANSITION_NEXT(transition);
378 0 : GST_INFO_OBJECT(textTrackSink, "State change: (%s) -> (%s)", gst_element_state_get_name(current_state),
379 : gst_element_state_get_name(next_state));
380 :
381 0 : switch (transition)
382 : {
383 0 : case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
384 : {
385 0 : if (!textTrackSink->priv->m_textTrackSession->play())
386 : {
387 0 : GST_ERROR_OBJECT(textTrackSink, "Failed to play textTrack session");
388 0 : return GST_STATE_CHANGE_FAILURE;
389 : }
390 0 : break;
391 : }
392 0 : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
393 : {
394 0 : if (!textTrackSink->priv->m_textTrackSession->pause())
395 : {
396 0 : GST_ERROR_OBJECT(textTrackSink, "Failed to pause textTrack session");
397 0 : return GST_STATE_CHANGE_FAILURE;
398 : }
399 :
400 0 : break;
401 : }
402 0 : default:
403 0 : break;
404 : }
405 :
406 0 : GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
407 0 : if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
408 : {
409 0 : GST_WARNING_OBJECT(textTrackSink, "State change failed");
410 0 : return result;
411 : }
412 :
413 0 : return GST_STATE_CHANGE_SUCCESS;
414 : }
415 :
416 0 : static void gst_rialto_text_track_sink_get_property(GObject *object, guint propId, // NOLINT(build/function_format)
417 : GValue *value, GParamSpec *pspec)
418 : {
419 0 : GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(object);
420 0 : if (!textTrackSink)
421 : {
422 0 : GST_ERROR_OBJECT(textTrackSink, "Sink not initalised");
423 0 : return;
424 : }
425 0 : GstRialtoTextTrackSinkPrivate *priv = textTrackSink->priv;
426 :
427 0 : switch (propId)
428 : {
429 0 : case PROP_MUTE:
430 : {
431 0 : g_value_set_boolean(value, priv->m_isMuted.load());
432 0 : break;
433 : }
434 0 : case PROP_TEXT_TRACK_IDENTIFIER:
435 : {
436 0 : g_value_set_string(value, priv->m_textTrackIdentifier.c_str());
437 0 : break;
438 : }
439 0 : case PROP_POSITION:
440 : {
441 : // Thunder ITextTrack does not provide getPosition API so we are unable to determine current position
442 0 : g_value_set_uint64(value, GST_CLOCK_TIME_NONE);
443 0 : break;
444 : }
445 0 : default:
446 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
447 0 : break;
448 : }
449 : }
450 :
451 0 : static void gst_rialto_text_track_sink_set_property(GObject *object, guint propId, // NOLINT(build/function_format)
452 : const GValue *value, GParamSpec *pspec)
453 : {
454 0 : GstRialtoTextTrackSink *textTrackSink = GST_RIALTO_TEXT_TRACK_SINK(object);
455 0 : if (!textTrackSink)
456 : {
457 0 : GST_ERROR_OBJECT(textTrackSink, "Sink not initalised");
458 0 : return;
459 : }
460 0 : GstRialtoTextTrackSinkPrivate *priv = textTrackSink->priv;
461 :
462 0 : switch (propId)
463 : {
464 0 : case PROP_MUTE:
465 : {
466 0 : priv->m_isMuted = g_value_get_boolean(value);
467 0 : if (priv->m_textTrackSession)
468 : {
469 0 : priv->m_textTrackSession->mute(priv->m_isMuted);
470 : }
471 0 : break;
472 : }
473 0 : case PROP_TEXT_TRACK_IDENTIFIER:
474 : {
475 0 : priv->m_textTrackIdentifier = g_value_get_string(value);
476 0 : if (priv->m_textTrackSession && priv->m_textTrackSession->isClosedCaptions())
477 : {
478 0 : priv->m_textTrackSession->setSessionCCSelection(priv->m_textTrackIdentifier);
479 : }
480 :
481 0 : break;
482 : }
483 0 : case PROP_VIDEO_DECODER:
484 : {
485 0 : priv->m_videoDecoderIdentifier = g_value_get_uint64(value);
486 0 : if (priv->m_textTrackSession && priv->m_textTrackSession->isClosedCaptions())
487 : {
488 0 : priv->m_textTrackSession->associateVideoDecoder(priv->m_videoDecoderIdentifier);
489 : }
490 :
491 0 : break;
492 : }
493 0 : case PROP_POSITION:
494 : {
495 0 : guint64 position = g_value_get_uint64(value);
496 0 : std::unique_lock lock{priv->m_mutex};
497 0 : if (priv->m_textTrackSession && priv->m_capsSet)
498 : {
499 0 : priv->m_position = position;
500 0 : gst_rialto_text_track_sink_set_position(textTrackSink);
501 : }
502 : else
503 : {
504 0 : priv->m_queuedPosition = position;
505 : }
506 0 : break;
507 : }
508 0 : case PROP_OFFSET:
509 : {
510 0 : uint64_t offset = g_value_get_uint64(value);
511 0 : std::unique_lock lock{priv->m_mutex};
512 0 : if (priv->m_textTrackSession && priv->m_capsSet)
513 : {
514 0 : priv->m_offset = offset;
515 0 : gst_rialto_text_track_sink_set_position(textTrackSink);
516 : }
517 : else
518 : {
519 0 : priv->m_queuedOffset = offset;
520 : }
521 0 : break;
522 : }
523 :
524 0 : default:
525 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
526 0 : break;
527 : }
528 : }
529 :
530 0 : static gboolean gst_rialto_text_track_sink_query(GstElement *element, GstQuery *query) // NOLINT(build/function_format)
531 : {
532 0 : GstRialtoTextTrackSink *sink = GST_RIALTO_TEXT_TRACK_SINK(element);
533 0 : GST_DEBUG_OBJECT(sink, "handling query '%s'", GST_QUERY_TYPE_NAME(query));
534 0 : switch (GST_QUERY_TYPE(query))
535 : {
536 0 : case GST_QUERY_POSITION:
537 : {
538 : GstFormat fmt;
539 0 : gst_query_parse_position(query, &fmt, NULL);
540 0 : switch (fmt)
541 : {
542 0 : case GST_FORMAT_TIME:
543 : {
544 : // GST_CLOCK_TIME_NONE has to be returned here, because otherwise whole pipeline returns incorrect position
545 0 : gst_query_set_position(query, fmt, GST_CLOCK_TIME_NONE);
546 0 : break;
547 : }
548 0 : default:
549 0 : break;
550 : }
551 0 : return TRUE;
552 : }
553 0 : default:
554 0 : break;
555 : }
556 0 : GstElement *parent = GST_ELEMENT(&sink->parent);
557 0 : return GST_ELEMENT_CLASS(parent_class)->query(parent, query);
558 : }
559 :
560 : namespace firebolt::rialto::server
561 : {
562 1 : std::shared_ptr<IGstTextTrackSinkFactory> IGstTextTrackSinkFactory::createFactory()
563 : {
564 1 : std::shared_ptr<IGstTextTrackSinkFactory> factory;
565 :
566 : try
567 : {
568 1 : factory = std::make_shared<GstTextTrackSinkFactory>();
569 : }
570 0 : catch (const std::exception &e)
571 : {
572 0 : RIALTO_SERVER_LOG_ERROR("Failed to create the textTrackSink element factory, reason: %s", e.what());
573 : }
574 :
575 1 : return factory;
576 : }
577 :
578 0 : GstElement *GstTextTrackSinkFactory::createGstTextTrackSink() const
579 : {
580 0 : GstElement *elem = GST_ELEMENT(g_object_new(GST_RIALTO_TEXT_TRACK_SINK_TYPE, nullptr));
581 :
582 0 : return elem;
583 : }
584 :
585 : }; // namespace firebolt::rialto::server
|