20 #include "GstMSESrc.h"
22 #include <gst/app/gstappsrc.h>
25 #define GST_MSE_SRC_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), GST_MSE_TYPE_SRC, GstMSESrcPrivate))
37 static GstStaticPadTemplate srcTemplate = GST_STATIC_PAD_TEMPLATE(
"src_%u",
42 GST_DEBUG_CATEGORY_STATIC(gst_mse_src_debug);
43 #define GST_CAT_DEFAULT gst_mse_src_debug
45 static void gst_mse_src_uri_handler_init(gpointer gIface, gpointer ifaceData);
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*);
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"););
62 GObjectClass* oklass = G_OBJECT_CLASS(klass);
63 GstElementClass* eklass = GST_ELEMENT_CLASS(klass);
64 GstBinClass* bklass = GST_BIN_CLASS(klass);
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;
71 gst_element_class_add_pad_template(eklass,
72 gst_static_pad_template_get(&srcTemplate));
74 g_object_class_install_property(oklass,
76 g_param_spec_string(
"location",
78 "Location to read from",
80 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
83 eklass->change_state = GST_DEBUG_FUNCPTR(gst_mse_src_change_state);
86 bklass->handle_message = GST_DEBUG_FUNCPTR(gst_mse_src_handle_message);
91 static void gst_mse_src_init(
GstMSESrc* src)
96 src->priv->configured = FALSE;
97 src->priv->pad_counter = 0;
99 g_object_set(GST_BIN(src),
"message-forward",
TRUE, NULL);
102 static void gst_mse_src_dispose(GObject*
object)
104 GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (
object));
107 static void gst_mse_src_finalize(GObject*
object)
113 priv->~GstMSESrcPrivate();
115 GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (
object));
118 static void gst_mse_src_set_property(GObject*
object, guint prop,
const GValue* value, GParamSpec* pspec)
121 const gchar* uri = NULL;
125 uri = g_value_get_string(value);
126 gst_uri_handler_set_uri((GstURIHandler*)(src), uri, 0);
129 G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop, pspec);
135 static GstStateChangeReturn gst_mse_src_change_state(GstElement* element, GstStateChange transition)
139 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
141 ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
148 static GstURIType gst_mse_src_uri_get_type(GType)
153 const gchar*
const* gst_mse_src_get_protocols(GType)
155 static const char* protocols[] = {
"mse", 0 };
159 static gchar* gst_mse_src_get_uri(GstURIHandler* handler)
164 GST_OBJECT_LOCK(src);
165 ret = g_strdup(src->priv->uri);
166 GST_OBJECT_UNLOCK(src);
170 static gboolean gst_mse_src_set_uri(GstURIHandler* handler,
const gchar* uri, GError** error)
175 if (GST_STATE(src) >= GST_STATE_PAUSED) {
176 GST_ERROR_OBJECT(src,
"URI can only be set in states < PAUSED");
180 GST_OBJECT_LOCK(src);
186 GST_OBJECT_UNLOCK(src);
190 priv->uri = g_strdup(uri);
191 GST_OBJECT_UNLOCK(src);
195 static void gst_mse_src_uri_handler_init(gpointer gIface, gpointer)
197 GstURIHandlerInterface* iface = (GstURIHandlerInterface *) gIface;
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;
205 static gboolean gst_mse_src_query_with_parent(GstPad* pad, GstObject* parent, GstQuery* query)
207 GstMSESrc* src = GST_MSE_SRC(GST_ELEMENT(parent));
208 gboolean result = FALSE;
210 switch (GST_QUERY_TYPE(query)) {
212 GstPad* target = gst_ghost_pad_get_target(GST_GHOST_PAD_CAST(pad));
215 result = gst_pad_query(target, query);
216 gst_object_unref(target);
224 void gst_mse_src_handle_message(GstBin* bin, GstMessage* message)
226 GstMSESrc* src = GST_MSE_SRC(GST_ELEMENT(bin));
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");
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);
251 gst_message_unref(message);
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());
260 GST_BIN_CLASS(parent_class)->handle_message(bin, message);
265 void gst_mse_src_register_player(GstElement* element, GstElement* appsrc)
268 gchar* name = g_strdup_printf(
"src_%u", src->priv->pad_counter);
270 src->priv->pad_counter++;
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);
276 gst_pad_set_query_function(pad, gst_mse_src_query_with_parent);
277 gst_pad_set_active(pad,
TRUE);
279 gst_element_add_pad(element, pad);
280 GST_OBJECT_FLAG_SET(pad, GST_PAD_FLAG_NEED_PARENT);
282 gst_element_sync_state_with_parent(appsrc);
285 gst_object_unref(target);
288 void gst_mse_src_unregister_player(GstElement* element, GstElement* appsrc)
291 GstPad* pad = gst_element_get_static_pad(appsrc,
"src");
292 GstPad* peer = gst_pad_get_peer(pad);
294 GST_DEBUG_OBJECT(src,
"Unregistering player from pad %s, appsrc: %p", GST_PAD_NAME(pad), appsrc);
297 GstPad* ghost = GST_PAD_CAST(gst_proxy_pad_get_internal(GST_PROXY_PAD(peer)));
300 gst_ghost_pad_set_target(GST_GHOST_PAD_CAST(ghost), NULL);
301 gst_element_remove_pad(element, ghost);
302 gst_object_unref(ghost);
305 gst_object_unref(peer);
308 gst_app_src_end_of_stream(GST_APP_SRC(appsrc));
310 gst_element_set_state(appsrc, GST_STATE_NULL);
311 gst_bin_remove(GST_BIN(src), appsrc);
313 if (src->priv->pad_counter > 0)
314 src->priv->pad_counter--;
316 if (GST_BIN_NUMCHILDREN(src) == 0) {
317 GST_DEBUG_OBJECT(src,
"No player left, unconfiguring");
318 src->priv->configured = FALSE;
322 void gst_mse_src_configuration_done(GstElement* element)
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);
331 gboolean gst_mse_src_configured(GstElement* element)
334 return src->priv->configured;
337 static void gst_mse_src_get_property(GObject*
object, guint prop, GValue* value, GParamSpec* pspec)
342 GST_OBJECT_LOCK(src);
345 g_value_set_string(value, priv->uri);
348 G_OBJECT_WARN_INVALID_PROPERTY_ID(
object, prop, pspec);
351 GST_OBJECT_UNLOCK(src);