static void pad_added (GstElement *elem, GstPad *pad, PipelineChangeListenerContext *ctx) { GstPad *peer = gst_pad_get_peer (pad); GST_INFO ("found pad: %s (%s)", gst_pad_get_name (pad), G_OBJECT_TYPE_NAME (pad)); /* if this pad isn't already linked, setup a signal handler.. otherwise * simulate the signal: */ if (peer != NULL) { pad_linked (pad, peer, ctx); gst_object_unref (peer); } else { g_signal_connect (pad, "linked", pad_linked, ctx); } }
// Used to seal up unconnected source nodes by connecting unconnected src pads to fake sinks bool MediaNode::releaseFakeSinkIfConnected(GstElement *tee, GstElement *fakesink, GstElement *bin) { if (GST_ELEMENT_PARENT(fakesink) == GST_ELEMENT(bin)) { GstPad *sinkPad = gst_element_get_pad(fakesink, "sink"); // Release requested src pad from tee GstPad *requestedPad = gst_pad_get_peer(sinkPad); if (requestedPad) { gst_element_release_request_pad(tee, requestedPad); gst_object_unref(requestedPad); } gst_object_unref(sinkPad); gst_element_set_state(fakesink, GST_STATE_NULL); gst_bin_remove(GST_BIN(bin), fakesink); Q_ASSERT(!GST_ELEMENT_PARENT(fakesink)); } return true; }
static void gst_ghost_pad_dispose (GObject * object) { GstPad *pad; GstPad *internal; GstPad *peer; pad = GST_PAD (object); GST_DEBUG_OBJECT (pad, "dispose"); gst_ghost_pad_set_target (GST_GHOST_PAD (pad), NULL); /* Unlink here so that gst_pad_dispose doesn't. That would lead to a call to * gst_ghost_pad_do_unlink when the ghost pad is in an inconsistent state */ peer = gst_pad_get_peer (pad); if (peer) { if (GST_PAD_IS_SRC (pad)) gst_pad_unlink (pad, peer); else gst_pad_unlink (peer, pad); gst_object_unref (peer); } GST_PROXY_LOCK (pad); internal = GST_PROXY_PAD_INTERNAL (pad); gst_pad_set_activatepull_function (internal, NULL); gst_pad_set_activatepush_function (internal, NULL); g_signal_handler_disconnect (internal, GST_GHOST_PAD_PRIVATE (pad)->notify_id); /* disposes of the internal pad, since the ghostpad is the only possible object * that has a refcount on the internal pad. */ gst_object_unparent (GST_OBJECT_CAST (internal)); GST_PROXY_PAD_INTERNAL (pad) = NULL; GST_PROXY_UNLOCK (pad); G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object); }
static GstCaps * gst_play_sink_convert_bin_getcaps (GstPad * pad, GstCaps * filter) { GstPlaySinkConvertBin *self = GST_PLAY_SINK_CONVERT_BIN (gst_pad_get_parent (pad)); GstCaps *ret; GstPad *otherpad, *peer; GST_PLAY_SINK_CONVERT_BIN_LOCK (self); if (pad == self->srcpad) { otherpad = self->sinkpad; } else if (pad == self->sinkpad) { otherpad = self->srcpad; } else { GST_ERROR_OBJECT (pad, "Not one of our pads"); otherpad = NULL; } if (otherpad) { peer = gst_pad_get_peer (otherpad); if (peer) { GstCaps *peer_caps = gst_pad_query_caps (peer, filter); gst_object_unref (peer); if (self->converter_caps && is_raw_caps (peer_caps, self->audio)) { ret = gst_caps_merge (peer_caps, gst_caps_ref (self->converter_caps)); } else { ret = peer_caps; } } else { ret = gst_caps_ref (self->converter_caps); } } else { ret = gst_caps_new_any (); } GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self); gst_object_unref (self); GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret); return ret; }
static void kms_element_release_pad (GstElement * element, GstPad * pad) { GstElement *agnosticbin; GstPad *target; GstPad *peer; if (g_str_has_prefix (GST_OBJECT_NAME (pad), "audio_src")) { agnosticbin = KMS_ELEMENT (element)->priv->audio_agnosticbin; } else if (g_str_has_prefix (GST_OBJECT_NAME (pad), "video_src")) { agnosticbin = KMS_ELEMENT (element)->priv->video_agnosticbin; } else { return; } // TODO: Remove pad if is a sinkpad target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad)); if (target != NULL) { if (agnosticbin != NULL) { gst_element_release_request_pad (agnosticbin, target); } g_object_unref (target); } peer = gst_pad_get_peer (pad); gst_pad_push_event (pad, gst_event_new_flush_start ()); if (GST_STATE (element) >= GST_STATE_PAUSED || GST_STATE_PENDING (element) >= GST_STATE_PAUSED) { gst_pad_set_active (pad, FALSE); } if (peer) { gst_pad_send_event (peer, gst_event_new_flush_stop (FALSE)); g_object_unref (peer); } gst_element_remove_pad (element, pad); }
static void mex_telepathy_channel_update_video_parameters (MexTelepathyChannel *self, gboolean restart) { MexTelepathyChannelPrivate *priv = self->priv; GstCaps *caps; GstPad *src, *peer; src = gst_element_get_static_pad (priv->video_input, "src"); peer = gst_pad_get_peer (src); if (restart) { /* Assuming the pipeline is in playing state */ gst_element_set_locked_state (priv->video_input, TRUE); gst_element_set_state (priv->video_input, GST_STATE_NULL); gst_bin_remove (GST_BIN (priv->pipeline), priv->video_input); } g_object_get (priv->video_capsfilter, "caps", &caps, NULL); caps = gst_caps_make_writable (caps); gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, priv->framerate, 1, "width", G_TYPE_INT, priv->width, "height", G_TYPE_INT, priv->height, NULL); g_object_set (priv->video_capsfilter, "caps", caps, NULL); if (restart) { gst_bin_add (GST_BIN (priv->pipeline), priv->video_input); gst_pad_link (src, peer); gst_element_set_locked_state (priv->video_input, FALSE); gst_element_sync_state_with_parent (priv->video_input); } gst_object_unref (src); gst_object_unref (peer); }
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); }
static void gst_uri_downloader_stop (GstUriDownloader * downloader) { GstPad *pad; GST_DEBUG_OBJECT (downloader, "Stopping source element"); /* remove the bus' sync handler */ gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL); /* unlink the source element from the internal pad */ pad = gst_pad_get_peer (downloader->priv->pad); if (pad) { gst_pad_unlink (pad, downloader->priv->pad); gst_object_unref (pad); } /* set the element state to NULL */ gst_element_set_state (downloader->priv->urisrc, GST_STATE_NULL); gst_element_get_state (downloader->priv->urisrc, NULL, NULL, GST_CLOCK_TIME_NONE); }
static void gst_v4l2sink_navigation_send_event (GstNavigation * navigation, GstStructure * structure) { GstV4l2Sink *v4l2sink = GST_V4L2SINK (navigation); GstV4l2Xv *xv = v4l2sink->v4l2object->xv; GstPad *peer; if (!xv) return; if ((peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (v4l2sink)))) { GstVideoRectangle rect; gdouble x, y, xscale = 1.0, yscale = 1.0; gst_v4l2_video_overlay_get_render_rect (v4l2sink->v4l2object, &rect); /* We calculate scaling using the original video frames geometry to * include pixel aspect ratio scaling. */ xscale = (gdouble) v4l2sink->video_width / rect.w; yscale = (gdouble) v4l2sink->video_height / rect.h; /* Converting pointer coordinates to the non scaled geometry */ if (gst_structure_get_double (structure, "pointer_x", &x)) { x = MIN (x, rect.x + rect.w); x = MAX (x - rect.x, 0); gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, (gdouble) x * xscale, NULL); } if (gst_structure_get_double (structure, "pointer_y", &y)) { y = MIN (y, rect.y + rect.h); y = MAX (y - rect.y, 0); gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, (gdouble) y * yscale, NULL); } gst_pad_send_event (peer, gst_event_new_navigation (structure)); gst_object_unref (peer); } }
static void gst_glimage_sink_navigation_send_event (GstNavigation * navigation, GstStructure * structure) { GstGLImageSink *sink = GST_GLIMAGE_SINK (navigation); GstEvent *event = NULL; GstPad *pad = NULL; GstGLWindow *window = gst_gl_context_get_window (sink->context); guint width, height; gdouble x, y, xscale, yscale; g_return_if_fail (GST_GL_IS_WINDOW (window)); width = GST_VIDEO_SINK_WIDTH (sink); height = GST_VIDEO_SINK_HEIGHT (sink); gst_gl_window_get_surface_dimensions (window, &width, &height); event = gst_event_new_navigation (structure); pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink)); /* Converting pointer coordinates to the non scaled geometry */ if (width != GST_VIDEO_SINK_WIDTH (sink) && width != 0 && gst_structure_get_double (structure, "pointer_x", &x)) { xscale = (gdouble) GST_VIDEO_SINK_WIDTH (sink) / width; gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, (gdouble) x * xscale, NULL); } if (height != GST_VIDEO_SINK_HEIGHT (sink) && height != 0 && gst_structure_get_double (structure, "pointer_y", &y)) { yscale = (gdouble) GST_VIDEO_SINK_HEIGHT (sink) / height; gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, (gdouble) y * yscale, NULL); } if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) gst_pad_send_event (pad, event); gst_object_unref (pad); gst_object_unref (window); }
GstPadProbeReturn stop_pad_cb (GstPad *pad, GstPadProbeInfo *info, gpointer data) { MbMedia *media = NULL; GstPad *peer; GST_DEBUG_OBJECT(pad, "pad is blocked now"); /* first remove the probe */ gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID(info)); media = (MbMedia *) data; g_assert (media); peer = gst_pad_get_peer (pad); g_assert(peer); gst_pad_send_event (peer, gst_event_new_eos ()); gst_object_unref(peer); return GST_PAD_PROBE_OK; }
static void check_all_streams_for_eos (GstDecodebin3 * dbin) { GList *tmp; if (!all_inputs_are_eos (dbin)) return; /* We know all streams are EOS, properly clean up everything */ for (tmp = dbin->input_streams; tmp; tmp = tmp->next) { DecodebinInputStream *input = (DecodebinInputStream *) tmp->data; GstPad *peer = gst_pad_get_peer (input->srcpad); /* Send EOS and then remove elements */ if (peer) { gst_pad_send_event (peer, gst_event_new_eos ()); gst_object_unref (peer); } GST_FIXME_OBJECT (input->srcpad, "Remove input stream"); } }
static gboolean idle_unlink (gpointer data) { GstPad *sink, *src; GstElement *decoder = (GstElement *) data; GstElement *agnostic = g_object_get_data (G_OBJECT (decoder), AGNOSTIC_KEY); sink = gst_element_get_static_pad (decoder, "sink"); src = gst_pad_get_peer (sink); gst_pad_unlink (src, sink); gst_element_release_request_pad (agnostic, src); g_object_unref (src); g_object_unref (sink); g_timeout_add (200, link_again, decoder); return FALSE; }
static gboolean gst_shape_wipe_src_query (GstPad * pad, GstQuery * query) { GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad)); gboolean ret; GstPad *peer = gst_pad_get_peer (self->video_sinkpad); GST_DEBUG_OBJECT (pad, "Handling query of type '%s'", gst_query_type_get_name (GST_QUERY_TYPE (query))); if (!peer) { GST_INFO_OBJECT (pad, "No peer yet"); ret = FALSE; } else { ret = gst_pad_query (peer, query); gst_object_unref (peer); } gst_object_unref (self); return ret; }
static void gst_d3dvideosink_navigation_send_event (GstNavigation * navigation, GstStructure * structure) { GstD3DVideoSink *sink = GST_D3DVIDEOSINK (navigation); GstEvent *e; if ((e = gst_event_new_navigation (structure))) { GstPad *pad; if ((pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink)))) { if (!gst_pad_send_event (pad, gst_event_ref (e))) { /* If upstream didn't handle the event we'll post a message with it * for the application in case it wants to do something with it */ gst_element_post_message (GST_ELEMENT_CAST (sink), gst_navigation_message_new_event (GST_OBJECT_CAST (sink), e)); } gst_event_unref (e); gst_object_unref (pad); } } }
static GstPadProbeReturn remove_on_unlinked_blocked (GstPad * pad, GstPadProbeInfo * info, gpointer elem) { KmsAgnosticBin2 *self; GstPad *sink; if (elem == NULL) { return GST_PAD_PROBE_REMOVE; } GST_DEBUG_OBJECT (pad, "Unlinking pad"); GST_OBJECT_LOCK (pad); if (g_object_get_qdata (G_OBJECT (pad), unlinking_data_quark ())) { GST_OBJECT_UNLOCK (pad); if (GST_PAD_PROBE_INFO_TYPE (info) & GST_PAD_PROBE_TYPE_QUERY_BOTH) { /* Queries must be answered */ return GST_PAD_PROBE_PASS; } else { return GST_PAD_PROBE_DROP; } } g_object_set_qdata (G_OBJECT (pad), unlinking_data_quark (), GINT_TO_POINTER (TRUE)); GST_OBJECT_UNLOCK (pad); sink = gst_pad_get_peer (pad); if (sink != NULL) { gst_pad_unlink (pad, sink); g_object_unref (sink); } self = KMS_AGNOSTIC_BIN2 (GST_OBJECT_PARENT (elem)); g_thread_pool_push (self->priv->remove_pool, g_object_ref (elem), NULL); return GST_PAD_PROBE_PASS; }
static void gst_ghost_pad_dispose (GObject * object) { GstPad *pad; GstPad *internal; GstPad *intpeer; pad = GST_PAD (object); GST_DEBUG_OBJECT (pad, "dispose"); GST_PROXY_LOCK (pad); internal = GST_PROXY_PAD_INTERNAL (pad); gst_pad_set_activatepull_function (internal, NULL); gst_pad_set_activatepush_function (internal, NULL); g_signal_handler_disconnect (internal, GST_GHOST_PAD_CAST (pad)->notify_id); intpeer = gst_pad_get_peer (internal); if (intpeer) { if (GST_PAD_IS_SRC (internal)) gst_pad_unlink (internal, intpeer); else gst_pad_unlink (intpeer, internal); gst_object_unref (intpeer); } GST_PROXY_PAD_INTERNAL (internal) = NULL; /* disposes of the internal pad, since the ghostpad is the only possible object * that has a refcount on the internal pad. */ gst_object_unparent (GST_OBJECT_CAST (internal)); GST_PROXY_UNLOCK (pad); G_OBJECT_CLASS (gst_ghost_pad_parent_class)->dispose (object); }
/* Must be called with mutex locked. */ static void gst_uri_downloader_stop (GstUriDownloader * downloader) { GstPad *pad; GstElement *urisrc; if (!downloader->priv->urisrc) return; GST_DEBUG_OBJECT (downloader, "Stopping source element %s", GST_ELEMENT_NAME (downloader->priv->urisrc)); /* remove the bus' sync handler */ gst_bus_set_sync_handler (downloader->priv->bus, NULL, NULL, NULL); /* unlink the source element from the internal pad */ pad = gst_pad_get_peer (downloader->priv->pad); if (pad) { gst_pad_unlink (pad, downloader->priv->pad); gst_object_unref (pad); } urisrc = downloader->priv->urisrc; downloader->priv->urisrc = NULL; /* unlock so it doesn't block on chain function while changing state */ g_mutex_unlock (&downloader->priv->lock); GST_DEBUG_OBJECT (downloader, "Stopping source element %s", GST_ELEMENT_NAME (urisrc)); /* set the element state to NULL */ gst_element_set_state (urisrc, GST_STATE_NULL); gst_element_get_state (urisrc, NULL, NULL, GST_CLOCK_TIME_NONE); gst_element_set_bus (urisrc, NULL); gst_object_unref (urisrc); /* caller expects the mutex to be locked */ g_mutex_lock (&downloader->priv->lock); gst_bus_set_flushing (downloader->priv->bus, TRUE); }
static gboolean pipeline_op (GObject *player, GstElement *fixture, GstElement *element, gboolean use_pad_block, GstPadBlockCallback callback) { RBGstPipelineOp *op; GstPad *fixture_pad; GstPad *block_pad; op = new_pipeline_op (player, fixture, element); /* seems like we should be able to just block the src pad connected * to the fixture's sink pad.. */ fixture_pad = gst_element_get_static_pad (fixture, "sink"); block_pad = gst_pad_get_peer (fixture_pad); gst_object_unref (fixture_pad); if (use_pad_block) { char *whatpad; whatpad = gst_object_get_path_string (GST_OBJECT (block_pad)); rb_debug ("blocking pad %s to perform an operation", whatpad); g_free (whatpad); gst_pad_set_blocked_async (block_pad, TRUE, callback, op); } else { rb_debug ("not using pad blocking, calling op directly"); (*callback) (block_pad, FALSE, op); } gst_object_unref (block_pad); return TRUE; }
static gboolean gst_ghost_pad_internal_activate_pull_default (GstPad * pad, GstObject * parent, gboolean active) { gboolean ret; GstPad *other; GST_LOG_OBJECT (pad, "%sactivate pull on %s:%s", (active ? "" : "de"), GST_DEBUG_PAD_NAME (pad)); if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) { /* we are activated in pull mode by our peer element, which is a sinkpad * that wants to operate in pull mode. This activation has to propagate * upstream through the pipeline. We call the internal activation function, * which will trigger gst_ghost_pad_activate_pull_default, which propagates even * further upstream */ GST_LOG_OBJECT (pad, "pad is src, activate internal"); GST_PROXY_PAD_ACQUIRE_INTERNAL (pad, other, FALSE); ret = gst_pad_activate_mode (other, GST_PAD_MODE_PULL, active); GST_PROXY_PAD_RELEASE_INTERNAL (other); } else if (G_LIKELY ((other = gst_pad_get_peer (pad)))) { /* We are SINK, the ghostpad is SRC, we propagate the activation upstream * since we hold a pointer to the upstream peer. */ GST_LOG_OBJECT (pad, "activating peer"); ret = gst_pad_activate_mode (other, GST_PAD_MODE_PULL, active); gst_object_unref (other); } else if (active) { /* this is failure, we can't activate pull if there is no peer */ GST_LOG_OBJECT (pad, "not src and no peer, failing"); ret = FALSE; } else { GST_LOG_OBJECT (pad, "deactivating pull, with no peer - allowing"); ret = TRUE; } return ret; }
static void remove_input_stream (GstDecodebin3 * dbin, DecodebinInputStream * stream) { MultiQueueSlot *slot; GST_DEBUG_OBJECT (dbin, "Removing input stream %p (%s)", stream, stream->active_stream ? gst_stream_get_stream_id (stream->active_stream) : "<NONE>"); /* Unlink from slot */ if (stream->srcpad) { GstPad *peer; peer = gst_pad_get_peer (stream->srcpad); if (peer) { gst_pad_unlink (stream->srcpad, peer); gst_object_unref (peer); } } g_mutex_lock (&dbin->selection_lock); slot = get_slot_for_input (dbin, stream); g_mutex_unlock (&dbin->selection_lock); if (slot) { slot->pending_stream = NULL; slot->input = NULL; GST_DEBUG_OBJECT (dbin, "slot %p cleared", slot); } if (stream->active_stream) gst_object_unref (stream->active_stream); if (stream->pending_stream) gst_object_unref (stream->pending_stream); dbin->input_streams = g_list_remove (dbin->input_streams, stream); g_free (stream); }
static gboolean gst_splitmux_part_reader_send_event (GstElement * element, GstEvent * event) { GstSplitMuxPartReader *reader = (GstSplitMuxPartReader *) element; gboolean ret = FALSE; GstPad *pad = NULL; /* Send event to the first source pad we found */ SPLITMUX_PART_LOCK (reader); if (reader->pads) { GstPad *proxy_pad = GST_PAD_CAST (reader->pads->data); pad = gst_pad_get_peer (proxy_pad); } SPLITMUX_PART_UNLOCK (reader); if (pad) { ret = gst_pad_send_event (pad, event); gst_object_unref (pad); } else { gst_event_unref (event); } return ret; }
static void gst_hls_sink2_release_pad (GstElement * element, GstPad * pad) { GstHlsSink2 *sink = GST_HLS_SINK2_CAST (element); GstPad *peer; g_return_if_fail (pad == sink->audio_sink || pad == sink->video_sink); peer = gst_pad_get_peer (pad); if (peer) { gst_element_release_request_pad (sink->splitmuxsink, pad); gst_object_unref (peer); } gst_object_ref (pad); gst_element_remove_pad (element, pad); gst_pad_set_active (pad, FALSE); if (pad == sink->audio_sink) sink->audio_sink = NULL; else sink->video_sink = NULL; gst_object_unref (pad); }
/* Clean up output/input pad and respective selector request pad */ void cleanup_pad (GstPad * pad, GstElement * element) { GstPad *selpad = NULL; guint probe_id = 0; fail_if (pad == NULL, "pad doesn't exist"); /* remove probe if necessary */ probe_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "probe_id")); if (probe_id) gst_pad_remove_data_probe (pad, probe_id); /* unlink */ selpad = gst_pad_get_peer (pad); if (GST_PAD_DIRECTION (selpad) == GST_PAD_SRC) { gst_pad_unlink (selpad, pad); } else { gst_pad_unlink (pad, selpad); } /* caps could have been set, make sure they get unset */ gst_pad_set_caps (pad, NULL); GST_DEBUG_OBJECT (pad, "clean up %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT, selpad, pad); /* cleanup the pad */ gst_pad_set_active (pad, FALSE); ASSERT_OBJECT_REFCOUNT (pad, "pad", 1); gst_object_unref (pad); /* cleanup selector pad, reffed by this function (_get_peer) and creator */ gst_element_release_request_pad (element, selpad); gst_object_unref (selpad); }
static void gst_gtk_base_sink_navigation_send_event (GstNavigation * navigation, GstStructure * structure) { GstGtkBaseSink *sink = GST_GTK_BASE_SINK (navigation); GstEvent *event; GstPad *pad; event = gst_event_new_navigation (structure); pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink)); GST_TRACE_OBJECT (sink, "navigation event %" GST_PTR_FORMAT, structure); if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) { if (!gst_pad_send_event (pad, gst_event_ref (event))) { /* If upstream didn't handle the event we'll post a message with it * for the application in case it wants to do something with it */ gst_element_post_message (GST_ELEMENT_CAST (sink), gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event)); } gst_event_unref (event); gst_object_unref (pad); } }
static GstCaps * gst_aspect_ratio_crop_get_caps (GstPad * pad, GstCaps * filter) { GstPad *peer; GstAspectRatioCrop *aspect_ratio_crop; GstCaps *return_caps; aspect_ratio_crop = GST_ASPECT_RATIO_CROP (gst_pad_get_parent (pad)); g_mutex_lock (&aspect_ratio_crop->crop_lock); peer = gst_pad_get_peer (aspect_ratio_crop->sink); if (peer == NULL) { return_caps = gst_static_pad_template_get_caps (&src_template); } else { GstCaps *peer_caps; peer_caps = gst_pad_query_caps (peer, filter); return_caps = gst_aspect_ratio_crop_transform_caps (aspect_ratio_crop, peer_caps); gst_caps_unref (peer_caps); gst_object_unref (peer); } g_mutex_unlock (&aspect_ratio_crop->crop_lock); gst_object_unref (aspect_ratio_crop); if (return_caps && filter) { GstCaps *tmp = gst_caps_intersect_full (filter, return_caps, GST_CAPS_INTERSECT_FIRST); gst_caps_replace (&return_caps, tmp); gst_caps_unref (tmp); } return return_caps; }
static void pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self) { GstPad *peer; GstCaps *caps; gboolean raw; GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self); self->sink_proxypad_blocked = blocked; GST_DEBUG_OBJECT (self, "Pad blocked: %d", blocked); if (!blocked) goto done; /* There must be a peer at this point */ peer = gst_pad_get_peer (self->sinkpad); caps = gst_pad_get_negotiated_caps (peer); if (!caps) caps = gst_pad_get_caps_reffed (peer); gst_object_unref (peer); raw = is_raw_caps (caps); GST_DEBUG_OBJECT (self, "Caps %" GST_PTR_FORMAT " are raw: %d", caps, raw); gst_caps_unref (caps); if (raw == self->raw) goto unblock; self->raw = raw; if (raw) { GstBin *bin = GST_BIN_CAST (self); GstElement *head = NULL, *prev = NULL; GstPad *pad; GST_DEBUG_OBJECT (self, "Creating raw conversion pipeline"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL); self->conv = gst_element_factory_make ("ffmpegcolorspace", "conv"); if (self->conv == NULL) { post_missing_element_message (self, "ffmpegcolorspace"); GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "ffmpegcolorspace"), ("video rendering might fail")); } else { gst_bin_add (bin, self->conv); gst_element_sync_state_with_parent (self->conv); distribute_running_time (self->conv, &self->segment); prev = head = self->conv; } self->scale = gst_element_factory_make ("videoscale", "scale"); if (self->scale == NULL) { post_missing_element_message (self, "videoscale"); GST_ELEMENT_WARNING (self, CORE, MISSING_PLUGIN, (_("Missing element '%s' - check your GStreamer installation."), "videoscale"), ("possibly a liboil version mismatch?")); } else { /* Add black borders if necessary to keep the DAR */ g_object_set (self->scale, "add-borders", TRUE, NULL); gst_bin_add (bin, self->scale); gst_element_sync_state_with_parent (self->scale); distribute_running_time (self->scale, &self->segment); if (prev) { if (!gst_element_link_pads_full (prev, "src", self->scale, "sink", GST_PAD_LINK_CHECK_TEMPLATE_CAPS)) goto link_failed; } else { head = self->scale; } prev = self->scale; } if (head) { pad = gst_element_get_static_pad (head, "sink"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), pad); gst_object_unref (pad); } if (prev) { pad = gst_element_get_static_pad (prev, "src"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), pad); gst_object_unref (pad); } if (!head && !prev) { gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); } GST_DEBUG_OBJECT (self, "Raw conversion pipeline created"); } else { GstBin *bin = GST_BIN_CAST (self); GST_DEBUG_OBJECT (self, "Removing raw conversion pipeline"); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->sinkpad), NULL); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), NULL); if (self->conv) { gst_element_set_state (self->conv, GST_STATE_NULL); gst_bin_remove (bin, self->conv); self->conv = NULL; } if (self->scale) { gst_element_set_state (self->scale, GST_STATE_NULL); gst_bin_remove (bin, self->scale); self->scale = NULL; } gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); GST_DEBUG_OBJECT (self, "Raw conversion pipeline removed"); } unblock: gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE, (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self), (GDestroyNotify) gst_object_unref); done: GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self); return; link_failed: { GST_ELEMENT_ERROR (self, CORE, PAD, (NULL), ("Failed to configure the video converter.")); gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (self->srcpad), self->sink_proxypad); gst_pad_set_blocked_async_full (self->sink_proxypad, FALSE, (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self), (GDestroyNotify) gst_object_unref); return; } }
/* Helper function to test delayed linking support in parse_launch by creating * a test element based on bin, which contains a fakesrc and a sometimes * pad-template, and trying to link to a fakesink. When the bin transitions * to paused it adds a pad, which should get linked to the fakesink */ static void run_delayed_test (const gchar * pipe_str, const gchar * peer, gboolean expect_link) { GstElement *pipe, *src, *sink; GstPad *srcpad, *sinkpad, *peerpad = NULL; pipe = setup_pipeline (pipe_str); src = gst_bin_get_by_name (GST_BIN (pipe), "src"); fail_if (src == NULL, "Test source element was not created"); sink = gst_bin_get_by_name (GST_BIN (pipe), "sink"); fail_if (sink == NULL, "Test sink element was not created"); /* The src should not yet have a src pad */ srcpad = gst_element_get_static_pad (src, "src"); fail_unless (srcpad == NULL, "Source element already has a source pad"); /* Set the state to PAUSED and wait until the src at least reaches that * state */ fail_if (gst_element_set_state (pipe, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE); fail_if (gst_element_get_state (src, NULL, NULL, GST_CLOCK_TIME_NONE) == GST_STATE_CHANGE_FAILURE); /* Now, the source element should have a src pad, and if "peer" was passed, * then the src pad should have gotten linked to the 'sink' pad of that * peer */ srcpad = gst_element_get_static_pad (src, "src"); fail_if (srcpad == NULL, "Source element did not create source pad"); peerpad = gst_pad_get_peer (srcpad); if (expect_link == TRUE) { fail_if (peerpad == NULL, "Source element pad did not get linked"); } else { fail_if (peerpad != NULL, "Source element pad got linked but should not have"); } if (peerpad != NULL) gst_object_unref (peerpad); if (peer != NULL) { GstElement *peer_elem = gst_bin_get_by_name (GST_BIN (pipe), peer); fail_if (peer_elem == NULL, "Could not retrieve peer %s", peer); sinkpad = gst_element_get_static_pad (peer_elem, "sink"); fail_if (sinkpad == NULL, "Peer element did not have a 'sink' pad"); fail_unless (peerpad == sinkpad, "Source src pad got connected to the wrong peer"); gst_object_unref (sinkpad); } gst_object_unref (srcpad); gst_object_unref (src); gst_object_unref (sink); gst_element_set_state (pipe, GST_STATE_NULL); gst_object_unref (pipe); }
static void run_output_order_test (gint n_linked) { /* This test creates a multiqueue with 2 linked output, and 3 outputs that * return 'not-linked' when data is pushed, then verifies that all buffers * are received on not-linked pads only after earlier buffers on the * 'linked' pads are made */ GstElement *pipe; GstElement *mq; GstPad *inputpads[5]; GstPad *sinkpads[5]; struct PadData pad_data[5]; guint32 max_linked_id; guint32 eos_seen; GMutex *mutex; GCond *cond; gint i; const gint NPADS = 5; const gint NBUFFERS = 1000; mutex = g_mutex_new (); cond = g_cond_new (); pipe = gst_bin_new ("testbin"); mq = gst_element_factory_make ("multiqueue", NULL); fail_unless (mq != NULL); gst_bin_add (GST_BIN (pipe), mq); /* No limits */ g_object_set (mq, "max-size-bytes", (guint) 0, "max-size-buffers", (guint) 0, "max-size-time", (guint64) 0, "extra-size-bytes", (guint) 0, "extra-size-buffers", (guint) 0, "extra-size-time", (guint64) 0, NULL); /* Construct NPADS dummy output pads. The first 'n_linked' return FLOW_OK, the rest * return NOT_LINKED. The not-linked ones check the expected ordering of * output buffers */ for (i = 0; i < NPADS; i++) { GstPad *mq_srcpad, *mq_sinkpad; gchar *name; name = g_strdup_printf ("dummysrc%d", i); inputpads[i] = gst_pad_new (name, GST_PAD_SRC); g_free (name); gst_pad_set_getcaps_function (inputpads[i], mq_dummypad_getcaps); mq_sinkpad = gst_element_get_request_pad (mq, "sink%d"); fail_unless (mq_sinkpad != NULL); gst_pad_link (inputpads[i], mq_sinkpad); gst_pad_set_active (inputpads[i], TRUE); mq_srcpad = mq_sinkpad_to_srcpad (mq, mq_sinkpad); name = g_strdup_printf ("dummysink%d", i); sinkpads[i] = gst_pad_new (name, GST_PAD_SINK); g_free (name); gst_pad_set_chain_function (sinkpads[i], mq_dummypad_chain); gst_pad_set_event_function (sinkpads[i], mq_dummypad_event); gst_pad_set_getcaps_function (sinkpads[i], mq_dummypad_getcaps); pad_data[i].pad_num = i; pad_data[i].max_linked_id_ptr = &max_linked_id; pad_data[i].eos_count_ptr = &eos_seen; pad_data[i].is_linked = (i < n_linked ? TRUE : FALSE); pad_data[i].n_linked = n_linked; pad_data[i].cond = cond; pad_data[i].mutex = mutex; pad_data[i].first_buf = TRUE; gst_pad_set_element_private (sinkpads[i], pad_data + i); gst_pad_link (mq_srcpad, sinkpads[i]); gst_pad_set_active (sinkpads[i], TRUE); gst_object_unref (mq_sinkpad); gst_object_unref (mq_srcpad); } /* Run the test. Push 1000 buffers through the multiqueue in a pattern */ max_linked_id = 0; eos_seen = 0; gst_element_set_state (pipe, GST_STATE_PLAYING); for (i = 0; i < NBUFFERS; i++) { const guint8 pad_pattern[] = { 0, 0, 0, 0, 1, 1, 2, 1, 0, 2, 3, 2, 3, 1, 4 }; const guint n = sizeof (pad_pattern) / sizeof (guint8); guint8 cur_pad; GstBuffer *buf; GstFlowReturn ret; cur_pad = pad_pattern[i % n]; buf = gst_buffer_new_and_alloc (4); g_static_mutex_lock (&_check_lock); fail_if (buf == NULL); g_static_mutex_unlock (&_check_lock); GST_WRITE_UINT32_BE (GST_BUFFER_DATA (buf), i + 1); GST_BUFFER_TIMESTAMP (buf) = (i + 1) * GST_SECOND; ret = gst_pad_push (inputpads[cur_pad], buf); g_static_mutex_lock (&_check_lock); if (pad_data[cur_pad].is_linked) { fail_unless (ret == GST_FLOW_OK, "Push on pad %d returned %d when FLOW_OK was expected", cur_pad, ret); } else { /* Expect OK initially, then NOT_LINKED when the srcpad starts pushing */ fail_unless (ret == GST_FLOW_OK || ret == GST_FLOW_NOT_LINKED, "Push on pad %d returned %d when FLOW_OK or NOT_LINKED was expected", cur_pad, ret); } g_static_mutex_unlock (&_check_lock); } for (i = 0; i < NPADS; i++) { gst_pad_push_event (inputpads[i], gst_event_new_eos ()); } /* Wait while the buffers are processed */ g_mutex_lock (mutex); while (eos_seen < 5) { g_cond_wait (cond, mutex); } g_mutex_unlock (mutex); /* Clean up */ for (i = 0; i < 5; i++) { GstPad *mq_input = gst_pad_get_peer (inputpads[i]); gst_pad_unlink (inputpads[i], mq_input); gst_element_release_request_pad (mq, mq_input); gst_object_unref (mq_input); gst_object_unref (inputpads[i]); gst_object_unref (sinkpads[i]); } gst_element_set_state (pipe, GST_STATE_NULL); gst_object_unref (pipe); g_cond_free (cond); g_mutex_free (mutex); }
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); }