/** * gst_ghost_pad_set_target: * @gpad: the #GstGhostPad * @newtarget: (transfer none) (allow-none): the new pad target * * Set the new target of the ghostpad @gpad. Any existing target * is unlinked and links to the new target are established. if @newtarget is * %NULL the target will be cleared. * * Returns: (transfer full): %TRUE if the new target could be set. This function * can return %FALSE when the internal pads could not be linked. */ gboolean gst_ghost_pad_set_target (GstGhostPad * gpad, GstPad * newtarget) { GstPad *internal; GstPad *oldtarget; GstPadLinkReturn lret; g_return_val_if_fail (GST_IS_GHOST_PAD (gpad), FALSE); g_return_val_if_fail (GST_PAD_CAST (gpad) != newtarget, FALSE); g_return_val_if_fail (newtarget != GST_PROXY_PAD_INTERNAL (gpad), FALSE); GST_OBJECT_LOCK (gpad); internal = GST_PROXY_PAD_INTERNAL (gpad); if (newtarget) GST_DEBUG_OBJECT (gpad, "set target %s:%s", GST_DEBUG_PAD_NAME (newtarget)); else GST_DEBUG_OBJECT (gpad, "clearing target"); /* clear old target */ if ((oldtarget = gst_pad_get_peer (internal))) { GST_OBJECT_UNLOCK (gpad); /* unlink internal pad */ if (GST_PAD_IS_SRC (internal)) gst_pad_unlink (internal, oldtarget); else gst_pad_unlink (oldtarget, internal); gst_object_unref (oldtarget); } else { GST_OBJECT_UNLOCK (gpad); } if (newtarget) { /* and link to internal pad without any checks */ GST_DEBUG_OBJECT (gpad, "connecting internal pad to target %" GST_PTR_FORMAT, newtarget); if (GST_PAD_IS_SRC (internal)) lret = gst_pad_link_full (internal, newtarget, GST_PAD_LINK_CHECK_NOTHING); else lret = gst_pad_link_full (newtarget, internal, GST_PAD_LINK_CHECK_NOTHING); if (lret != GST_PAD_LINK_OK) goto link_failed; } return TRUE; /* ERRORS */ link_failed: { GST_WARNING_OBJECT (gpad, "could not link internal and target, reason:%s", gst_pad_link_get_name (lret)); return FALSE; } }
void AudioSourceProviderGStreamer::handleNewDeinterleavePad(GstPad* pad) { m_deinterleaveSourcePads++; if (m_deinterleaveSourcePads > 2) { g_warning("The AudioSourceProvider supports only mono and stereo audio. Silencing out this new channel."); GstElement* queue = gst_element_factory_make("queue", 0); GstElement* sink = gst_element_factory_make("fakesink", 0); g_object_set(sink, "async", FALSE, nullptr); gst_bin_add_many(GST_BIN(m_audioSinkBin.get()), queue, sink, nullptr); GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(queue, "sink")); gst_pad_link_full(pad, sinkPad.get(), GST_PAD_LINK_CHECK_NOTHING); GQuark quark = g_quark_from_static_string("peer"); g_object_set_qdata(G_OBJECT(pad), quark, sinkPad.get()); gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_sync_state_with_parent(queue); gst_element_sync_state_with_parent(sink); return; } // A new pad for a planar channel was added in deinterleave. Plug // in an appsink so we can pull the data from each // channel. Pipeline looks like: // ... deinterleave ! queue ! appsink. GstElement* queue = gst_element_factory_make("queue", 0); GstElement* sink = gst_element_factory_make("appsink", 0); GstAppSinkCallbacks callbacks; callbacks.eos = 0; callbacks.new_preroll = 0; callbacks.new_sample = onAppsinkNewBufferCallback; gst_app_sink_set_callbacks(GST_APP_SINK(sink), &callbacks, this, 0); g_object_set(sink, "async", FALSE, nullptr); GRefPtr<GstCaps> caps = adoptGRef(gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, static_cast<int>(gSampleBitRate), "channels", G_TYPE_INT, 1, "format", G_TYPE_STRING, GST_AUDIO_NE(F32), "layout", G_TYPE_STRING, "interleaved", nullptr)); gst_app_sink_set_caps(GST_APP_SINK(sink), caps.get()); gst_bin_add_many(GST_BIN(m_audioSinkBin.get()), queue, sink, nullptr); GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(queue, "sink")); gst_pad_link_full(pad, sinkPad.get(), GST_PAD_LINK_CHECK_NOTHING); GQuark quark = g_quark_from_static_string("peer"); g_object_set_qdata(G_OBJECT(pad), quark, sinkPad.get()); gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING); sinkPad = adoptGRef(gst_element_get_static_pad(sink, "sink")); gst_pad_add_probe(sinkPad.get(), GST_PAD_PROBE_TYPE_EVENT_FLUSH, onAppsinkFlushCallback, this, nullptr); gst_element_sync_state_with_parent(queue); gst_element_sync_state_with_parent(sink); }
void AudioFileReader::plugDeinterleave(GstPad* pad) { // A decodebin pad was added, plug in a deinterleave element to // separate each planar channel. Sub pipeline looks like // ... decodebin2 ! audioconvert ! audioresample ! capsfilter ! deinterleave. GstElement* audioConvert = gst_element_factory_make("audioconvert", 0); GstElement* audioResample = gst_element_factory_make("audioresample", 0); GstElement* capsFilter = gst_element_factory_make("capsfilter", 0); m_deInterleave = gst_element_factory_make("deinterleave", "deinterleave"); g_object_set(m_deInterleave.get(), "keep-positions", TRUE, NULL); g_signal_connect(m_deInterleave.get(), "pad-added", G_CALLBACK(onGStreamerDeinterleavePadAddedCallback), this); g_signal_connect(m_deInterleave.get(), "no-more-pads", G_CALLBACK(onGStreamerDeinterleaveReadyCallback), this); GstCaps* caps = getGstAudioCaps(2, m_sampleRate); g_object_set(capsFilter, "caps", caps, NULL); gst_caps_unref(caps); gst_bin_add_many(GST_BIN(m_pipeline), audioConvert, audioResample, capsFilter, m_deInterleave.get(), NULL); GstPad* sinkPad = gst_element_get_static_pad(audioConvert, "sink"); gst_pad_link_full(pad, sinkPad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref(GST_OBJECT(sinkPad)); gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_link_pads_full(audioResample, "src", capsFilter, "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_link_pads_full(capsFilter, "src", m_deInterleave.get(), "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_sync_state_with_parent(audioConvert); gst_element_sync_state_with_parent(audioResample); gst_element_sync_state_with_parent(capsFilter); gst_element_sync_state_with_parent(m_deInterleave.get()); }
void AudioFileReader::handleNewDeinterleavePad(GstPad* pad) { // A new pad for a planar channel was added in deinterleave. Plug // in an appsink so we can pull the data from each // channel. Pipeline looks like: // ... deinterleave ! queue ! appsink. GstElement* queue = gst_element_factory_make("queue", 0); GstElement* sink = gst_element_factory_make("appsink", 0); GstAppSinkCallbacks callbacks; callbacks.eos = 0; callbacks.new_preroll = 0; callbacks.new_sample = onAppsinkPullRequiredCallback; gst_app_sink_set_callbacks(GST_APP_SINK(sink), &callbacks, this, 0); g_object_set(sink, "sync", FALSE, NULL); gst_bin_add_many(GST_BIN(m_pipeline), queue, sink, NULL); GstPad* sinkPad = gst_element_get_static_pad(queue, "sink"); gst_pad_link_full(pad, sinkPad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref(GST_OBJECT(sinkPad)); gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_sync_state_with_parent(queue); gst_element_sync_state_with_parent(sink); }
void AudioDestinationGStreamer::finishBuildingPipelineAfterWavParserPadReady(GstPad* pad) { ASSERT(m_wavParserAvailable); GRefPtr<GstElement> audioSink = gst_element_factory_make("autoaudiosink", 0); m_audioSinkAvailable = audioSink; if (!audioSink) { LOG_ERROR("Failed to create GStreamer autoaudiosink element"); return; } // Autoaudiosink does the real sink detection in the GST_STATE_NULL->READY transition // so it's best to roll it to READY as soon as possible to ensure the underlying platform // audiosink was loaded correctly. GstStateChangeReturn stateChangeReturn = gst_element_set_state(audioSink.get(), GST_STATE_READY); if (stateChangeReturn == GST_STATE_CHANGE_FAILURE) { LOG_ERROR("Failed to change autoaudiosink element state"); gst_element_set_state(audioSink.get(), GST_STATE_NULL); m_audioSinkAvailable = false; return; } GstElement* audioConvert = gst_element_factory_make("audioconvert", 0); gst_bin_add_many(GST_BIN(m_pipeline), audioConvert, audioSink.get(), NULL); // Link wavparse's src pad to audioconvert sink pad. GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(audioConvert, "sink")); gst_pad_link_full(pad, sinkPad.get(), GST_PAD_LINK_CHECK_NOTHING); // Link audioconvert to audiosink and roll states. gst_element_link_pads_full(audioConvert, "src", audioSink.get(), "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_sync_state_with_parent(audioConvert); gst_element_sync_state_with_parent(audioSink.leakRef()); }
static GObject * link_element_to_mixer_with_smpte (GstBin * bin, GstElement * element, GstElement * mixer, gint type, GstElement ** smpteref) { GstPad *srcpad, *sinkpad; GstElement *smptealpha = gst_element_factory_make ("smptealpha", NULL); g_object_set (G_OBJECT (smptealpha), "type", (gint) type, "invert", (gboolean) TRUE, NULL); gst_bin_add (bin, smptealpha); fast_element_link (element, smptealpha); /* crack */ if (smpteref) { *smpteref = smptealpha; } srcpad = gst_element_get_static_pad (smptealpha, "src"); sinkpad = gst_element_get_request_pad (mixer, "sink_%u"); gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref (srcpad); return G_OBJECT (sinkpad); }
static void kms_base_rtp_session_link_pads (GstPad * src, GstPad * sink) { GstPadLinkReturn ret; ret = gst_pad_link_full (src, sink, GST_PAD_LINK_CHECK_CAPS); if (ret != GST_PAD_LINK_OK) { GST_ERROR ("Error linking pads (src: %" GST_PTR_FORMAT ", sink: %" GST_PTR_FORMAT "), ret: '%s'", src, sink, gst_pad_link_get_name (ret)); } }
static GObject * link_element_to_mixer (GstElement * element, GstElement * mixer) { GstPad *sinkpad = gst_element_get_request_pad (mixer, "sink_%u"); GstPad *srcpad = gst_element_get_static_pad (element, "src"); gst_pad_link_full (srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref (srcpad); return G_OBJECT (sinkpad); }
AudioDestinationGStreamer::AudioDestinationGStreamer(AudioIOCallback& callback, float sampleRate) : m_callback(callback) , m_renderBus(AudioBus::create(2, framesToPull, false)) , m_sampleRate(sampleRate) , m_isPlaying(false) { m_pipeline = gst_pipeline_new("play"); GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline))); ASSERT(bus); gst_bus_add_signal_watch(bus.get()); g_signal_connect(bus.get(), "message", G_CALLBACK(messageCallback), this); GstElement* webkitAudioSrc = reinterpret_cast<GstElement*>(g_object_new(WEBKIT_TYPE_WEB_AUDIO_SRC, "rate", sampleRate, "bus", m_renderBus.get(), "provider", &m_callback, "frames", framesToPull, NULL)); GRefPtr<GstPad> srcPad = adoptGRef(gst_element_get_static_pad(webkitAudioSrc, "src")); GRefPtr<GstElement> audioSink = gst_element_factory_make("autoaudiosink", 0); m_audioSinkAvailable = audioSink; if (!audioSink) { LOG_ERROR("Failed to create GStreamer autoaudiosink element"); return; } // Autoaudiosink does the real sink detection in the GST_STATE_NULL->READY transition // so it's best to roll it to READY as soon as possible to ensure the underlying platform // audiosink was loaded correctly. GstStateChangeReturn stateChangeReturn = gst_element_set_state(audioSink.get(), GST_STATE_READY); if (stateChangeReturn == GST_STATE_CHANGE_FAILURE) { LOG_ERROR("Failed to change autoaudiosink element state"); gst_element_set_state(audioSink.get(), GST_STATE_NULL); m_audioSinkAvailable = false; return; } GstElement* audioConvert = gst_element_factory_make("audioconvert", 0); GstElement* audioResample = gst_element_factory_make("audioresample", 0); gst_bin_add_many(GST_BIN(m_pipeline), webkitAudioSrc, audioConvert, audioResample, audioSink.get(), NULL); // Link wavparse's src pad to audioconvert sink pad. GRefPtr<GstPad> sinkPad = adoptGRef(gst_element_get_static_pad(audioConvert, "sink")); gst_pad_link_full(srcPad.get(), sinkPad.get(), GST_PAD_LINK_CHECK_NOTHING); // Link audioconvert to audiosink and roll states. gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_link_pads_full(audioResample, "src", audioSink.get(), "sink", GST_PAD_LINK_CHECK_NOTHING); }
static void add_smpte_to_bin (GstPad * sink, GstElement * smptealpha, GESTrackVideoTransitionPrivate * priv) { GstPad *peer, *sinkpad; g_object_set (smptealpha, "type", (gint) priv->pending_type, "invert", (gboolean) TRUE, NULL); gst_bin_add (GST_BIN (priv->topbin), smptealpha); gst_element_sync_state_with_parent (smptealpha); sinkpad = gst_element_get_static_pad (smptealpha, "sink"); peer = gst_pad_get_peer (sink); gst_pad_unlink (peer, sink); gst_pad_link_full (peer, sinkpad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref (sinkpad); gst_object_unref (peer); }
void AudioFileReader::plugDeinterleave(GstPad* pad) { // Ignore any additional source pads just in case. if (m_deInterleave) return; // A decodebin pad was added, plug in a deinterleave element to // separate each planar channel. Sub pipeline looks like // ... decodebin2 ! audioconvert ! audioresample ! capsfilter ! deinterleave. GstElement* audioConvert = gst_element_factory_make("audioconvert", 0); GstElement* audioResample = gst_element_factory_make("audioresample", 0); GstElement* capsFilter = gst_element_factory_make("capsfilter", 0); m_deInterleave = gst_element_factory_make("deinterleave", "deinterleave"); g_object_set(m_deInterleave.get(), "keep-positions", TRUE, NULL); g_signal_connect(m_deInterleave.get(), "pad-added", G_CALLBACK(onGStreamerDeinterleavePadAddedCallback), this); g_signal_connect(m_deInterleave.get(), "no-more-pads", G_CALLBACK(onGStreamerDeinterleaveReadyCallback), this); GstCaps* caps = gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, static_cast<int>(m_sampleRate), "channels", G_TYPE_INT, m_channels, "format", G_TYPE_STRING, GST_AUDIO_NE(F32), "layout", G_TYPE_STRING, "interleaved", nullptr); g_object_set(capsFilter, "caps", caps, NULL); gst_caps_unref(caps); gst_bin_add_many(GST_BIN(m_pipeline), audioConvert, audioResample, capsFilter, m_deInterleave.get(), NULL); GstPad* sinkPad = gst_element_get_static_pad(audioConvert, "sink"); gst_pad_link_full(pad, sinkPad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref(GST_OBJECT(sinkPad)); gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_link_pads_full(audioResample, "src", capsFilter, "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_link_pads_full(capsFilter, "src", m_deInterleave.get(), "sink", GST_PAD_LINK_CHECK_NOTHING); gst_element_sync_state_with_parent(audioConvert); gst_element_sync_state_with_parent(audioResample); gst_element_sync_state_with_parent(capsFilter); gst_element_sync_state_with_parent(m_deInterleave.get()); }
void AudioLiveInputPipeline::handleNewDeinterleavePad(GstPad* pad) { // A new pad for a planar channel was added in deinterleave. // Plug in an appsink so we can pull the data from each channel. // Pipeline looks like: // ... deinterleave ! appsink. GstElement* queue = gst_element_factory_make("queue", nullptr); GstElement* sink = gst_element_factory_make("appsink", nullptr); gst_bin_add_many(GST_BIN(m_pipeline), queue, sink, nullptr); GstPad* sinkPad = gst_element_get_static_pad(queue, "sink"); gst_pad_link_full(pad, sinkPad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref(GST_OBJECT(sinkPad)); gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING); m_sinkList = g_slist_prepend(m_sinkList, sink); gst_element_sync_state_with_parent(queue); gst_element_sync_state_with_parent(sink); }
static gboolean gst_uri_downloader_set_uri (GstUriDownloader * downloader, const gchar * uri) { GstPad *pad; if (!gst_uri_is_valid (uri)) return FALSE; if (downloader->urisrc) { GstURIHandler *uri_handler = GST_URI_HANDLER (downloader->urisrc); if (gst_uri_handler_set_uri (uri_handler, uri, NULL)) { GST_DEBUG_OBJECT (downloader, "reusing element %s to download URI %s", GST_ELEMENT_NAME (downloader->urisrc), uri); return TRUE; } gst_element_set_state (downloader->urisrc, GST_STATE_NULL); gst_object_unref (downloader->urisrc); } GST_DEBUG_OBJECT (downloader, "creating source element for URI %s", uri); downloader->urisrc = gst_element_make_from_uri (GST_URI_SRC, uri, NULL, NULL); if (!downloader->urisrc) { GST_ERROR_OBJECT (downloader, "no element can handle URI %s", uri); return FALSE; } /* add a sync handler for the bus messages to detect errors */ gst_element_set_bus (downloader->urisrc, downloader->bus); gst_bus_set_sync_handler (downloader->bus, gst_uri_downloader_bus_handler, downloader, NULL); pad = gst_element_get_static_pad (downloader->urisrc, "src"); gst_pad_link_full (pad, downloader->pad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref (pad); return TRUE; }
static void link_element_to_tee (GstElement * tee, GstElement * element) { GstPad *tee_src = gst_element_get_request_pad (tee, "src_%u"); GstPad *element_sink = gst_element_get_static_pad (element, "sink"); GstPadLinkReturn ret; GstPadChainFunction old_func; /* * HACK Add a custom chain function that does not return error, this way * we avoid race conditions produced by reconnect events not using the stream * lock */ old_func = GST_PAD_CHAINFUNC (element_sink); if (old_func != NULL) { if (old_func != no_fail_chain) { g_object_set_data (G_OBJECT (element_sink), OLD_CHAIN_KEY, old_func); } gst_pad_set_chain_function (element_sink, no_fail_chain); } remove_element_on_unlinked (element, "src", "sink"); g_signal_connect (tee_src, "unlinked", G_CALLBACK (remove_tee_pad_on_unlink), NULL); gst_pad_add_probe (tee_src, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, tee_src_probe, NULL, NULL); ret = gst_pad_link_full (tee_src, element_sink, GST_PAD_LINK_CHECK_NOTHING); if (G_UNLIKELY (GST_PAD_LINK_FAILED (ret))) { GST_ERROR ("Linking %" GST_PTR_FORMAT " with %" GST_PTR_FORMAT " result %d", tee_src, element_sink, ret); } g_object_unref (element_sink); g_object_unref (tee_src); }
static void link_element_to_tee (GstElement * tee, GstElement * element) { GstPad *tee_src = gst_element_get_request_pad (tee, "src_%u"); GstPad *element_sink = gst_element_get_static_pad (element, "sink"); GstPadLinkReturn ret; remove_element_on_unlinked (element, "src", "sink"); g_signal_connect (tee_src, "unlinked", G_CALLBACK (remove_tee_pad_on_unlink), NULL); gst_pad_add_probe (tee_src, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, tee_src_probe, NULL, NULL); ret = gst_pad_link_full (tee_src, element_sink, GST_PAD_LINK_CHECK_NOTHING); if (G_UNLIKELY (GST_PAD_LINK_FAILED (ret))) { GST_ERROR ("Linking %" GST_PTR_FORMAT " with %" GST_PTR_FORMAT " result %d", tee_src, element_sink, ret); } g_object_unref (element_sink); g_object_unref (tee_src); }
static void gst_insert_bin_do_change (GstInsertBin * self, GstPad * pad) { struct ChangeData *data; GST_OBJECT_LOCK (self); if (!is_right_direction_for_block (pad)) { GST_WARNING_OBJECT (self, "Block pad does not have the expected direction"); goto next; } while ((data = g_queue_pop_head (&self->priv->change_queue)) != NULL) { GstPad *peer = NULL; GstPad *other_peer = NULL; GST_OBJECT_UNLOCK (self); if (data->action == GST_INSERT_BIN_ACTION_ADD && !validate_element (self, data->element)) goto error; peer = gst_pad_get_peer (pad); if (peer == NULL) { GST_WARNING_OBJECT (self, "Blocked pad has no peer"); goto error; } if (data->action == GST_INSERT_BIN_ACTION_ADD) { GstPad *srcpad = NULL, *sinkpad = NULL; GstPad *peersrcpad, *peersinkpad; /* First let's make sure we have the right pad */ if (data->sibling) { GstElement *parent = NULL; GstPad *siblingpad; if ((gst_pad_get_direction (pad) == GST_PAD_SRC && data->direction == DIRECTION_BEFORE) || (gst_pad_get_direction (pad) == GST_PAD_SINK && data->direction == DIRECTION_AFTER)) siblingpad = peer; else siblingpad = pad; parent = gst_pad_get_parent_element (siblingpad); if (parent != NULL) gst_object_unref (parent); if (parent != data->sibling) goto retry; } else { GstObject *parent; GstPad *ghost; GstPad *proxypad; if (data->direction == DIRECTION_BEFORE) { ghost = self->priv->srcpad; if (gst_pad_get_direction (pad) == GST_PAD_SINK) proxypad = pad; else proxypad = peer; } else { ghost = self->priv->sinkpad; if (gst_pad_get_direction (pad) == GST_PAD_SINK) proxypad = peer; else proxypad = pad; } if (!GST_IS_PROXY_PAD (proxypad)) goto retry; parent = gst_pad_get_parent (proxypad); if (!parent) goto retry; gst_object_unref (parent); if (GST_PAD_CAST (parent) != ghost) goto retry; } if (gst_pad_get_direction (pad) == GST_PAD_SRC) { peersrcpad = pad; peersinkpad = peer; } else { peersrcpad = peer; peersinkpad = pad; } if (GST_IS_PROXY_PAD (peersrcpad)) { GstObject *parent = gst_pad_get_parent (peersrcpad); if (GST_PAD_CAST (parent) == self->priv->sinkpad) peersrcpad = NULL; if (parent) gst_object_unref (parent); } if (GST_IS_PROXY_PAD (peersinkpad)) { GstObject *parent = gst_pad_get_parent (peersinkpad); if (GST_PAD_CAST (parent) == self->priv->srcpad) peersinkpad = NULL; if (parent) gst_object_unref (parent); } if (peersinkpad && peersrcpad) { gst_pad_unlink (peersrcpad, peersinkpad); } else { if (!peersinkpad) gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad), NULL); if (!peersrcpad) gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad), NULL); } srcpad = get_single_pad (data->element, GST_PAD_SRC); sinkpad = get_single_pad (data->element, GST_PAD_SINK); if (srcpad == NULL || sinkpad == NULL) { GST_WARNING_OBJECT (self, "Can not get element src or sink pad"); goto error; } if (!gst_bin_add (GST_BIN (self), data->element)) { GST_WARNING_OBJECT (self, "Can not add element to bin"); goto error; } if (peersrcpad) { if (GST_PAD_LINK_FAILED (gst_pad_link (peersrcpad, sinkpad))) { GST_WARNING_OBJECT (self, "Can not link sibling's %s:%s pad" " to element's %s:%s pad", GST_DEBUG_PAD_NAME (peersrcpad), GST_DEBUG_PAD_NAME (sinkpad)); goto error; } } else { if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->sinkpad), sinkpad)) { GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s", GST_DEBUG_PAD_NAME (sinkpad), GST_DEBUG_PAD_NAME (self->priv->sinkpad)); goto error; } } if (peersinkpad) { if (GST_PAD_LINK_FAILED (gst_pad_link (srcpad, peersinkpad))) { GST_WARNING_OBJECT (self, "Can not link element's %s:%s pad" " to sibling's %s:%s pad", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (peersinkpad)); goto error; } } else { if (!gst_ghost_pad_set_target (GST_GHOST_PAD (self->priv->srcpad), srcpad)) { GST_WARNING_OBJECT (self, "Can not set %s:%s as target for %s:%s", GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (self->priv->srcpad)); goto error; } } gst_object_unref (srcpad); gst_object_unref (sinkpad); if (!gst_element_sync_state_with_parent (data->element)) { GST_WARNING_OBJECT (self, "Can not sync element's state with parent"); goto error; } } else { GstElement *parent = NULL; GstPad *other_pad; GstCaps *caps = NULL, *peercaps = NULL; gboolean can_intersect; gboolean success; parent = gst_pad_get_parent_element (peer); if (parent != NULL) gst_object_unref (parent); if (parent != data->element) goto retry; if (gst_pad_get_direction (peer) == GST_PAD_SRC) other_pad = get_single_pad (data->element, GST_PAD_SINK); else other_pad = get_single_pad (data->element, GST_PAD_SRC); if (!other_pad) { GST_WARNING_OBJECT (self, "Can not get element's other pad"); goto error; } other_peer = gst_pad_get_peer (other_pad); gst_object_unref (other_pad); if (!other_peer) { GST_WARNING_OBJECT (self, "Can not get element's other peer"); goto error; } /* Get the negotiated caps for the source pad peer, * because renegotiation while the pipeline is playing doesn't work * that fast. */ if (gst_pad_get_direction (pad) == GST_PAD_SRC) caps = gst_pad_get_current_caps (pad); else peercaps = gst_pad_get_current_caps (other_peer); if (!caps) caps = gst_pad_query_caps (pad, NULL); if (!peercaps) peercaps = gst_pad_query_caps (other_peer, NULL); can_intersect = gst_caps_can_intersect (caps, peercaps); gst_caps_unref (caps); gst_caps_unref (peercaps); if (!can_intersect) { GST_WARNING_OBJECT (self, "Pads are incompatible without the element"); goto error; } if (gst_pad_get_direction (other_peer) == GST_PAD_SRC && gst_pad_is_active (other_peer)) { gulong probe_id; probe_id = gst_pad_add_probe (other_peer, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, wait_and_drop_eos_cb, NULL, NULL); gst_pad_send_event (peer, gst_event_new_eos ()); gst_pad_remove_probe (other_peer, probe_id); } gst_element_set_locked_state (data->element, TRUE); gst_element_set_state (data->element, GST_STATE_NULL); if (!gst_bin_remove (GST_BIN (self), data->element)) { GST_WARNING_OBJECT (self, "Element removal rejected"); goto error; } gst_element_set_locked_state (data->element, FALSE); if (gst_pad_get_direction (pad) == GST_PAD_SRC) success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (pad, other_peer, GST_PAD_LINK_CHECK_HIERARCHY | GST_PAD_LINK_CHECK_TEMPLATE_CAPS)); else success = GST_PAD_LINK_SUCCESSFUL (gst_pad_link_full (other_peer, pad, GST_PAD_LINK_CHECK_HIERARCHY | GST_PAD_LINK_CHECK_TEMPLATE_CAPS)); gst_object_unref (other_peer); other_peer = NULL; if (!success) { GST_ERROR_OBJECT (self, "Could not re-link after the element's" " removal"); goto error; } } gst_insert_bin_change_data_complete (self, data, TRUE); gst_object_unref (peer); GST_OBJECT_LOCK (self); continue; done: if (other_peer != NULL) gst_object_unref (other_peer); if (peer != NULL) gst_object_unref (peer); break; retry: GST_OBJECT_LOCK (self); g_queue_push_head (&self->priv->change_queue, data); goto done; error: /* Handle error */ gst_insert_bin_change_data_complete (self, data, FALSE); GST_OBJECT_LOCK (self); goto done; } next: gst_insert_bin_block_pad_unlock (self); }
static void uridecodebin_pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstDiscoverer * dc) { PrivateStream *ps; GstPad *sinkpad = NULL; GstCaps *caps; static GstCaps *subs_caps = NULL; if (!subs_caps) { subs_caps = gst_caps_from_string ("text/plain; text/x-pango-markup; " "subpicture/x-pgs; subpicture/x-dvb; application/x-subtitle-unknown; " "application/x-ssa; application/x-ass; subtitle/x-kate; " "video/x-dvd-subpicture; "); } GST_DEBUG_OBJECT (dc, "pad %s:%s", GST_DEBUG_PAD_NAME (pad)); ps = g_slice_new0 (PrivateStream); ps->dc = dc; ps->pad = pad; ps->queue = gst_element_factory_make ("queue", NULL); ps->sink = gst_element_factory_make ("fakesink", NULL); if (G_UNLIKELY (ps->queue == NULL || ps->sink == NULL)) goto error; g_object_set (ps->sink, "silent", TRUE, NULL); g_object_set (ps->queue, "max-size-buffers", 1, "silent", TRUE, NULL); caps = gst_pad_get_caps_reffed (pad); if (gst_caps_can_intersect (caps, subs_caps)) { /* Subtitle streams are sparse and don't provide any information - don't * wait for data to preroll */ g_object_set (ps->sink, "async", FALSE, NULL); } gst_caps_unref (caps); gst_bin_add_many (dc->priv->pipeline, ps->queue, ps->sink, NULL); if (!gst_element_link_pads_full (ps->queue, "src", ps->sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) goto error; if (!gst_element_sync_state_with_parent (ps->sink)) goto error; if (!gst_element_sync_state_with_parent (ps->queue)) goto error; sinkpad = gst_element_get_static_pad (ps->queue, "sink"); if (sinkpad == NULL) goto error; if (gst_pad_link_full (pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK) goto error; gst_object_unref (sinkpad); /* Add an event probe */ gst_pad_add_event_probe (pad, G_CALLBACK (_event_probe), ps); DISCO_LOCK (dc); dc->priv->streams = g_list_append (dc->priv->streams, ps); DISCO_UNLOCK (dc); GST_DEBUG_OBJECT (dc, "Done handling pad"); return; error: GST_ERROR_OBJECT (dc, "Error while handling pad"); if (sinkpad) gst_object_unref (sinkpad); if (ps->queue) gst_object_unref (ps->queue); if (ps->sink) gst_object_unref (ps->sink); g_slice_free (PrivateStream, ps); return; }
static void pad_added_cb (GstElement * timeline, GstPad * pad, GESTimelinePipeline * self) { OutputChain *chain; GESTrack *track; GstPad *sinkpad; gboolean reconfigured = FALSE; GST_DEBUG_OBJECT (self, "new pad %s:%s , caps:%" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (pad), GST_PAD_CAPS (pad)); if (G_UNLIKELY (!(track = ges_timeline_get_track_for_pad (self->priv->timeline, pad)))) { GST_WARNING_OBJECT (self, "Couldn't find coresponding track !"); return; } /* Don't connect track if it's not going to be used */ if (track->type == GES_TRACK_TYPE_VIDEO && !(self->priv->mode & TIMELINE_MODE_PREVIEW_VIDEO) && !(self->priv->mode & TIMELINE_MODE_RENDER) && !(self->priv->mode & TIMELINE_MODE_SMART_RENDER)) { GST_DEBUG_OBJECT (self, "Video track... but we don't need it. Not linking"); } if (track->type == GES_TRACK_TYPE_AUDIO && !(self->priv->mode & TIMELINE_MODE_PREVIEW_AUDIO) && !(self->priv->mode & TIMELINE_MODE_RENDER) && !(self->priv->mode & TIMELINE_MODE_SMART_RENDER)) { GST_DEBUG_OBJECT (self, "Audio track... but we don't need it. Not linking"); } /* Get an existing chain or create it */ if (!(chain = get_output_chain_for_track (self, track))) chain = new_output_chain_for_track (self, track); chain->srcpad = pad; /* Adding tee */ chain->tee = gst_element_factory_make ("tee", NULL); gst_bin_add (GST_BIN_CAST (self), chain->tee); gst_element_sync_state_with_parent (chain->tee); /* Linking pad to tee */ sinkpad = gst_element_get_static_pad (chain->tee, "sink"); gst_pad_link_full (pad, sinkpad, GST_PAD_LINK_CHECK_NOTHING); gst_object_unref (sinkpad); /* Connect playsink */ if (self->priv->mode & TIMELINE_MODE_PREVIEW) { const gchar *sinkpad_name; GstPad *tmppad; GST_DEBUG_OBJECT (self, "Connecting to playsink"); switch (track->type) { case GES_TRACK_TYPE_VIDEO: sinkpad_name = "video_sink"; break; case GES_TRACK_TYPE_AUDIO: sinkpad_name = "audio_sink"; break; case GES_TRACK_TYPE_TEXT: sinkpad_name = "text_sink"; break; default: GST_WARNING_OBJECT (self, "Can't handle tracks of type %d yet", track->type); goto error; } /* Request a sinkpad from playsink */ if (G_UNLIKELY (!(sinkpad = gst_element_get_request_pad (self->priv->playsink, sinkpad_name)))) { GST_ERROR_OBJECT (self, "Couldn't get a pad from the playsink !"); goto error; } tmppad = gst_element_get_request_pad (chain->tee, "src%d"); if (G_UNLIKELY (gst_pad_link_full (tmppad, sinkpad, GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) { GST_ERROR_OBJECT (self, "Couldn't link track pad to playsink"); gst_object_unref (tmppad); goto error; } gst_object_unref (tmppad); GST_DEBUG ("Reconfiguring playsink"); /* reconfigure playsink */ g_signal_emit_by_name (self->priv->playsink, "reconfigure", &reconfigured); GST_DEBUG ("'reconfigure' returned %d", reconfigured); /* We still hold a reference on the sinkpad */ chain->playsinkpad = sinkpad; } /* Connect to encodebin */ if (self->priv->mode & (TIMELINE_MODE_RENDER | TIMELINE_MODE_SMART_RENDER)) { GstPad *tmppad; GST_DEBUG_OBJECT (self, "Connecting to encodebin"); if (!chain->encodebinpad) { /* Check for unused static pads */ sinkpad = get_compatible_unlinked_pad (self->priv->encodebin, pad); if (sinkpad == NULL) { GstCaps *caps = gst_pad_get_caps_reffed (pad); /* If no compatible static pad is available, request a pad */ g_signal_emit_by_name (self->priv->encodebin, "request-pad", caps, &sinkpad); gst_caps_unref (caps); if (G_UNLIKELY (sinkpad == NULL)) { GST_ERROR_OBJECT (self, "Couldn't get a pad from encodebin !"); goto error; } } chain->encodebinpad = sinkpad; } tmppad = gst_element_get_request_pad (chain->tee, "src%d"); if (G_UNLIKELY (gst_pad_link_full (tmppad, chain->encodebinpad, GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)) { GST_WARNING_OBJECT (self, "Couldn't link track pad to playsink"); goto error; } gst_object_unref (tmppad); } /* If chain wasn't already present, insert it in list */ if (!get_output_chain_for_track (self, track)) self->priv->chains = g_list_append (self->priv->chains, chain); GST_DEBUG ("done"); return; error: { if (chain->tee) { gst_bin_remove (GST_BIN_CAST (self), chain->tee); } if (sinkpad) gst_object_unref (sinkpad); g_free (chain); } }
static GstElement * gst_auto_convert_add_element (GstAutoConvert * autoconvert, GstElementFactory * factory) { GstElement *element = NULL; GstPad *internal_sinkpad = NULL; GstPad *internal_srcpad = NULL; GstPad *sinkpad = NULL; GstPad *srcpad = NULL; GstPadLinkReturn padlinkret; GST_DEBUG_OBJECT (autoconvert, "Adding element %s to the autoconvert bin", gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); element = gst_element_factory_create (factory, NULL); if (!element) return NULL; if (!gst_bin_add (GST_BIN (autoconvert), element)) { GST_ERROR_OBJECT (autoconvert, "Could not add element %s to the bin", GST_OBJECT_NAME (element)); gst_object_unref (element); return NULL; } srcpad = get_pad_by_direction (element, GST_PAD_SRC); if (!srcpad) { GST_ERROR_OBJECT (autoconvert, "Could not find source in %s", GST_OBJECT_NAME (element)); goto error; } sinkpad = get_pad_by_direction (element, GST_PAD_SINK); if (!sinkpad) { GST_ERROR_OBJECT (autoconvert, "Could not find sink in %s", GST_OBJECT_NAME (element)); goto error; } internal_sinkpad = gst_pad_new_from_static_template (&sink_internal_template, "sink_internal"); internal_srcpad = gst_pad_new_from_static_template (&src_internal_template, "src_internal"); if (!internal_sinkpad || !internal_srcpad) { GST_ERROR_OBJECT (autoconvert, "Could not create internal pads"); if (internal_srcpad) gst_object_unref (internal_srcpad); if (internal_sinkpad) gst_object_unref (internal_sinkpad); goto error; } g_object_weak_ref (G_OBJECT (element), (GWeakNotify) gst_object_unref, internal_sinkpad); g_object_weak_ref (G_OBJECT (element), (GWeakNotify) gst_object_unref, internal_srcpad); gst_pad_set_active (internal_sinkpad, TRUE); gst_pad_set_active (internal_srcpad, TRUE); g_object_set_qdata (G_OBJECT (internal_srcpad), parent_quark, autoconvert); g_object_set_qdata (G_OBJECT (internal_sinkpad), parent_quark, autoconvert); gst_pad_set_chain_function (internal_sinkpad, GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_chain)); gst_pad_set_chain_list_function (internal_sinkpad, GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_chain_list)); gst_pad_set_event_function (internal_sinkpad, GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_event)); gst_pad_set_query_function (internal_sinkpad, GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_query)); gst_pad_set_event_function (internal_srcpad, GST_DEBUG_FUNCPTR (gst_auto_convert_internal_src_event)); gst_pad_set_query_function (internal_srcpad, GST_DEBUG_FUNCPTR (gst_auto_convert_internal_src_query)); padlinkret = gst_pad_link_full (internal_srcpad, sinkpad, GST_PAD_LINK_CHECK_NOTHING); if (GST_PAD_LINK_FAILED (padlinkret)) { GST_WARNING_OBJECT (autoconvert, "Could not links pad %s:%s to %s:%s" " for reason %d", GST_DEBUG_PAD_NAME (internal_srcpad), GST_DEBUG_PAD_NAME (sinkpad), padlinkret); goto error; } padlinkret = gst_pad_link_full (srcpad, internal_sinkpad, GST_PAD_LINK_CHECK_NOTHING); if (GST_PAD_LINK_FAILED (padlinkret)) { GST_WARNING_OBJECT (autoconvert, "Could not links pad %s:%s to %s:%s" " for reason %d", GST_DEBUG_PAD_NAME (internal_srcpad), GST_DEBUG_PAD_NAME (sinkpad), padlinkret); goto error; } g_object_set_qdata (G_OBJECT (element), internal_srcpad_quark, internal_srcpad); g_object_set_qdata (G_OBJECT (element), internal_sinkpad_quark, internal_sinkpad); /* Iffy */ gst_element_sync_state_with_parent (element); /* Increment the reference count we will return to the caller */ gst_object_ref (element); /* unref sink and src pad */ gst_object_unref (srcpad); gst_object_unref (sinkpad); return element; error: gst_element_set_locked_state (element, TRUE); gst_element_set_state (element, GST_STATE_NULL); gst_bin_remove (GST_BIN (autoconvert), element); if (srcpad) gst_object_unref (srcpad); if (sinkpad) gst_object_unref (sinkpad); return NULL; }
bool MediaSinkImpl::linkPad (std::shared_ptr<MediaSourceImpl> mediaSrc, GstPad *src) { RecMutex::Lock lock (mutex); std::shared_ptr<MediaSourceImpl> connectedSrcLocked; GstPad *sink; bool ret = false; try { connectedSrcLocked = connectedSrc.lock(); } catch (const std::bad_weak_ptr &e) { } if ( (sink = gst_element_get_static_pad (getGstreamerElement(), getPadName().c_str() ) ) == NULL) { sink = gst_element_get_request_pad (getGstreamerElement(), getPadName().c_str() ); } if (gst_pad_is_linked (sink) ) { unlink (connectedSrcLocked, sink); } if (std::dynamic_pointer_cast<MediaObjectImpl> (mediaSrc)->getParent() == getParent() ) { GstBin *container; GstElement *filter, *parent; GstPad *aux_sink, *aux_src; GST_DEBUG ("Connecting loopback, adding a capsfilter to allow connection"); parent = GST_ELEMENT (GST_OBJECT_PARENT (sink) ); if (parent == NULL) { goto end; } container = GST_BIN (GST_OBJECT_PARENT (parent) ); if (container == NULL) { goto end; } filter = gst_element_factory_make ("capsfilter", NULL); aux_sink = gst_element_get_static_pad (filter, "sink"); aux_src = gst_element_get_static_pad (filter, "src"); g_signal_connect (G_OBJECT (aux_sink), "unlinked", G_CALLBACK (sink_unlinked), filter ); g_signal_connect (G_OBJECT (aux_src), "unlinked", G_CALLBACK (src_unlinked), filter ); gst_bin_add (container, filter); gst_element_sync_state_with_parent (filter); if (gst_pad_link_full (aux_src, sink, GST_PAD_LINK_CHECK_NOTHING) == GST_PAD_LINK_OK) { if (gst_pad_link_full (src, aux_sink, GST_PAD_LINK_CHECK_NOTHING) == GST_PAD_LINK_OK) { ret = true; } else { gst_pad_unlink (aux_src, sink); } } g_object_unref (aux_sink); g_object_unref (aux_src); gst_debug_bin_to_dot_file_with_ts (GST_BIN (container), GST_DEBUG_GRAPH_SHOW_ALL, "loopback"); } else { if (gst_pad_link_full (src, sink, GST_PAD_LINK_CHECK_NOTHING) == GST_PAD_LINK_OK) { ret = true; } } if (ret == true) { connectedSrc = std::weak_ptr<MediaSourceImpl> (mediaSrc); } else { gst_element_release_request_pad (getGstreamerElement(), sink); } end: g_object_unref (sink); return ret; }