static gboolean gst_vdp_output_src_pad_setcaps (GstPad * pad, GstCaps * caps) { GstVdpOutputSrcPad *vdp_pad = GST_VDP_OUTPUT_SRC_PAD (pad); const GstStructure *structure; structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "width", &vdp_pad->width)) return FALSE; if (!gst_structure_get_int (structure, "height", &vdp_pad->height)) return FALSE; if (gst_structure_has_name (structure, "video/x-raw-rgb")) { if (!gst_vdp_caps_to_rgba_format (caps, &vdp_pad->rgba_format)) return FALSE; /* create buffer pool if we dont't have one */ if (!vdp_pad->bpool) vdp_pad->bpool = gst_vdp_output_buffer_pool_new (vdp_pad->device); if (vdp_pad->output_caps) gst_caps_unref (vdp_pad->output_caps); vdp_pad->output_caps = gst_caps_new_simple ("video/x-vdpau-output", "rgba-format", G_TYPE_INT, vdp_pad->rgba_format, "width", G_TYPE_INT, vdp_pad->width, "height", G_TYPE_INT, vdp_pad->height, NULL); gst_vdp_buffer_pool_set_caps (vdp_pad->bpool, vdp_pad->output_caps); vdp_pad->output_format = GST_VDP_OUTPUT_SRC_PAD_FORMAT_RGB; } else if (gst_structure_has_name (structure, "video/x-vdpau-output")) { if (!gst_structure_get_int (structure, "rgba-format", (gint *) & vdp_pad->rgba_format)) return FALSE; /* don't need the buffer pool */ if (vdp_pad->bpool) { gst_object_unref (vdp_pad->bpool); vdp_pad->bpool = NULL; } vdp_pad->output_format = GST_VDP_OUTPUT_SRC_PAD_FORMAT_VDPAU; } else return FALSE; return TRUE; }
/* 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 gboolean gst_vdp_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) { VdpSink *vdp_sink; GstCaps *allowed_caps; gboolean ret = TRUE; GstStructure *structure; GstCaps *intersection; gint new_width, new_height; const GValue *fps; vdp_sink = GST_VDP_SINK (bsink); GST_OBJECT_LOCK (vdp_sink); if (!vdp_sink->device) return FALSE; GST_OBJECT_UNLOCK (vdp_sink); allowed_caps = gst_pad_get_caps (GST_BASE_SINK_PAD (bsink)); GST_DEBUG_OBJECT (vdp_sink, "sinkconnect possible caps %" GST_PTR_FORMAT " with given caps %" GST_PTR_FORMAT, allowed_caps, caps); /* We intersect those caps with our template to make sure they are correct */ intersection = gst_caps_intersect (allowed_caps, caps); gst_caps_unref (allowed_caps); GST_DEBUG_OBJECT (vdp_sink, "intersection returned %" GST_PTR_FORMAT, intersection); if (gst_caps_is_empty (intersection)) { gst_caps_unref (intersection); return FALSE; } gst_caps_unref (intersection); structure = gst_caps_get_structure (caps, 0); ret &= gst_structure_get_int (structure, "width", &new_width); ret &= gst_structure_get_int (structure, "height", &new_height); fps = gst_structure_get_value (structure, "framerate"); ret &= (fps != NULL); if (!ret) return FALSE; GST_VIDEO_SINK_WIDTH (vdp_sink) = new_width; GST_VIDEO_SINK_HEIGHT (vdp_sink) = new_height; vdp_sink->fps_n = gst_value_get_fraction_numerator (fps); vdp_sink->fps_d = gst_value_get_fraction_denominator (fps); gst_vdp_buffer_pool_set_caps (vdp_sink->bpool, caps); /* Notify application to set xwindow id now */ g_mutex_lock (vdp_sink->flow_lock); if (!vdp_sink->window) { g_mutex_unlock (vdp_sink->flow_lock); gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (vdp_sink)); } else { g_mutex_unlock (vdp_sink->flow_lock); } /* Creating our window and our image */ if (GST_VIDEO_SINK_WIDTH (vdp_sink) <= 0 || GST_VIDEO_SINK_HEIGHT (vdp_sink) <= 0) { GST_ELEMENT_ERROR (vdp_sink, CORE, NEGOTIATION, (NULL), ("Invalid image size.")); return FALSE; } g_mutex_lock (vdp_sink->flow_lock); if (!vdp_sink->window) { vdp_sink->window = gst_vdp_sink_window_new (vdp_sink, GST_VIDEO_SINK_WIDTH (vdp_sink), GST_VIDEO_SINK_HEIGHT (vdp_sink)); } g_mutex_unlock (vdp_sink->flow_lock); return TRUE; }
static gboolean gst_vdp_vpp_sink_setcaps (GstPad * pad, GstCaps * caps) { GstVdpVideoPostProcess *vpp = GST_VDP_VIDEO_POST_PROCESS (gst_pad_get_parent (pad)); GstStructure *structure; GstCaps *video_caps = NULL; gboolean res = FALSE; GstCaps *allowed_caps, *output_caps, *src_caps; /* check if the input is non native */ structure = gst_caps_get_structure (caps, 0); if (gst_structure_has_name (structure, "video/x-raw-yuv")) { if (!gst_structure_get_fourcc (structure, "format", &vpp->fourcc)) goto done; vpp->native_input = FALSE; video_caps = gst_vdp_yuv_to_video_caps (caps); if (!video_caps) goto done; if (!vpp->vpool) vpp->vpool = gst_vdp_video_buffer_pool_new (vpp->device); gst_vdp_buffer_pool_set_caps (vpp->vpool, video_caps); } else { vpp->native_input = TRUE; video_caps = gst_caps_ref (caps); if (vpp->vpool) { g_object_unref (vpp->vpool); vpp->vpool = NULL; } } structure = gst_caps_get_structure (video_caps, 0); if (!gst_structure_get_int (structure, "width", &vpp->width) || !gst_structure_get_int (structure, "height", &vpp->height) || !gst_structure_get_int (structure, "chroma-type", (gint *) & vpp->chroma_type)) goto done; /* get interlaced flag */ gst_structure_get_boolean (structure, "interlaced", &vpp->interlaced); /* extract par */ if (gst_structure_has_field_typed (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION)) { gst_structure_get_fraction (structure, "pixel-aspect-ratio", &vpp->par_n, &vpp->par_d); vpp->got_par = TRUE; } else vpp->got_par = FALSE; allowed_caps = gst_pad_get_allowed_caps (vpp->srcpad); if (G_UNLIKELY (!allowed_caps)) goto null_allowed_caps; if (G_UNLIKELY (gst_caps_is_empty (allowed_caps))) goto empty_allowed_caps; GST_DEBUG ("allowed_caps: %" GST_PTR_FORMAT, allowed_caps); output_caps = gst_vdp_video_to_output_caps (video_caps); src_caps = gst_caps_intersect (output_caps, allowed_caps); gst_caps_unref (allowed_caps); gst_caps_unref (output_caps); if (gst_caps_is_empty (src_caps)) goto not_negotiated; gst_pad_fixate_caps (vpp->srcpad, src_caps); if (gst_vdp_vpp_is_interlaced (vpp)) { gint fps_n, fps_d; if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) { gst_fraction_double (&fps_n, &fps_d); gst_caps_set_simple (src_caps, "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL); vpp->field_duration = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n); } gst_caps_set_simple (src_caps, "interlaced", G_TYPE_BOOLEAN, FALSE, NULL); } GST_DEBUG ("src_caps: %" GST_PTR_FORMAT, src_caps); res = gst_pad_set_caps (vpp->srcpad, src_caps); gst_caps_unref (src_caps); done: gst_object_unref (vpp); if (video_caps) gst_caps_unref (video_caps); return res; null_allowed_caps: GST_ERROR_OBJECT (vpp, "Got null from gst_pad_get_allowed_caps"); goto done; empty_allowed_caps: GST_ERROR_OBJECT (vpp, "Got EMPTY caps from gst_pad_get_allowed_caps"); gst_caps_unref (allowed_caps); goto done; not_negotiated: gst_caps_unref (src_caps); GST_ERROR_OBJECT (vpp, "Couldn't find suitable output format"); goto done; }