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 183 : 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_LAST
55 : };
56 :
57 180 : static GstStateChangeReturn rialto_mse_video_sink_change_state(GstElement *element, GstStateChange transition)
58 : {
59 180 : RialtoMSEVideoSink *sink = RIALTO_MSE_VIDEO_SINK(element);
60 180 : if (GST_STATE_CHANGE_NULL_TO_READY == transition)
61 : {
62 60 : GST_INFO_OBJECT(sink, "RialtoMSEVideoSink state change to READY. Initializing delegate");
63 60 : auto delegate = std::make_shared<PullModeVideoPlaybackDelegate>(element);
64 60 : delegate->createControlBackend();
65 60 : rialto_mse_base_sink_initialise_delegate(RIALTO_MSE_BASE_SINK(sink), delegate);
66 : }
67 180 : GstStateChangeReturn result = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
68 180 : if (G_UNLIKELY(result == GST_STATE_CHANGE_FAILURE))
69 : {
70 1 : GST_WARNING_OBJECT(sink, "State change failed");
71 1 : return result;
72 : }
73 :
74 179 : return result;
75 : }
76 :
77 17 : static void rialto_mse_video_sink_get_property(GObject *object, guint propId, GValue *value, GParamSpec *pspec)
78 : {
79 17 : switch (propId)
80 : {
81 5 : case PROP_WINDOW_SET:
82 : {
83 5 : g_value_set_string(value, "0,0,1920,1080"); // Set default value
84 5 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::WindowSet,
85 : value);
86 5 : break;
87 : }
88 1 : case PROP_MAX_VIDEO_WIDTH_DEPRECATED:
89 1 : GST_WARNING_OBJECT(object, "MaxVideoWidth property is deprecated. Use 'max-video-width' instead");
90 : case PROP_MAX_VIDEO_WIDTH:
91 : {
92 2 : g_value_set_uint(value, 0); // Set default value
93 2 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
94 2 : IPlaybackDelegate::Property::MaxVideoWidth, value);
95 2 : break;
96 : }
97 1 : case PROP_MAX_VIDEO_HEIGHT_DEPRECATED:
98 1 : GST_WARNING_OBJECT(object, "MaxVideoHeight property is deprecated. Use 'max-video-height' instead");
99 : case PROP_MAX_VIDEO_HEIGHT:
100 : {
101 2 : g_value_set_uint(value, 0); // Set default value
102 2 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
103 2 : IPlaybackDelegate::Property::MaxVideoHeight, value);
104 2 : break;
105 : }
106 1 : case PROP_FRAME_STEP_ON_PREROLL:
107 : {
108 1 : g_value_set_boolean(value, FALSE); // Set default value
109 1 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
110 1 : IPlaybackDelegate::Property::FrameStepOnPreroll, value);
111 1 : break;
112 : }
113 3 : case PROP_IMMEDIATE_OUTPUT:
114 : {
115 3 : g_value_set_boolean(value, FALSE); // Set default value
116 3 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object),
117 3 : IPlaybackDelegate::Property::ImmediateOutput, value);
118 3 : break;
119 : }
120 1 : case PROP_IS_MASTER:
121 : {
122 1 : g_value_set_boolean(value, TRUE); // Set default value
123 : std::unique_ptr<firebolt::rialto::IMediaPipelineCapabilities> mediaPlayerCapabilities =
124 1 : firebolt::rialto::IMediaPipelineCapabilitiesFactory::createFactory()->createMediaPipelineCapabilities();
125 1 : bool isMaster{false};
126 1 : if (mediaPlayerCapabilities && mediaPlayerCapabilities->isVideoMaster(isMaster))
127 : {
128 1 : g_value_set_boolean(value, isMaster);
129 : }
130 1 : break;
131 : }
132 2 : case PROP_VIDEO_PTS:
133 : {
134 2 : g_value_set_int64(value, 0); // Set default value
135 2 : rialto_mse_base_sink_handle_get_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::VideoPts,
136 : value);
137 2 : break;
138 : }
139 1 : default:
140 1 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
141 1 : break;
142 : }
143 17 : }
144 :
145 24 : static void rialto_mse_video_sink_set_property(GObject *object, guint propId, const GValue *value, GParamSpec *pspec)
146 : {
147 24 : switch (propId)
148 : {
149 4 : case PROP_WINDOW_SET:
150 : {
151 4 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object), IPlaybackDelegate::Property::WindowSet,
152 : value);
153 4 : break;
154 : }
155 2 : case PROP_MAX_VIDEO_WIDTH:
156 : case PROP_MAX_VIDEO_WIDTH_DEPRECATED:
157 2 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
158 2 : IPlaybackDelegate::Property::MaxVideoWidth, value);
159 2 : break;
160 2 : case PROP_MAX_VIDEO_HEIGHT:
161 : case PROP_MAX_VIDEO_HEIGHT_DEPRECATED:
162 2 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
163 2 : IPlaybackDelegate::Property::MaxVideoHeight, value);
164 2 : break;
165 5 : case PROP_FRAME_STEP_ON_PREROLL:
166 : {
167 5 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
168 5 : IPlaybackDelegate::Property::FrameStepOnPreroll, value);
169 5 : break;
170 : }
171 4 : case PROP_IMMEDIATE_OUTPUT:
172 : {
173 4 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
174 4 : IPlaybackDelegate::Property::ImmediateOutput, value);
175 4 : break;
176 : }
177 4 : case PROP_SYNCMODE_STREAMING:
178 : {
179 4 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
180 4 : IPlaybackDelegate::Property::SyncmodeStreaming, value);
181 4 : break;
182 : }
183 2 : case PROP_SHOW_VIDEO_WINDOW:
184 : {
185 2 : rialto_mse_base_sink_handle_set_property(RIALTO_MSE_BASE_SINK(object),
186 2 : IPlaybackDelegate::Property::ShowVideoWindow, value);
187 2 : break;
188 : }
189 1 : default:
190 1 : G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
191 1 : break;
192 : }
193 24 : }
194 :
195 60 : static void rialto_mse_video_sink_init(RialtoMSEVideoSink *sink)
196 : {
197 60 : RialtoMSEBaseSinkPrivate *basePriv = sink->parent.priv;
198 :
199 60 : if (!rialto_mse_base_sink_initialise_sinkpad(RIALTO_MSE_BASE_SINK(sink)))
200 : {
201 0 : GST_ERROR_OBJECT(sink, "Failed to initialise VIDEO sink. Sink pad initialisation failed.");
202 0 : return;
203 : }
204 :
205 60 : gst_pad_set_chain_function(basePriv->m_sinkPad, rialto_mse_base_sink_chain);
206 60 : gst_pad_set_event_function(basePriv->m_sinkPad, rialto_mse_base_sink_event);
207 : }
208 :
209 1 : static void rialto_mse_video_sink_class_init(RialtoMSEVideoSinkClass *klass)
210 : {
211 1 : GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
212 1 : GstElementClass *elementClass = GST_ELEMENT_CLASS(klass);
213 1 : gobjectClass->get_property = rialto_mse_video_sink_get_property;
214 1 : gobjectClass->set_property = rialto_mse_video_sink_set_property;
215 1 : elementClass->change_state = rialto_mse_video_sink_change_state;
216 :
217 1 : g_object_class_install_property(gobjectClass, PROP_WINDOW_SET,
218 : g_param_spec_string("rectangle", "rectangle", "Window Set Format: x,y,width,height",
219 : nullptr, GParamFlags(G_PARAM_READWRITE)));
220 :
221 1 : g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_WIDTH,
222 : g_param_spec_uint("max-video-width",
223 : "max video width", "Maximum width of video frames to be decoded. Should only be set for video only streams.",
224 : 0, 3840, DEFAULT_MAX_VIDEO_WIDTH, GParamFlags(G_PARAM_READWRITE)));
225 :
226 1 : g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_HEIGHT,
227 : g_param_spec_uint("max-video-height",
228 : "max video height", "Maximum height of video frames to be decoded. should only be set for video only streams.",
229 : 0, 2160, DEFAULT_MAX_VIDEO_HEIGHT, GParamFlags(G_PARAM_READWRITE)));
230 :
231 1 : g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_WIDTH_DEPRECATED,
232 : g_param_spec_uint("maxVideoWidth", "maxVideoWidth", "[DEPRECATED] Use max-video-width",
233 : 0, 3840, DEFAULT_MAX_VIDEO_WIDTH, GParamFlags(G_PARAM_READWRITE)));
234 :
235 1 : g_object_class_install_property(gobjectClass, PROP_MAX_VIDEO_HEIGHT_DEPRECATED,
236 : g_param_spec_uint("maxVideoHeight", "maxVideoHeight", "[DEPRECATED] max-video-height",
237 : 0, 2160, DEFAULT_MAX_VIDEO_HEIGHT, GParamFlags(G_PARAM_READWRITE)));
238 :
239 1 : g_object_class_install_property(gobjectClass, PROP_FRAME_STEP_ON_PREROLL,
240 : g_param_spec_boolean("frame-step-on-preroll", "frame step on preroll",
241 : "allow frame stepping on preroll into pause", FALSE,
242 : G_PARAM_READWRITE));
243 1 : g_object_class_install_property(gobjectClass, PROP_IS_MASTER,
244 : g_param_spec_boolean("is-master", "is master",
245 : "Checks if the platform is video master", TRUE,
246 : G_PARAM_READABLE));
247 1 : g_object_class_install_property(gobjectClass, PROP_VIDEO_PTS,
248 : g_param_spec_int64("video_pts", "video PTS", "current video PTS value", G_MININT64,
249 : G_MAXINT64, 0, G_PARAM_READABLE));
250 :
251 : std::unique_ptr<firebolt::rialto::IMediaPipelineCapabilities> mediaPlayerCapabilities =
252 1 : firebolt::rialto::IMediaPipelineCapabilitiesFactory::createFactory()->createMediaPipelineCapabilities();
253 1 : if (mediaPlayerCapabilities)
254 : {
255 : std::vector<std::string> supportedMimeTypes =
256 1 : mediaPlayerCapabilities->getSupportedMimeTypes(firebolt::rialto::MediaSourceType::VIDEO);
257 :
258 1 : rialto_mse_sink_setup_supported_caps(elementClass, supportedMimeTypes);
259 :
260 2 : const std::string kImmediateOutputPropertyName{"immediate-output"};
261 2 : const std::string kSyncmodeStreamingPropertyName{"syncmode-streaming"};
262 1 : const std::string kShowVideoWindowPropertyName{"show-video-window"};
263 : const std::vector<std::string> kPropertyNamesToSearch{kImmediateOutputPropertyName,
264 : kSyncmodeStreamingPropertyName,
265 5 : kShowVideoWindowPropertyName};
266 : std::vector<std::string> supportedProperties{
267 1 : mediaPlayerCapabilities->getSupportedProperties(firebolt::rialto::MediaSourceType::VIDEO,
268 1 : kPropertyNamesToSearch)};
269 :
270 4 : for (const auto &propertyName : supportedProperties)
271 : {
272 3 : if (kImmediateOutputPropertyName == propertyName)
273 : {
274 1 : g_object_class_install_property(gobjectClass, PROP_IMMEDIATE_OUTPUT,
275 : g_param_spec_boolean(kImmediateOutputPropertyName.c_str(),
276 : "immediate output", "immediate output", TRUE,
277 : GParamFlags(G_PARAM_READWRITE)));
278 : }
279 2 : else if (kSyncmodeStreamingPropertyName == propertyName)
280 : {
281 1 : g_object_class_install_property(gobjectClass, PROP_SYNCMODE_STREAMING,
282 : g_param_spec_boolean("syncmode-streaming", "Streaming Sync Mode",
283 : "Enable/disable OTT streaming sync mode", FALSE,
284 : G_PARAM_WRITABLE));
285 : }
286 1 : else if (kShowVideoWindowPropertyName == propertyName)
287 : {
288 1 : g_object_class_install_property(gobjectClass, PROP_SHOW_VIDEO_WINDOW,
289 : g_param_spec_boolean(kShowVideoWindowPropertyName.c_str(),
290 : "make video window visible",
291 : "true: visible, false: hidden", TRUE,
292 : G_PARAM_WRITABLE));
293 : }
294 : }
295 : }
296 : else
297 : {
298 0 : GST_ERROR("Failed to get supported mime types for VIDEO");
299 : }
300 :
301 1 : gst_element_class_set_details_simple(elementClass, "Rialto Video Sink", "Decoder/Video/Sink/Video",
302 : "Communicates with Rialto Server", "Sky");
303 2 : }
|