Line data Source code
1 : /*
2 : * Copyright (C) 2022 Sky UK
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Lesser General Public
6 : * License as published by the Free Software Foundation;
7 : * version 2.1 of the License.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public
15 : * License along with this library; if not, write to the Free Software
16 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 : */
18 :
19 : #include <gst/gst.h>
20 : #include <inttypes.h>
21 : #include <stdint.h>
22 :
23 : #include "GStreamerEMEUtils.h"
24 : #include "GStreamerMSEUtils.h"
25 : #include "IMediaPipelineCapabilities.h"
26 : #include "PullModeVideoPlaybackDelegate.h"
27 : #include "RialtoGStreamerMSEBaseSinkPrivate.h"
28 : #include "RialtoGStreamerMSEVideoSink.h"
29 :
30 : using namespace firebolt::rialto::client;
31 :
32 : GST_DEBUG_CATEGORY_STATIC(RialtoMSEVideoSinkDebug);
33 : #define GST_CAT_DEFAULT RialtoMSEVideoSinkDebug
34 :
35 : #define rialto_mse_video_sink_parent_class parent_class
36 212 : G_DEFINE_TYPE_WITH_CODE(RialtoMSEVideoSink, rialto_mse_video_sink, RIALTO_TYPE_MSE_BASE_SINK,
37 : GST_DEBUG_CATEGORY_INIT(RialtoMSEVideoSinkDebug, "rialtomsevideosink", 0,
38 : "rialto mse video sink"));
39 :
40 : enum
41 : {
42 : PROP_0,
43 : PROP_WINDOW_SET,
44 : PROP_MAX_VIDEO_WIDTH,
45 : PROP_MAX_VIDEO_HEIGHT,
46 : PROP_MAX_VIDEO_WIDTH_DEPRECATED,
47 : PROP_MAX_VIDEO_HEIGHT_DEPRECATED,
48 : PROP_FRAME_STEP_ON_PREROLL,
49 : PROP_IMMEDIATE_OUTPUT,
50 : PROP_SYNCMODE_STREAMING,
51 : PROP_SHOW_VIDEO_WINDOW,
52 : PROP_IS_MASTER,
53 : PROP_VIDEO_PTS,
54 : PROP_REPORT_DECODE_ERRORS,
55 : PROP_QUEUED_FRAMES,
56 : PROP_LAST
57 : };
58 :
59 : enum
60 : {
61 : SIGNAL_FIRST_VIDEO_FRAME_RECEIVED,
62 : SIGNAL_LAST
63 : };
64 :
65 : static guint g_signals[SIGNAL_LAST] = {0};
66 :
67 1 : void rialto_mse_video_handle_rialto_server_sent_first_video_frame_received(RialtoMSEVideoSink *sink)
68 : {
69 1 : GST_INFO_OBJECT(sink, "Sending first frame received signal");
70 1 : g_signal_emit(G_OBJECT(sink), g_signals[SIGNAL_FIRST_VIDEO_FRAME_RECEIVED], 0, 0, nullptr);
71 : }
72 :
73 208 : static GstStateChangeReturn rialto_mse_video_sink_change_state(GstElement *element, GstStateChange transition)
74 : {
75 208 : RialtoMSEVideoSink *sink = RIALTO_MSE_VIDEO_SINK(element);
76 208 : if (GST_STATE_CHANGE_NULL_TO_READY == transition)
77 : {
78 69 : GST_INFO_OBJECT(sink, "RialtoMSEVideoSink state change to READY. Initializing delegate");
79 69 : auto delegate = std::make_shared<PullModeVideoPlaybackDelegate>(element);
80 69 : delegate->createControlBackend();
81 69 : rialto_mse_base_sink_initialise_delegate(RIALTO_MSE_BASE_SINK(sink), delegate);
82 : }
83 208 : GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
84 208 : if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
85 : {
86 1 : GST_WARNING_OBJECT(sink, "State change failed");
87 1 : return result;
88 : }
89 :
90 207 : return result;
91 : }
92 :
93 20 : static void rialto_mse_video_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
94 : {
95 20 : switch (propId)
96 : {
97 5 : case PROP_WINDOW_SET:
98 : {
99 5 : g_value_set_string(value, "0,0,1920,1080"); // Set default value
100 5 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::WindowSet,
101 : value);
102 5 : break;
103 : }
104 1 : case PROP_MAX_VIDEO_WIDTH_DEPRECATED:
105 1 : GST_WARNING_OBJECT(object, "MaxVideoWidth property is deprecated. Use 'max-video-width' instead");
106 : case PROP_MAX_VIDEO_WIDTH:
107 : {
108 2 : g_value_set_uint(value, 0); // Set default value
109 2 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
110 2 : IPlaybackDelegate::Property::MaxVideoWidth, value);
111 2 : break;
112 : }
113 1 : case PROP_MAX_VIDEO_HEIGHT_DEPRECATED:
114 1 : GST_WARNING_OBJECT(object, "MaxVideoHeight property is deprecated. Use 'max-video-height' instead");
115 : case PROP_MAX_VIDEO_HEIGHT:
116 : {
117 2 : g_value_set_uint(value, 0); // Set default value
118 2 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
119 2 : IPlaybackDelegate::Property::MaxVideoHeight, value);
120 2 : break;
121 : }
122 1 : case PROP_FRAME_STEP_ON_PREROLL:
123 : {
124 1 : g_value_set_boolean(value, FALSE); // Set default value
125 1 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
126 1 : IPlaybackDelegate::Property::FrameStepOnPreroll, value);
127 1 : break;
128 : }
129 3 : case PROP_QUEUED_FRAMES:
130 : {
131 3 : g_value_set_uint(value, 0); // Set default value
132 3 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
133 3 : IPlaybackDelegate::Property::QueuedFrames, value);
134 3 : break;
135 : }
136 3 : case PROP_IMMEDIATE_OUTPUT:
137 : {
138 3 : g_value_set_boolean(value, FALSE); // Set default value
139 3 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
140 3 : IPlaybackDelegate::Property::ImmediateOutput, value);
141 3 : break;
142 : }
143 1 : case PROP_IS_MASTER:
144 : {
145 1 : g_value_set_boolean(value, TRUE); // Set default value
146 : std::unique_ptr<firebolt::rialto::IMediaPipelineCapabilities> mediaPlayerCapabilities =
147 1 : firebolt::rialto::IMediaPipelineCapabilitiesFactory::createFactory()->createMediaPipelineCapabilities();
148 1 : bool isMaster{false};
149 1 : if (mediaPlayerCapabilities && mediaPlayerCapabilities->isVideoMaster(isMaster))
150 : {
151 1 : g_value_set_boolean(value, isMaster);
152 : }
153 1 : break;
154 : }
155 2 : case PROP_VIDEO_PTS:
156 : {
157 2 : g_value_set_int64(value, 0); // Set default value
158 2 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::VideoPts,
159 : value);
160 2 : break;
161 : }
162 1 : default:
163 1 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
164 1 : break;
165 : }
166 20 : }
167 :
168 28 : static void rialto_mse_video_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
169 : {
170 28 : switch (propId)
171 : {
172 4 : case PROP_WINDOW_SET:
173 : {
174 4 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::WindowSet,
175 : value);
176 4 : break;
177 : }
178 2 : case PROP_MAX_VIDEO_WIDTH:
179 : case PROP_MAX_VIDEO_WIDTH_DEPRECATED:
180 2 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
181 2 : IPlaybackDelegate::Property::MaxVideoWidth, value);
182 2 : break;
183 2 : case PROP_MAX_VIDEO_HEIGHT:
184 : case PROP_MAX_VIDEO_HEIGHT_DEPRECATED:
185 2 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
186 2 : IPlaybackDelegate::Property::MaxVideoHeight, value);
187 2 : break;
188 5 : case PROP_FRAME_STEP_ON_PREROLL:
189 : {
190 5 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
191 5 : IPlaybackDelegate::Property::FrameStepOnPreroll, value);
192 5 : break;
193 : }
194 4 : case PROP_REPORT_DECODE_ERRORS:
195 : {
196 4 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
197 4 : IPlaybackDelegate::Property::ReportDecodeErrors, value);
198 4 : break;
199 : }
200 4 : case PROP_IMMEDIATE_OUTPUT:
201 : {
202 4 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
203 4 : IPlaybackDelegate::Property::ImmediateOutput, value);
204 4 : break;
205 : }
206 4 : case PROP_SYNCMODE_STREAMING:
207 : {
208 4 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
209 4 : IPlaybackDelegate::Property::SyncmodeStreaming, value);
210 4 : break;
211 : }
212 2 : case PROP_SHOW_VIDEO_WINDOW:
213 : {
214 2 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
215 2 : IPlaybackDelegate::Property::ShowVideoWindow, value);
216 2 : break;
217 : }
218 1 : default:
219 1 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
220 1 : break;
221 : }
222 28 : }
223 :
224 69 : static void rialto_mse_video_sink_init(RialtoMSEVideoSink *sink)
225 : {
226 69 : RialtoMSEBaseSinkPrivate *basePriv = sink->parent.priv;
227 :
228 69 : if (!rialto_mse_base_sink_initialise_sinkpad(RIALTO_MSE_BASE_SINK(sink)))
229 : {
230 0 : GST_ERROR_OBJECT(sink, "Failed to initialise VIDEO sink. Sink pad initialisation failed.");
231 0 : return;
232 : }
233 :
234 69 : gst_pad_set_chain_function(basePriv->m_sinkPad, rialto_mse_base_sink_chain);
235 69 : gst_pad_set_event_function(basePriv->m_sinkPad, rialto_mse_base_sink_event);
236 : }
237 :
238 1 : static void rialto_mse_video_sink_class_init(RialtoMSEVideoSinkClass *klass)
239 : {
240 1 : GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
241 1 : GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
242 1 : gobjectClass->get_property = rialto_mse_video_sink_get_property;
243 1 : gobjectClass->set_property = rialto_mse_video_sink_set_property;
244 1 : elementClass->change_state = rialto_mse_video_sink_change_state;
245 :
246 1 : g_object_class_install_property(gobjectClass, PROP_WINDOW_SET,
247 : g_param_spec_string("rectangle", "rectangle", "Window Set Format: x,y,width,height",
248 : nullptr, GParamFlags(G_PARAM_READWRITE)));
249 :
250 1 : g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_WIDTH,
251 : g_param_spec_uint("max-video-width",
252 : "max video width", "Maximum width of video frames to be decoded. Should only be set for video only streams.",
253 : 0, 3840, DEFAULT_MAX_VIDEO_WIDTH, GParamFlags(G_PARAM_READWRITE)));
254 :
255 1 : g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_HEIGHT,
256 : g_param_spec_uint("max-video-height",
257 : "max video height", "Maximum height of video frames to be decoded. should only be set for video only streams.",
258 : 0, 2160, DEFAULT_MAX_VIDEO_HEIGHT, GParamFlags(G_PARAM_READWRITE)));
259 :
260 1 : g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_WIDTH_DEPRECATED,
261 : g_param_spec_uint("maxVideoWidth", "maxVideoWidth", "[DEPRECATED] Use max-video-width",
262 : 0, 3840, DEFAULT_MAX_VIDEO_WIDTH, GParamFlags(G_PARAM_READWRITE)));
263 :
264 1 : g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_HEIGHT_DEPRECATED,
265 : g_param_spec_uint("maxVideoHeight", "maxVideoHeight", "[DEPRECATED] max-video-height",
266 : 0, 2160, DEFAULT_MAX_VIDEO_HEIGHT, GParamFlags(G_PARAM_READWRITE)));
267 :
268 1 : g_object_class_install_property(gobjectClass, PROP_FRAME_STEP_ON_PREROLL,
269 : g_param_spec_boolean("frame-step-on-preroll", "frame step on preroll",
270 : "allow frame stepping on preroll into pause", FALSE,
271 : G_PARAM_READWRITE));
272 1 : g_object_class_install_property(gobjectClass, PROP_REPORT_DECODE_ERRORS,
273 : g_param_spec_boolean("report-decode-errors", "Report decode errors",
274 : "Enable reporting of decode errors", FALSE, G_PARAM_WRITABLE));
275 :
276 1 : g_object_class_install_property(gobjectClass, PROP_QUEUED_FRAMES,
277 : g_param_spec_uint("queued-frames", "Queued frames",
278 : "Number of frames currently queued in decoder", 0, G_MAXUINT, 0,
279 : G_PARAM_READABLE));
280 1 : g_object_class_install_property(gobjectClass, PROP_IS_MASTER,
281 : g_param_spec_boolean("is-master", "is master",
282 : "Checks if the platform is video master", TRUE,
283 : G_PARAM_READABLE));
284 1 : g_object_class_install_property(gobjectClass, PROP_VIDEO_PTS,
285 : g_param_spec_int64("video_pts", "video PTS", "current video PTS value", G_MININT64,
286 : G_MAXINT64, 0, G_PARAM_READABLE));
287 1 : g_object_class_install_property(gobjectClass, PROP_SHOW_VIDEO_WINDOW,
288 : g_param_spec_boolean("show-video-window", "make video window visible",
289 : "true: visible, false: hidden", TRUE, G_PARAM_WRITABLE));
290 :
291 1 : g_signals[SIGNAL_FIRST_VIDEO_FRAME_RECEIVED] = g_signal_new("first-video-frame-callback", G_TYPE_FROM_CLASS(klass),
292 : (GSignalFlags)(G_SIGNAL_RUN_LAST), 0, nullptr, nullptr,
293 : g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2,
294 : G_TYPE_UINT, G_TYPE_POINTER);
295 :
296 : std::unique_ptr<firebolt::rialto::IMediaPipelineCapabilities> mediaPlayerCapabilities =
297 1 : firebolt::rialto::IMediaPipelineCapabilitiesFactory::createFactory()->createMediaPipelineCapabilities();
298 1 : if (mediaPlayerCapabilities)
299 : {
300 : std::vector<std::string> supportedMimeTypes =
301 1 : mediaPlayerCapabilities->getSupportedMimeTypes(firebolt::rialto::MediaSourceType::VIDEO);
302 :
303 1 : rialto_mse_sink_setup_supported_caps(elementClass, supportedMimeTypes);
304 :
305 2 : const std::string kImmediateOutputPropertyName{"immediate-output"};
306 1 : const std::string kSyncmodeStreamingPropertyName{"syncmode-streaming"};
307 : const std::vector<std::string> kPropertyNamesToSearch{kImmediateOutputPropertyName,
308 4 : kSyncmodeStreamingPropertyName};
309 : std::vector<std::string> supportedProperties{
310 1 : mediaPlayerCapabilities->getSupportedProperties(firebolt::rialto::MediaSourceType::VIDEO,
311 1 : kPropertyNamesToSearch)};
312 :
313 3 : for (const auto &propertyName : supportedProperties)
314 : {
315 2 : if (kImmediateOutputPropertyName == propertyName)
316 : {
317 1 : g_object_class_install_property(gobjectClass, PROP_IMMEDIATE_OUTPUT,
318 : g_param_spec_boolean(kImmediateOutputPropertyName.c_str(),
319 : "immediate output", "immediate output", TRUE,
320 : GParamFlags(G_PARAM_READWRITE)));
321 : }
322 1 : else if (kSyncmodeStreamingPropertyName == propertyName)
323 : {
324 1 : g_object_class_install_property(gobjectClass, PROP_SYNCMODE_STREAMING,
325 : g_param_spec_boolean("syncmode-streaming", "Streaming Sync Mode",
326 : "Enable/disable OTT streaming sync mode", FALSE,
327 : G_PARAM_WRITABLE));
328 : }
329 : }
330 : }
331 : else
332 : {
333 0 : GST_ERROR("Failed to get supported mime types for VIDEO");
334 : }
335 :
336 1 : gst_element_class_set_details_simple(elementClass, "Rialto Video Sink", "Decoder/Video/Sink/Video",
337 : "Communicates with Rialto Server", "Sky");
338 2 : }
|