RDK Documentation (Open Sourced RDK Components)
GstMSESrc.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2017 RDK Management
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 "GstMSESrc.h"
21 
22 #include <gst/app/gstappsrc.h>
23 #include <gst/gst.h>
24 
25 #define GST_MSE_SRC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), GST_MSE_TYPE_SRC, GstMSESrcPrivate))
27  gchar* uri;
28  guint pad_counter;
29  gboolean configured;
30 };
31 
32 enum {
33  PROP_0,
34  PROP_LOCATION
35 };
36 
37 static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE("src_%u",
38  GST_PAD_SRC,
39  GST_PAD_SOMETIMES,
40  GST_STATIC_CAPS_ANY);
41 
42 GST_DEBUG_CATEGORY_STATIC(gst_mse_src_debug);
43 #define GST_CAT_DEFAULT gst_mse_src_debug
44 
45 static void gst_mse_src_uri_handler_init(gpointer gIface, gpointer ifaceData);
46 
47 static void gst_mse_src_dispose(GObject*);
48 static void gst_mse_src_finalize(GObject*);
49 static void gst_mse_src_set_property(GObject*, guint propertyID, const GValue*, GParamSpec*);
50 static GstStateChangeReturn gst_mse_src_change_state(GstElement*, GstStateChange);
51 static void gst_mse_src_handle_message(GstBin*, GstMessage*);
52 static gboolean gst_mse_src_query_with_parent(GstPad*, GstObject*, GstQuery*);
53 static void gst_mse_src_get_property(GObject*, guint propertyID, GValue*, GParamSpec*);
54 
55 #define gst_mse_src_parent_class parent_class
56 G_DEFINE_TYPE_WITH_CODE(GstMSESrc, gst_mse_src, GST_TYPE_BIN,
57  G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, gst_mse_src_uri_handler_init);
58  GST_DEBUG_CATEGORY_INIT(gst_mse_src_debug, "msesrc", 0, "mse src element"););
59 
60 static void gst_mse_src_class_init(GstMSESrcClass* klass)
61 {
62  GObjectClass* oklass = G_OBJECT_CLASS(klass);
63  GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
64  GstBinClass* bklass = GST_BIN_CLASS(klass);
65 
66  oklass->dispose = gst_mse_src_dispose;
67  oklass->finalize = gst_mse_src_finalize;
68  oklass->set_property = gst_mse_src_set_property;
69  oklass->get_property = gst_mse_src_get_property;
70 
71  gst_element_class_add_pad_template(eklass,
72  gst_static_pad_template_get(&srcTemplate));
73 
74  g_object_class_install_property(oklass,
75  PROP_LOCATION,
76  g_param_spec_string("location",
77  "location",
78  "Location to read from",
79  0,
80  (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
81 
82 
83  eklass->change_state = GST_DEBUG_FUNCPTR(gst_mse_src_change_state);
84  // eklass->send_event = gst_mse_src_send_event;
85 
86  bklass->handle_message = GST_DEBUG_FUNCPTR(gst_mse_src_handle_message);
87 
88  g_type_class_add_private(klass, sizeof(GstMSESrcPrivate));
89 }
90 
91 static void gst_mse_src_init(GstMSESrc* src)
92 {
93  GstMSESrcPrivate* priv = GST_MSE_SRC_GET_PRIVATE(src);
94 
95  src->priv = priv;
96  src->priv->configured = FALSE;
97  src->priv->pad_counter = 0;
98 
99  g_object_set(GST_BIN(src), "message-forward", TRUE, NULL);
100 }
101 
102 static void gst_mse_src_dispose(GObject* object)
103 {
104  GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object));
105 }
106 
107 static void gst_mse_src_finalize(GObject* object)
108 {
109  GstMSESrc* src = GST_MSE_SRC(object);
110  GstMSESrcPrivate* priv = src->priv;
111 
112  g_free(priv->uri);
113  priv->~GstMSESrcPrivate();
114 
115  GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
116 }
117 
118 static void gst_mse_src_set_property(GObject* object, guint prop, const GValue* value, GParamSpec* pspec)
119 {
120  GstMSESrc* src = GST_MSE_SRC(object);
121  const gchar* uri = NULL;
122 
123  switch (prop) {
124  case PROP_LOCATION:
125  uri = g_value_get_string(value);
126  gst_uri_handler_set_uri((GstURIHandler*)(src), uri, 0);
127  break;
128  default:
129  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop, pspec);
130  break;
131  }
132 }
133 
134 
135 static GstStateChangeReturn gst_mse_src_change_state(GstElement* element, GstStateChange transition)
136 {
137  GstMSESrc* src = GST_MSE_SRC(element);
138  GstMSESrcPrivate* priv = src->priv;
139  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
140 
141  ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
142  return ret;
143 }
144 
145 
146 // uri handler interface
147 
148 static GstURIType gst_mse_src_uri_get_type(GType)
149 {
150  return GST_URI_SRC;
151 }
152 
153 const gchar* const* gst_mse_src_get_protocols(GType)
154 {
155  static const char* protocols[] = {"mse", 0 };
156  return protocols;
157 }
158 
159 static gchar* gst_mse_src_get_uri(GstURIHandler* handler)
160 {
161  GstMSESrc* src = GST_MSE_SRC(handler);
162  gchar* ret;
163 
164  GST_OBJECT_LOCK(src);
165  ret = g_strdup(src->priv->uri);
166  GST_OBJECT_UNLOCK(src);
167  return ret;
168 }
169 
170 static gboolean gst_mse_src_set_uri(GstURIHandler* handler, const gchar* uri, GError** error)
171 {
172  GstMSESrc* src = GST_MSE_SRC(handler);
173  GstMSESrcPrivate* priv = src->priv;
174 
175  if (GST_STATE(src) >= GST_STATE_PAUSED) {
176  GST_ERROR_OBJECT(src, "URI can only be set in states < PAUSED");
177  return FALSE;
178  }
179 
180  GST_OBJECT_LOCK(src);
181 
182  g_free(priv->uri);
183  priv->uri = 0;
184 
185  if (!uri) {
186  GST_OBJECT_UNLOCK(src);
187  return TRUE;
188  }
189 
190  priv->uri = g_strdup(uri);
191  GST_OBJECT_UNLOCK(src);
192  return TRUE;
193 }
194 
195 static void gst_mse_src_uri_handler_init(gpointer gIface, gpointer)
196 {
197  GstURIHandlerInterface* iface = (GstURIHandlerInterface *) gIface;
198 
199  iface->get_type = gst_mse_src_uri_get_type;
200  iface->get_protocols = gst_mse_src_get_protocols;
201  iface->get_uri = gst_mse_src_get_uri;
202  iface->set_uri = gst_mse_src_set_uri;
203 }
204 
205 static gboolean gst_mse_src_query_with_parent(GstPad* pad, GstObject* parent, GstQuery* query)
206 {
207  GstMSESrc* src = GST_MSE_SRC(GST_ELEMENT(parent));
208  gboolean result = FALSE;
209 
210  switch (GST_QUERY_TYPE(query)) {
211  default:{
212  GstPad* target = gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(pad));
213  // Forward the query to the proxy target pad.
214  if (target)
215  result = gst_pad_query(target, query);
216  gst_object_unref(target);
217  break;
218  }
219  }
220 
221  return result;
222 }
223 
224 void gst_mse_src_handle_message(GstBin* bin, GstMessage* message)
225 {
226  GstMSESrc* src = GST_MSE_SRC(GST_ELEMENT(bin));
227 
228  switch (GST_MESSAGE_TYPE(message)) {
229  case GST_MESSAGE_EOS: {
230  gboolean emit_eos = TRUE;
231  GstPad* pad = gst_element_get_static_pad(GST_ELEMENT(GST_MESSAGE_SRC(message)), "src");
232 
233  GST_DEBUG_OBJECT(src, "EOS received from %s", GST_MESSAGE_SRC_NAME(message));
234  g_object_set_data(G_OBJECT(pad), "is-eos", GINT_TO_POINTER(1));
235  gst_object_unref(pad);
236  for (guint i = 0; i < src->priv->pad_counter; i++) {
237  gchar* name = g_strdup_printf("src_%u", i);
238  GstPad* src_pad = gst_element_get_static_pad(GST_ELEMENT(src), name);
239  GstPad* target = gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(src_pad));
240  gint is_eos = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(target), "is-eos"));
241  gst_object_unref(target);
242  gst_object_unref(src_pad);
243  g_free(name);
244 
245  if (!is_eos) {
246  emit_eos = FALSE;
247  break;
248  }
249  }
250 
251  gst_message_unref(message);
252 
253  if (emit_eos) {
254  GST_DEBUG_OBJECT(src, "All appsrc elements are EOS, emitting event now.");
255  gst_element_send_event(GST_ELEMENT(bin), gst_event_new_eos());
256  }
257  break;
258  }
259  default:
260  GST_BIN_CLASS(parent_class)->handle_message(bin, message);
261  break;
262  }
263 }
264 
265 void gst_mse_src_register_player(GstElement* element, GstElement* appsrc)
266 {
267  GstMSESrc* src = GST_MSE_SRC(element);
268  gchar* name = g_strdup_printf("src_%u", src->priv->pad_counter);
269 
270  src->priv->pad_counter++;
271 
272  gst_bin_add(GST_BIN(element), appsrc);
273  GstPad* target = gst_element_get_static_pad(appsrc, "src");
274  GstPad* pad = gst_ghost_pad_new(name, target);
275 
276  gst_pad_set_query_function(pad, gst_mse_src_query_with_parent);
277  gst_pad_set_active(pad, TRUE);
278 
279  gst_element_add_pad(element, pad);
280  GST_OBJECT_FLAG_SET(pad, GST_PAD_FLAG_NEED_PARENT);
281 
282  gst_element_sync_state_with_parent(appsrc);
283 
284  g_free(name);
285  gst_object_unref(target);
286 }
287 
288 void gst_mse_src_unregister_player(GstElement* element, GstElement* appsrc)
289 {
290  GstMSESrc* src = GST_MSE_SRC(element);
291  GstPad* pad = gst_element_get_static_pad(appsrc, "src");
292  GstPad* peer = gst_pad_get_peer(pad);
293 
294  GST_DEBUG_OBJECT(src, "Unregistering player from pad %s, appsrc: %p", GST_PAD_NAME(pad), appsrc);
295 
296  if (peer) {
297  GstPad* ghost = GST_PAD_CAST(gst_proxy_pad_get_internal(GST_PROXY_PAD(peer)));
298 
299  if (ghost) {
300  gst_ghost_pad_set_target(GST_GHOST_PAD_CAST(ghost), NULL);
301  gst_element_remove_pad(element, ghost);
302  gst_object_unref(ghost);
303  }
304 
305  gst_object_unref(peer);
306  }
307 
308  gst_app_src_end_of_stream(GST_APP_SRC(appsrc));
309 
310  gst_element_set_state(appsrc, GST_STATE_NULL);
311  gst_bin_remove(GST_BIN(src), appsrc);
312 
313  if (src->priv->pad_counter > 0)
314  src->priv->pad_counter--;
315 
316  if (GST_BIN_NUMCHILDREN(src) == 0) {
317  GST_DEBUG_OBJECT(src, "No player left, unconfiguring");
318  src->priv->configured = FALSE;
319  }
320 }
321 
322 void gst_mse_src_configuration_done(GstElement* element)
323 {
324  GstMSESrc* src = GST_MSE_SRC(element);
325 
326  src->priv->configured = TRUE;
327  GST_DEBUG_OBJECT(src, "All players registered, proceeding with state-change completion");
328  gst_element_no_more_pads(element);
329 }
330 
331 gboolean gst_mse_src_configured(GstElement* element)
332 {
333  GstMSESrc* src = GST_MSE_SRC(element);
334  return src->priv->configured;
335 }
336 
337 static void gst_mse_src_get_property(GObject* object, guint prop, GValue* value, GParamSpec* pspec)
338 {
339  GstMSESrc* src = GST_MSE_SRC(object);
340  GstMSESrcPrivate* priv = src->priv;
341 
342  GST_OBJECT_LOCK(src);
343  switch (prop) {
344  case PROP_LOCATION:
345  g_value_set_string(value, priv->uri);
346  break;
347  default:
348  G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop, pspec);
349  break;
350  }
351  GST_OBJECT_UNLOCK(src);
352 }
_GstMSESrcClass
Definition: GstMSESrc.h:43
_GstMSESrcPrivate
Definition: GstMSESrc.cpp:26
_GstMSESrc
Definition: GstMSESrc.h:37
TRUE
#define TRUE
Defines for TRUE/FALSE/ENABLE flags.
Definition: wifi_common_hal.h:199