static KmsAlphaBlendingData * kms_alpha_blending_port_data_create (KmsAlphaBlending * mixer, gint id) { KmsAlphaBlendingData *data; gchar *padname; data = kms_create_alpha_blending_data (); data->id = id; data->mixer = mixer; data->videoconvert = gst_element_factory_make ("videoconvert", NULL); gst_bin_add_many (GST_BIN (mixer), data->videoconvert, NULL); gst_element_sync_state_with_parent (data->videoconvert); /*link basemixer -> video_agnostic */ kms_base_hub_link_video_sink (KMS_BASE_HUB (mixer), id, data->videoconvert, "sink", FALSE); padname = g_strdup_printf (AUDIO_SINK_PAD, id); kms_base_hub_link_audio_sink (KMS_BASE_HUB (mixer), id, mixer->priv->audiomixer, padname, FALSE); g_free (padname); data->videoconvert_sink_pad = gst_element_get_static_pad (data->videoconvert, "sink"); data->link_probe_id = gst_pad_add_probe (data->videoconvert_sink_pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_BLOCK, (GstPadProbeCallback) link_to_videomixer, KMS_ALPHA_BLENDING_REF (data), (GDestroyNotify) kms_ref_struct_unref); return data; }
static KmsSelectableMixerPortData * kms_selectable_mixer_port_data_create (KmsSelectableMixer * self, gint id) { KmsSelectableMixerPortData *data = g_slice_new0 (KmsSelectableMixerPortData); data->mixer = self; data->audiomixer = gst_element_factory_make ("audiomixerbin", NULL); data->audio_agnostic = gst_element_factory_make ("agnosticbin", NULL); data->video_agnostic = gst_element_factory_make ("agnosticbin", NULL); data->id = id; gst_bin_add_many (GST_BIN (self), g_object_ref (data->audio_agnostic), g_object_ref (data->video_agnostic), data->audiomixer, NULL); gst_element_sync_state_with_parent (data->audio_agnostic); gst_element_sync_state_with_parent (data->video_agnostic); gst_element_sync_state_with_parent (data->audiomixer); kms_base_hub_link_video_sink (KMS_BASE_HUB (self), id, data->video_agnostic, "sink", FALSE); kms_base_hub_link_audio_sink (KMS_BASE_HUB (self), id, data->audio_agnostic, "sink", FALSE); kms_base_hub_link_audio_src (KMS_BASE_HUB (self), id, data->audiomixer, "src", FALSE); return data; }
static KmsCompositeMixerData * kms_composite_mixer_port_data_create (KmsCompositeMixer * mixer, gint id) { KmsCompositeMixerData *data; gchar *padname; GstCaps *filtercaps; data = kms_create_composite_mixer_data (); data->mixer = mixer; data->id = id; data->input = FALSE; data->removing = FALSE; data->eos_managed = FALSE; data->videoconvert = gst_element_factory_make ("videoconvert", NULL); data->input_capsfilter = gst_element_factory_make ("capsfilter", NULL); filtercaps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "AYUV", "width", G_TYPE_INT, mixer->priv->output_width, "height", G_TYPE_INT, mixer->priv->output_height, "framerate", GST_TYPE_FRACTION, 15, 1, NULL); g_object_set (G_OBJECT (data->input_capsfilter), "caps", filtercaps, NULL); gst_caps_unref (filtercaps); gst_bin_add_many (GST_BIN (mixer), data->input_capsfilter, data->videoconvert, NULL); gst_element_sync_state_with_parent (data->videoconvert); gst_element_sync_state_with_parent (data->input_capsfilter); /*link basemixer -> video_agnostic */ kms_base_hub_link_video_sink (KMS_BASE_HUB (mixer), data->id, data->input_capsfilter, "sink", FALSE); gst_element_link (data->input_capsfilter, data->videoconvert); padname = g_strdup_printf (AUDIO_SINK_PAD, id); kms_base_hub_link_audio_sink (KMS_BASE_HUB (mixer), id, mixer->priv->audiomixer, padname, FALSE); g_free (padname); data->videoconvert_sink_pad = gst_element_get_static_pad (data->videoconvert, "sink"); data->link_probe_id = gst_pad_add_probe (data->videoconvert_sink_pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_BLOCK, (GstPadProbeCallback) link_to_videomixer, KMS_COMPOSITE_MIXER_REF (data), (GDestroyNotify) kms_ref_struct_unref); return data; }
static gint kms_alpha_blending_handle_port (KmsBaseHub * mixer, GstElement * mixer_end_point) { KmsAlphaBlending *self = KMS_ALPHA_BLENDING (mixer); KmsAlphaBlendingData *port_data; gint port_id; port_id = KMS_BASE_HUB_CLASS (G_OBJECT_CLASS (kms_alpha_blending_parent_class))->handle_port (mixer, mixer_end_point); if (port_id < 0) { return port_id; } KMS_ALPHA_BLENDING_LOCK (self); if (self->priv->videomixer == NULL) { GstElement *videorate_mixer; videorate_mixer = gst_element_factory_make ("videorate", NULL); self->priv->videomixer = gst_element_factory_make ("compositor", NULL); g_object_set (G_OBJECT (self->priv->videomixer), "background", 1, NULL); self->priv->mixer_video_agnostic = gst_element_factory_make ("agnosticbin", NULL); gst_bin_add_many (GST_BIN (mixer), self->priv->videomixer, videorate_mixer, self->priv->mixer_video_agnostic, NULL); gst_element_sync_state_with_parent (self->priv->videomixer); gst_element_sync_state_with_parent (videorate_mixer); gst_element_sync_state_with_parent (self->priv->mixer_video_agnostic); gst_element_link_many (self->priv->videomixer, videorate_mixer, self->priv->mixer_video_agnostic, NULL); } if (self->priv->audiomixer == NULL) { self->priv->audiomixer = gst_element_factory_make ("kmsaudiomixer", NULL); gst_bin_add (GST_BIN (mixer), self->priv->audiomixer); gst_element_sync_state_with_parent (self->priv->audiomixer); g_signal_connect (self->priv->audiomixer, "pad-added", G_CALLBACK (pad_added_cb), self); g_signal_connect (self->priv->audiomixer, "pad-removed", G_CALLBACK (pad_removed_cb), self); } kms_base_hub_link_video_src (KMS_BASE_HUB (self), port_id, self->priv->mixer_video_agnostic, "src_%u", TRUE); port_data = kms_alpha_blending_port_data_create (self, port_id); g_hash_table_insert (self->priv->ports, GINT_TO_POINTER (port_id), port_data); KMS_ALPHA_BLENDING_UNLOCK (self); return port_id; }
static gboolean kms_selectable_mixer_connect_video (KmsSelectableMixer * self, guint source, guint sink) { KmsSelectableMixerPortData *source_port, *sink_port; gboolean connected = FALSE; KMS_SELECTABLE_MIXER_LOCK (self); source_port = g_hash_table_lookup (self->priv->ports, &source); if (source_port == NULL) { GST_ERROR_OBJECT (self, "No source port %u found", source); goto end; } sink_port = g_hash_table_lookup (self->priv->ports, &sink); if (sink_port == NULL) { GST_ERROR_OBJECT (self, "No sink port %u found", source); goto end; } if (!(connected = kms_base_hub_link_video_src (KMS_BASE_HUB (self), sink_port->id, source_port->video_agnostic, "src_%u", TRUE))) { GST_ERROR_OBJECT (self, "Can not connect video port"); } end: KMS_SELECTABLE_MIXER_UNLOCK (self); return connected; }
static gboolean remove_elements_from_pipeline (KmsAlphaBlendingData * port_data) { KmsAlphaBlending *self = port_data->mixer; GstElement *videoconvert, *videoscale, *videorate, *capsfilter, *queue, *videobox; KMS_ALPHA_BLENDING_LOCK (self); videobox = port_data->videobox; gst_element_unlink (videobox, self->priv->videomixer); if (port_data->video_mixer_pad != NULL) { gst_element_release_request_pad (self->priv->videomixer, port_data->video_mixer_pad); g_object_unref (port_data->video_mixer_pad); port_data->video_mixer_pad = NULL; } videoconvert = g_object_ref (port_data->videoconvert); videorate = g_object_ref (port_data->videorate); queue = g_object_ref (port_data->queue); videoscale = g_object_ref (port_data->videoscale); capsfilter = g_object_ref (port_data->capsfilter); g_object_ref (videobox); g_object_unref (port_data->videoconvert_sink_pad); port_data->videoconvert_sink_pad = NULL; port_data->videoconvert = NULL; port_data->videorate = NULL; port_data->queue = NULL; port_data->videoscale = NULL; port_data->capsfilter = NULL; port_data->videobox = NULL; gst_bin_remove_many (GST_BIN (self), videoconvert, videoscale, capsfilter, videorate, queue, videobox, NULL); kms_base_hub_unlink_video_src (KMS_BASE_HUB (self), port_data->id); KMS_ALPHA_BLENDING_UNLOCK (self); gst_element_set_state (videoconvert, GST_STATE_NULL); gst_element_set_state (videoscale, GST_STATE_NULL); gst_element_set_state (videorate, GST_STATE_NULL); gst_element_set_state (capsfilter, GST_STATE_NULL); gst_element_set_state (queue, GST_STATE_NULL); gst_element_set_state (videobox, GST_STATE_NULL); g_object_unref (videoconvert); g_object_unref (videoscale); g_object_unref (videorate); g_object_unref (capsfilter); g_object_unref (queue); g_object_unref (videobox); return G_SOURCE_REMOVE; }
static gboolean remove_elements_from_pipeline (KmsCompositeMixerData * port_data) { KmsCompositeMixer *self = port_data->mixer; KMS_COMPOSITE_MIXER_LOCK (self); gst_element_unlink (port_data->capsfilter, self->priv->videomixer); if (port_data->video_mixer_pad != NULL) { gst_element_release_request_pad (self->priv->videomixer, port_data->video_mixer_pad); g_object_unref (port_data->video_mixer_pad); port_data->video_mixer_pad = NULL; } g_object_unref (port_data->videoconvert_sink_pad); gst_bin_remove_many (GST_BIN (self), g_object_ref (port_data->input_capsfilter), g_object_ref (port_data->videoconvert), g_object_ref (port_data->videoscale), g_object_ref (port_data->capsfilter), g_object_ref (port_data->videorate), g_object_ref (port_data->queue), NULL); kms_base_hub_unlink_video_src (KMS_BASE_HUB (self), port_data->id); KMS_COMPOSITE_MIXER_UNLOCK (self); gst_element_set_state (port_data->input_capsfilter, GST_STATE_NULL); gst_element_set_state (port_data->videoconvert, GST_STATE_NULL); gst_element_set_state (port_data->videoscale, GST_STATE_NULL); gst_element_set_state (port_data->videorate, GST_STATE_NULL); gst_element_set_state (port_data->capsfilter, GST_STATE_NULL); gst_element_set_state (port_data->queue, GST_STATE_NULL); g_object_unref (port_data->input_capsfilter); g_object_unref (port_data->videoconvert); g_object_unref (port_data->videoscale); g_object_unref (port_data->videorate); g_object_unref (port_data->capsfilter); g_object_unref (port_data->queue); port_data->videoconvert_sink_pad = NULL; port_data->input_capsfilter = NULL; port_data->videoconvert = NULL; port_data->videoscale = NULL; port_data->capsfilter = NULL; port_data->videorate = NULL; port_data->queue = NULL; return G_SOURCE_REMOVE; }
static gboolean kms_dispatcher_connect (KmsDispatcher * self, guint source, guint sink) { KmsDispatcherPortData *source_port, *sink_port; gboolean connected = FALSE; KMS_DISPATCHER_LOCK (self); source_port = g_hash_table_lookup (self->priv->ports, &source); if (source_port == NULL) { GST_ERROR_OBJECT (self, "No source port %u found", source); goto end; } sink_port = g_hash_table_lookup (self->priv->ports, &sink); if (sink_port == NULL) { GST_ERROR_OBJECT (self, "No sink port %u found", source); goto end; } if (!kms_base_hub_link_audio_src (KMS_BASE_HUB (self), sink_port->id, source_port->audio_agnostic, "src_%u", TRUE)) { GST_ERROR_OBJECT (self, "Can not connect audio port"); goto end; } if (!kms_base_hub_link_video_src (KMS_BASE_HUB (self), sink_port->id, source_port->video_agnostic, "src_%u", TRUE)) { GST_ERROR_OBJECT (self, "Can not connect video port"); kms_base_hub_unlink_audio_src (KMS_BASE_HUB (self), sink_port->id); goto end; } connected = TRUE; end: KMS_DISPATCHER_UNLOCK (self); return connected; }
static void kms_base_hub_dispose (GObject * object) { KmsBaseHub *self = KMS_BASE_HUB (object); GST_DEBUG_OBJECT (self, "dispose"); KMS_BASE_HUB_LOCK (self); g_hash_table_remove_all (self->priv->ports); KMS_BASE_HUB_UNLOCK (self); G_OBJECT_CLASS (kms_base_hub_parent_class)->dispose (object); }
static void kms_base_hub_finalize (GObject * object) { KmsBaseHub *self = KMS_BASE_HUB (object); GST_DEBUG_OBJECT (self, "finalize"); g_rec_mutex_clear (&self->priv->mutex); if (self->priv->ports != NULL) { g_hash_table_unref (self->priv->ports); self->priv->ports = NULL; } G_OBJECT_CLASS (kms_base_hub_parent_class)->finalize (object); }
static gboolean remove_elements_from_pipeline (KmsCompositeMixerData * port_data) { KmsCompositeMixer *self = port_data->mixer; KMS_COMPOSITE_MIXER_LOCK (self); gst_element_unlink (port_data->capsfilter, self->priv->videomixer); if (port_data->latency_probe_id > 0) { gst_pad_remove_probe (port_data->video_mixer_pad, port_data->latency_probe_id); port_data->latency_probe_id = 0; } if (port_data->video_mixer_pad != NULL) { gst_element_release_request_pad (self->priv->videomixer, port_data->video_mixer_pad); g_object_unref (port_data->video_mixer_pad); port_data->video_mixer_pad = NULL; } gst_bin_remove_many (GST_BIN (self), g_object_ref (port_data->capsfilter), g_object_ref (port_data->tee), g_object_ref (port_data->fakesink), NULL); kms_base_hub_unlink_video_src (KMS_BASE_HUB (self), port_data->id); KMS_COMPOSITE_MIXER_UNLOCK (self); gst_element_set_state (port_data->capsfilter, GST_STATE_NULL); gst_element_set_state (port_data->tee, GST_STATE_NULL); gst_element_set_state (port_data->fakesink, GST_STATE_NULL); g_object_unref (port_data->capsfilter); g_object_unref (port_data->tee); g_object_unref (port_data->fakesink); g_object_unref (port_data->tee_sink_pad); port_data->tee_sink_pad = NULL; port_data->capsfilter = NULL; port_data->tee = NULL; port_data->fakesink = NULL; return G_SOURCE_REMOVE; }
static void pad_added_cb (GstElement * element, GstPad * pad, gpointer data) { gint id; KmsAlphaBlending *self = KMS_ALPHA_BLENDING (data); if (gst_pad_get_direction (pad) != GST_PAD_SRC) return; id = get_stream_id_from_padname (GST_OBJECT_NAME (pad)); if (id < 0) { GST_ERROR_OBJECT (self, "Invalid HubPort for %" GST_PTR_FORMAT, pad); return; } kms_base_hub_link_audio_src (KMS_BASE_HUB (self), id, self->priv->audiomixer, GST_OBJECT_NAME (pad), TRUE); }
static void kms_alpha_blending_port_data_destroy (KmsAlphaBlendingData * port_data) { KmsAlphaBlending *self = port_data->mixer; GstPad *audiosink; gchar *padname; KMS_ALPHA_BLENDING_LOCK (self); port_data->removing = TRUE; kms_base_hub_unlink_video_sink (KMS_BASE_HUB (self), port_data->id); kms_base_hub_unlink_audio_sink (KMS_BASE_HUB (self), port_data->id); if (port_data->input) { GstEvent *event; gboolean result; GstPad *pad; if (port_data->videorate == NULL) { KMS_ALPHA_BLENDING_UNLOCK (self); return; } pad = gst_element_get_static_pad (port_data->videorate, "sink"); if (pad == NULL) { KMS_ALPHA_BLENDING_UNLOCK (self); return; } if (!GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_EOS)) { event = gst_event_new_eos (); result = gst_pad_send_event (pad, event); if (port_data->input && self->priv->n_elems > 0) { port_data->input = FALSE; self->priv->n_elems--; } if (!result) { GST_WARNING ("EOS event did not send"); } gst_element_unlink (port_data->videoconvert, port_data->videorate); g_object_unref (pad); KMS_ALPHA_BLENDING_UNLOCK (self); } else { gboolean remove = FALSE; /* EOS callback was triggered before we could remove the port data */ /* so we have to remove elements to avoid memory leaks. */ remove = port_data->eos_managed; gst_element_unlink (port_data->videoconvert, port_data->videorate); g_object_unref (pad); KMS_ALPHA_BLENDING_UNLOCK (self); if (remove) { /* Remove pipeline without helding the mutex */ kms_loop_idle_add_full (self->priv->loop, G_PRIORITY_DEFAULT, (GSourceFunc) remove_elements_from_pipeline, KMS_ALPHA_BLENDING_REF (port_data), (GDestroyNotify) kms_ref_struct_unref); } } } else { GstElement *videoconvert; videoconvert = g_object_ref (port_data->videoconvert); port_data->videoconvert = NULL; if (port_data->probe_id > 0) { gst_pad_remove_probe (port_data->video_mixer_pad, port_data->probe_id); } if (port_data->link_probe_id > 0) { gst_pad_remove_probe (port_data->videoconvert_sink_pad, port_data->link_probe_id); } KMS_ALPHA_BLENDING_UNLOCK (self); gst_bin_remove (GST_BIN (self), videoconvert); gst_element_set_state (videoconvert, GST_STATE_NULL); g_object_unref (videoconvert); } padname = g_strdup_printf (AUDIO_SINK_PAD, port_data->id); audiosink = gst_element_get_static_pad (self->priv->audiomixer, padname); gst_element_release_request_pad (self->priv->audiomixer, audiosink); gst_object_unref (audiosink); g_free (padname); KMS_ALPHA_BLENDING_UNREF (port_data); }
static gint kms_composite_mixer_handle_port (KmsBaseHub * mixer, GstElement * mixer_end_point) { KmsCompositeMixer *self = KMS_COMPOSITE_MIXER (mixer); KmsCompositeMixerData *port_data; gint port_id; GST_DEBUG ("handle new port"); port_id = KMS_BASE_HUB_CLASS (G_OBJECT_CLASS (kms_composite_mixer_parent_class))->handle_port (mixer, mixer_end_point); if (port_id < 0) { return port_id; } KMS_COMPOSITE_MIXER_LOCK (self); if (self->priv->videomixer == NULL) { self->priv->videomixer = gst_element_factory_make ("compositor", NULL); g_object_set (G_OBJECT (self->priv->videomixer), "background", 1 /*black */ , "start-time-selection", 1 /*first */ , "latency", LATENCY * GST_MSECOND, NULL); self->priv->mixer_video_agnostic = gst_element_factory_make ("agnosticbin", NULL); gst_bin_add_many (GST_BIN (mixer), self->priv->videomixer, self->priv->mixer_video_agnostic, NULL); if (self->priv->videotestsrc == NULL) { GstElement *capsfilter; GstCaps *filtercaps; GstPad *pad; GstPadTemplate *sink_pad_template; sink_pad_template = gst_element_class_get_pad_template (GST_ELEMENT_GET_CLASS (self->priv->videomixer), "sink_%u"); if (G_UNLIKELY (sink_pad_template == NULL)) { GST_ERROR_OBJECT (self, "Error taking a new pad from videomixer"); } self->priv->videotestsrc = gst_element_factory_make ("videotestsrc", NULL); capsfilter = gst_element_factory_make ("capsfilter", NULL); g_object_set (G_OBJECT (capsfilter), "caps-change-mode", 1, NULL); g_object_set (self->priv->videotestsrc, "is-live", TRUE, "pattern", /*black */ 2, NULL); filtercaps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, self->priv->output_width, "height", G_TYPE_INT, self->priv->output_height, "framerate", GST_TYPE_FRACTION, 15, 1, NULL); g_object_set (G_OBJECT (capsfilter), "caps", filtercaps, NULL); gst_caps_unref (filtercaps); gst_bin_add_many (GST_BIN (self), self->priv->videotestsrc, capsfilter, NULL); gst_element_link (self->priv->videotestsrc, capsfilter); /*link capsfilter -> videomixer */ pad = gst_element_request_pad (self->priv->videomixer, sink_pad_template, NULL, NULL); gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_QUERY_UPSTREAM, (GstPadProbeCallback) cb_latency, NULL, NULL); gst_element_link_pads (capsfilter, NULL, self->priv->videomixer, GST_OBJECT_NAME (pad)); g_object_set (pad, "xpos", 0, "ypos", 0, "alpha", 0.0, NULL); g_object_unref (pad); gst_element_sync_state_with_parent (capsfilter); gst_element_sync_state_with_parent (self->priv->videotestsrc); } gst_element_sync_state_with_parent (self->priv->videomixer); gst_element_sync_state_with_parent (self->priv->mixer_video_agnostic); gst_element_link (self->priv->videomixer, self->priv->mixer_video_agnostic); } if (self->priv->audiomixer == NULL) { self->priv->audiomixer = gst_element_factory_make ("kmsaudiomixer", NULL); gst_bin_add (GST_BIN (mixer), self->priv->audiomixer); gst_element_sync_state_with_parent (self->priv->audiomixer); g_signal_connect (self->priv->audiomixer, "pad-added", G_CALLBACK (pad_added_cb), self); g_signal_connect (self->priv->audiomixer, "pad-removed", G_CALLBACK (pad_removed_cb), self); } kms_base_hub_link_video_src (KMS_BASE_HUB (self), port_id, self->priv->mixer_video_agnostic, "src_%u", TRUE); port_data = kms_composite_mixer_port_data_create (self, port_id); g_hash_table_insert (self->priv->ports, create_gint (port_id), port_data); KMS_COMPOSITE_MIXER_UNLOCK (self); return port_id; }
static KmsCompositeMixerData * kms_composite_mixer_port_data_create (KmsCompositeMixer * mixer, gint id) { KmsCompositeMixerData *data; gchar *padname; GstPad *tee_src; GstCaps *filtercaps; data = kms_create_composite_mixer_data (); data->mixer = mixer; data->id = id; data->input = FALSE; data->removing = FALSE; data->eos_managed = FALSE; data->tee = gst_element_factory_make ("tee", NULL); data->fakesink = gst_element_factory_make ("fakesink", NULL); data->capsfilter = gst_element_factory_make ("capsfilter", NULL); g_object_set (G_OBJECT (data->capsfilter), "caps-change-mode", 1 /*delayed */ , NULL); g_object_set (G_OBJECT (data->fakesink), "async", FALSE, "sync", FALSE, NULL); gst_bin_add_many (GST_BIN (mixer), data->capsfilter, data->tee, data->fakesink, NULL); gst_element_sync_state_with_parent (data->capsfilter); gst_element_sync_state_with_parent (data->tee); gst_element_sync_state_with_parent (data->fakesink); filtercaps = gst_caps_new_simple ("video/x-raw", "width", G_TYPE_INT, mixer->priv->output_width, "height", G_TYPE_INT, mixer->priv->output_height, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL); g_object_set (data->capsfilter, "caps", filtercaps, NULL); gst_caps_unref (filtercaps); /*link basemixer -> video_agnostic */ kms_base_hub_link_video_sink (KMS_BASE_HUB (mixer), data->id, data->capsfilter, "sink", FALSE); data->tee_sink_pad = gst_element_get_static_pad (data->tee, "sink"); gst_element_link_pads (data->capsfilter, NULL, data->tee, GST_OBJECT_NAME (data->tee_sink_pad)); tee_src = gst_element_get_request_pad (data->tee, "src_%u"); gst_element_link_pads (data->tee, GST_OBJECT_NAME (tee_src), data->fakesink, "sink"); g_object_unref (tee_src); padname = g_strdup_printf (AUDIO_SINK_PAD, id); kms_base_hub_link_audio_sink (KMS_BASE_HUB (mixer), id, mixer->priv->audiomixer, padname, FALSE); g_free (padname); data->link_probe_id = gst_pad_add_probe (data->tee_sink_pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_BLOCK, (GstPadProbeCallback) link_to_videomixer, KMS_COMPOSITE_MIXER_REF (data), (GDestroyNotify) kms_ref_struct_unref); return data; }
static void kms_composite_mixer_port_data_destroy (gpointer data) { KmsCompositeMixerData *port_data = (KmsCompositeMixerData *) data; KmsCompositeMixer *self = port_data->mixer; GstPad *audiosink; gchar *padname; KMS_COMPOSITE_MIXER_LOCK (self); port_data->removing = TRUE; kms_base_hub_unlink_video_sink (KMS_BASE_HUB (self), port_data->id); kms_base_hub_unlink_audio_sink (KMS_BASE_HUB (self), port_data->id); if (port_data->input) { GstEvent *event; gboolean result; GstPad *pad; if (port_data->capsfilter == NULL) { KMS_COMPOSITE_MIXER_UNLOCK (self); return; } pad = gst_element_get_static_pad (port_data->capsfilter, "sink"); if (pad == NULL) { KMS_COMPOSITE_MIXER_UNLOCK (self); return; } if (!GST_OBJECT_FLAG_IS_SET (pad, GST_PAD_FLAG_EOS)) { if (GST_PAD_IS_FLUSHING (pad)) { gst_pad_send_event (pad, gst_event_new_flush_stop (FALSE)); } event = gst_event_new_eos (); result = gst_pad_send_event (pad, event); if (port_data->input && self->priv->n_elems > 0) { port_data->input = FALSE; self->priv->n_elems--; kms_composite_mixer_recalculate_sizes (self); } KMS_COMPOSITE_MIXER_UNLOCK (self); if (!result) { GST_WARNING ("EOS event did not send"); } } else { gboolean remove = FALSE; /* EOS callback was triggered before we could remove the port data */ /* so we have to remove elements to avoid memory leaks. */ remove = port_data->eos_managed; KMS_COMPOSITE_MIXER_UNLOCK (self); if (remove) { /* Remove pipeline without helding the mutex */ kms_loop_idle_add_full (self->priv->loop, G_PRIORITY_DEFAULT, (GSourceFunc) remove_elements_from_pipeline, KMS_COMPOSITE_MIXER_REF (port_data), (GDestroyNotify) kms_ref_struct_unref); } } gst_element_unlink (port_data->capsfilter, port_data->tee); g_object_unref (pad); } else { if (port_data->probe_id > 0) { gst_pad_remove_probe (port_data->video_mixer_pad, port_data->probe_id); } if (port_data->latency_probe_id > 0) { gst_pad_remove_probe (port_data->video_mixer_pad, port_data->latency_probe_id); } if (port_data->link_probe_id > 0) { gst_pad_remove_probe (port_data->tee_sink_pad, port_data->link_probe_id); } KMS_COMPOSITE_MIXER_UNLOCK (self); gst_element_unlink (port_data->capsfilter, port_data->tee); gst_element_unlink (port_data->tee, port_data->fakesink); gst_bin_remove (GST_BIN (self), g_object_ref (port_data->capsfilter)); gst_element_set_state (port_data->capsfilter, GST_STATE_NULL); g_object_unref (port_data->capsfilter); port_data->capsfilter = NULL; gst_bin_remove (GST_BIN (self), g_object_ref (port_data->tee)); gst_element_set_state (port_data->tee, GST_STATE_NULL); g_object_unref (port_data->tee); port_data->tee = NULL; gst_bin_remove (GST_BIN (self), g_object_ref (port_data->fakesink)); gst_element_set_state (port_data->fakesink, GST_STATE_NULL); g_object_unref (port_data->fakesink); port_data->fakesink = NULL; } padname = g_strdup_printf (AUDIO_SINK_PAD, port_data->id); audiosink = gst_element_get_static_pad (self->priv->audiomixer, padname); gst_element_release_request_pad (self->priv->audiomixer, audiosink); gst_object_unref (audiosink); g_free (padname); }