static gboolean gst_selector_pad_acceptcaps (GstPad * pad, GstCaps * caps) { GstInputSelector *sel; gboolean res; sel = GST_INPUT_SELECTOR (gst_pad_get_parent (pad)); GST_DEBUG_OBJECT (sel, "Checking acceptcaps of srcpad peer"); res = gst_pad_peer_accept_caps (sel->srcpad, caps); gst_object_unref (sel); return res; }
static gboolean gst_caps_debug_acceptcaps (GstPad * pad, GstCaps * caps) { GstCapsDebug *capsdebug; gchar *s; gboolean ret; GstPad *otherpad; capsdebug = GST_CAPS_DEBUG (gst_pad_get_parent (pad)); otherpad = (pad == capsdebug->srcpad) ? capsdebug->sinkpad : capsdebug->srcpad; s = gst_caps_to_string (caps); GST_INFO ("%s called acceptcaps with %s", THISPAD, s); g_free (s); ret = gst_pad_peer_accept_caps (otherpad, caps); GST_INFO ("%s returned %s", OTHERPAD, ret ? "TRUE" : "FALSE"); gst_object_unref (capsdebug); return ret; }
/* Buffer management * * The buffer_alloc function must either return a buffer with given size and * caps or create a buffer with different caps attached to the buffer. This * last option is called reverse negotiation, ie, where the sink suggests a * different format from the upstream peer. * * We try to do reverse negotiation when our geometry changes and we like a * resized buffer. */ static GstFlowReturn gst_vdp_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf) { VdpSink *vdp_sink; GstStructure *structure = NULL; GstFlowReturn ret = GST_FLOW_OK; gint width, height; GstCaps *alloc_caps; gint w_width, w_height; GError *err; vdp_sink = GST_VDP_SINK (bsink); GST_LOG_OBJECT (vdp_sink, "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT " and offset %" G_GUINT64_FORMAT, size, caps, offset); /* get struct to see what is requested */ structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "width", &width) || !gst_structure_get_int (structure, "height", &height)) { GST_WARNING_OBJECT (vdp_sink, "invalid caps for buffer allocation %" GST_PTR_FORMAT, caps); ret = GST_FLOW_NOT_NEGOTIATED; goto beach; } alloc_caps = gst_caps_ref (caps); /* We take the flow_lock because the window might go away */ g_mutex_lock (vdp_sink->flow_lock); if (!vdp_sink->window) { g_mutex_unlock (vdp_sink->flow_lock); goto alloc; } /* What is our geometry */ gst_vdp_sink_window_update_geometry (vdp_sink, vdp_sink->window); w_width = vdp_sink->window->width; w_height = vdp_sink->window->height; g_mutex_unlock (vdp_sink->flow_lock); /* We would like another geometry */ if (width != w_width || height != w_height) { GstCaps *new_caps, *allowed_caps, *desired_caps; GstStructure *desired_struct; /* make a copy of the incomming caps to create the new * suggestion. We can't use make_writable because we might * then destroy the original caps which we still need when the * peer does not accept the suggestion. */ new_caps = gst_caps_copy (caps); desired_struct = gst_caps_get_structure (new_caps, 0); GST_DEBUG ("we would love to receive a %dx%d video", w_width, w_height); gst_structure_set (desired_struct, "width", G_TYPE_INT, w_width, NULL); gst_structure_set (desired_struct, "height", G_TYPE_INT, w_height, NULL); allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (vdp_sink)); desired_caps = gst_caps_intersect (new_caps, allowed_caps); gst_caps_unref (new_caps); gst_caps_unref (allowed_caps); /* see if peer accepts our new suggestion, if there is no peer, this * function returns true. */ if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (vdp_sink), desired_caps)) { /* we will not alloc a buffer of the new suggested caps. Make sure * we also unref this new caps after we set it on the buffer. */ GST_DEBUG ("peer pad accepts our desired caps %" GST_PTR_FORMAT, desired_caps); gst_caps_unref (alloc_caps); alloc_caps = desired_caps; } else { GST_DEBUG ("peer pad does not accept our desired caps %" GST_PTR_FORMAT, desired_caps); /* we alloc a buffer with the original incomming caps already in the * width and height variables */ gst_caps_unref (desired_caps); } } alloc: gst_vdp_buffer_pool_set_caps (vdp_sink->bpool, alloc_caps); gst_caps_unref (alloc_caps); err = NULL; *buf = GST_BUFFER_CAST (gst_vdp_buffer_pool_get_buffer (vdp_sink->bpool, &err)); if (!*buf) { gst_vdp_sink_post_error (vdp_sink, err); return GST_FLOW_ERROR; } beach: return ret; }
static GstFlowReturn gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf) { gint width, height; GstStructure *structure = NULL; GstSLVideo *slvideo; slvideo = GST_SLVIDEO(bsink); // caps == requested caps // we can ignore these and reverse-negotiate our preferred dimensions with // the peer if we like - we need to do this to obey dynamic resize requests // flowing in from the app. structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int(structure, "width", &width) || !gst_structure_get_int(structure, "height", &height)) { GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps); return GST_FLOW_NOT_NEGOTIATED; } GstBuffer *newbuf = gst_buffer_new(); bool made_bufferdata_ptr = false; #define MAXDEPTHHACK 4 GST_OBJECT_LOCK(slvideo); if (slvideo->resize_forced_always) // app is giving us a fixed size to work with { gint slwantwidth, slwantheight; slwantwidth = slvideo->resize_try_width; slwantheight = slvideo->resize_try_height; if (slwantwidth != width || slwantheight != height) { // don't like requested caps, we will issue our own suggestion - copy // the requested caps but substitute our own width and height and see // if our peer is happy with that. GstCaps *desired_caps; GstStructure *desired_struct; desired_caps = gst_caps_copy (caps); desired_struct = gst_caps_get_structure (desired_caps, 0); GValue value = {0}; g_value_init(&value, G_TYPE_INT); g_value_set_int(&value, slwantwidth); gst_structure_set_value (desired_struct, "width", &value); g_value_unset(&value); g_value_init(&value, G_TYPE_INT); g_value_set_int(&value, slwantheight); gst_structure_set_value (desired_struct, "height", &value); if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo), desired_caps)) { // todo: re-use buffers from a pool? // todo: set MALLOCDATA to null, set DATA to point straight to shm? // peer likes our cap suggestion DEBUGMSG("peer loves us :)"); GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK; GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); gst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps); made_bufferdata_ptr = true; } else { // peer hates our cap suggestion INFOMSG("peer hates us :("); gst_caps_unref(desired_caps); } } } GST_OBJECT_UNLOCK(slvideo); if (!made_bufferdata_ptr) // need to fallback to malloc at original size { GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK; GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); gst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); } *buf = GST_BUFFER_CAST(newbuf); return GST_FLOW_OK; }