From f2eea7d0ed8004d4630739b04daf27075d6834e5 Mon Sep 17 00:00:00 2001 From: Carl-Anton Ingmarsson Date: Fri, 20 Mar 2009 21:24:40 +0100 Subject: vdpau: implement downstream caps negotiation --- sys/vdpau/gstvdpaudecoder.c | 283 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 219 insertions(+), 64 deletions(-) (limited to 'sys/vdpau/gstvdpaudecoder.c') diff --git a/sys/vdpau/gstvdpaudecoder.c b/sys/vdpau/gstvdpaudecoder.c index fe4e8796..230fa80c 100644 --- a/sys/vdpau/gstvdpaudecoder.c +++ b/sys/vdpau/gstvdpaudecoder.c @@ -28,6 +28,8 @@ #include #include + +#include "vdpauvariables.h" #include "gstvdpaudecoder.h" GST_DEBUG_CATEGORY_STATIC (gst_vdpaudecoder_debug); @@ -61,7 +63,7 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", #define DEBUG_INIT(bla) \ GST_DEBUG_CATEGORY_INIT (gst_vdpaudecoder_debug, "vdpaudecoder", 0, "vdpaudecoder base class"); -GST_BOILERPLATE_FULL (GstVDPAUDecoder, gst_vdpaudecoder, GstElement, +GST_BOILERPLATE_FULL (GstVdpauDecoder, gst_vdpaudecoder, GstElement, GST_TYPE_ELEMENT, DEBUG_INIT); static void gst_vdpaudecoder_set_property (GObject * object, guint prop_id, @@ -69,8 +71,213 @@ static void gst_vdpaudecoder_set_property (GObject * object, guint prop_id, static void gst_vdpaudecoder_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstStateChangeReturn gst_vdpaudecoder_change_state (GstElement * element, - GstStateChange transition); +typedef struct +{ + VdpChromaType chroma_type; + VdpYCbCrFormat format; + guint32 fourcc; +} VdpauFormats; + +static VdpChromaType chroma_types[3] = + { VDP_CHROMA_TYPE_420, VDP_CHROMA_TYPE_422, VDP_CHROMA_TYPE_444 }; +static VdpauFormats formats[6] = { + { + VDP_CHROMA_TYPE_420, + VDP_YCBCR_FORMAT_NV12, + GST_MAKE_FOURCC ('N', 'V', '1', '2') + }, + { + VDP_CHROMA_TYPE_422, + VDP_YCBCR_FORMAT_UYVY, + GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y') + }, + { + VDP_CHROMA_TYPE_444, + VDP_YCBCR_FORMAT_V8U8Y8A8, + GST_MAKE_FOURCC ('A', 'Y', 'U', 'V') + }, + { + VDP_CHROMA_TYPE_444, + VDP_YCBCR_FORMAT_Y8U8V8A8, + GST_MAKE_FOURCC ('A', 'V', 'U', 'Y') + }, + { + VDP_CHROMA_TYPE_422, + VDP_YCBCR_FORMAT_YUYV, + GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V') + }, + { + VDP_CHROMA_TYPE_420, + VDP_YCBCR_FORMAT_YV12, + GST_MAKE_FOURCC ('Y', 'V', '1', '2') + } +}; + +static GstCaps * +gst_vdpaudecoder_get_vdpau_support (GstVdpauDecoder * dec) +{ + GstCaps *caps; + gint i; + + caps = gst_caps_new_empty (); + + for (i = 0; i < 3; i++) { + VdpStatus status; + VdpBool is_supported; + guint32 max_w, max_h; + + status = vdp_video_surface_query_capabilities (dec->device, chroma_types[i], + &is_supported, &max_w, &max_h); + + if (status != VDP_STATUS_OK && status != VDP_STATUS_INVALID_CHROMA_TYPE) { + GST_ELEMENT_ERROR (dec, RESOURCE, READ, + ("Could not get VDPAU capabilites"), + ("Could not query video surface capabilities")); + + return NULL; + } + if (is_supported) { + gint j; + + for (j = 0; j < 6; j++) { + if (formats[j].chroma_type != chroma_types[i]) + continue; + + status = + vdp_video_surface_query_ycbcr_capabilities (dec->device, + formats[j].chroma_type, formats[j].format, &is_supported); + if (status != VDP_STATUS_OK + && status != VDP_STATUS_INVALID_Y_CB_CR_FORMAT) { + GST_ELEMENT_ERROR (dec, RESOURCE, READ, + ("Could not get VDPAU capabilites"), + ("Could not query video surface ycbcr capabilities")); + + return NULL; + } + if (is_supported) { + GstCaps *format_caps; + + format_caps = gst_caps_new_simple ("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, formats[j].fourcc, + "width", GST_TYPE_INT_RANGE, 1, max_w, + "height", GST_TYPE_INT_RANGE, 1, max_h, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + gst_caps_append (caps, format_caps); + GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT "\n", + GST_FOURCC_ARGS (formats[j].fourcc)); + } + } + } + } + if (gst_caps_is_empty (caps)) { + gst_caps_unref (caps); + return NULL; + } + + return caps; +} + +static gboolean +gst_vdpaudecoder_init_vdpau (GstVdpauDecoder * dec) +{ + Display *display; + int screen; + VdpStatus status; + GstCaps *caps; + + /* FIXME: We probably want to use the same VdpDevice for every VDPAU element */ + display = XOpenDisplay (dec->display); + if (!display) { + GST_ELEMENT_ERROR (dec, RESOURCE, READ, ("Could not initialise VDPAU"), + ("Could not open display")); + return GST_STATE_CHANGE_FAILURE; + } + + screen = DefaultScreen (display); + status = + vdp_device_create_x11 (display, screen, &dec->device, + &vdp_get_proc_address); + if (status != VDP_STATUS_OK) { + GST_ELEMENT_ERROR (dec, RESOURCE, READ, ("Could not initialise VDPAU"), + ("Could not create VDPAU device")); + XCloseDisplay (display); + + return FALSE; + } + XCloseDisplay (display); + + vdp_get_proc_address (dec->device, + VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES, + (void **) &vdp_video_surface_query_capabilities); + vdp_get_proc_address (dec->device, + VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES, + (void **) &vdp_video_surface_query_ycbcr_capabilities); + + caps = gst_vdpaudecoder_get_vdpau_support (dec); + if (!caps) + return FALSE; + + dec->src_caps = caps; + + return TRUE; +} + +static gboolean +gst_vdpaudecoder_sink_set_caps (GstPad * pad, GstCaps * caps) +{ + GstVdpauDecoder *dec = GST_VDPAU_DECODER (GST_OBJECT_PARENT (pad)); + + GstCaps *src_caps, *new_caps; + GstStructure *structure; + gint width, height; + gint framerate_numerator, framerate_denominator; + gboolean res; + + structure = gst_caps_get_structure (caps, 0); + gst_structure_get_int (structure, "width", &width); + gst_structure_get_int (structure, "height", &height); + gst_structure_get_fraction (structure, "framerate", + &framerate_numerator, &framerate_denominator); + + src_caps = gst_pad_get_allowed_caps (dec->src); + GST_DEBUG ("caps: %s\n\n", gst_caps_to_string (src_caps)); + + structure = gst_caps_get_structure (src_caps, 0); + gst_structure_set (structure, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + "framerate", GST_TYPE_FRACTION, framerate_numerator, + framerate_denominator, NULL); + + new_caps = gst_caps_copy_nth (src_caps, 0); + gst_caps_unref (src_caps); + gst_pad_fixate_caps (dec->src, new_caps); + res = gst_pad_set_caps (dec->src, new_caps); + + gst_caps_unref (new_caps); + GST_DEBUG ("caps: %s\n\n", gst_caps_to_string (gst_pad_get_caps (dec->src))); + + if (!res) + return FALSE; + + return TRUE; +} + +static GstCaps * +gst_vdpaudecoder_src_getcaps (GstPad * pad) +{ + GstVdpauDecoder *dec; + + dec = GST_VDPAU_DECODER (GST_OBJECT_PARENT (pad)); + + if (GST_PAD_CAPS (dec->src)) + return gst_caps_ref (GST_PAD_CAPS (dec->src)); + + if (dec->src_caps) + return gst_caps_ref (dec->src_caps); + + return gst_caps_copy (gst_pad_get_pad_template_caps (dec->src)); +} /* GObject vmethod implementations */ @@ -80,7 +287,7 @@ gst_vdpaudecoder_base_init (gpointer klass) GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_set_details_simple (element_class, - "VDPAUDecoder", + "VdpauDecoder", "Generic/Filter", "VDPAU decoder base class", "Carl-Anton Ingmarsson "); @@ -91,7 +298,7 @@ gst_vdpaudecoder_base_init (gpointer klass) /* initialize the vdpaudecoder's class */ static void -gst_vdpaudecoder_class_init (GstVDPAUDecoderClass * klass) +gst_vdpaudecoder_class_init (GstVdpauDecoderClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; @@ -109,73 +316,33 @@ gst_vdpaudecoder_class_init (GstVDPAUDecoderClass * klass) g_object_class_install_property (gobject_class, PROP_SILENT, g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?", FALSE, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_vdpaudecoder_change_state); } static void -gst_vdpaudecoder_init (GstVDPAUDecoder * dec, GstVDPAUDecoderClass * klass) +gst_vdpaudecoder_init (GstVdpauDecoder * dec, GstVdpauDecoderClass * klass) { dec->display = NULL; dec->device = 0; dec->silent = FALSE; + dec->src_caps = NULL; dec->src = gst_pad_new_from_static_template (&src_template, "src"); + gst_pad_set_getcaps_function (dec->src, gst_vdpaudecoder_src_getcaps); gst_element_add_pad (GST_ELEMENT (dec), dec->src); dec->sink = gst_pad_new_from_template (gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink"), "sink"); + gst_pad_set_setcaps_function (dec->sink, gst_vdpaudecoder_sink_set_caps); gst_element_add_pad (GST_ELEMENT (dec), dec->sink); -} -static GstStateChangeReturn -gst_vdpaudecoder_change_state (GstElement * element, GstStateChange transition) -{ - GstVDPAUDecoder *dec; - - dec = GST_VDPAUDECODER (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - { - Display *display; - int screen; - VdpStatus status; - - /* FIXME: We probably want to use the same VdpDevice for every VDPAU element */ - display = XOpenDisplay (dec->display); - if (!display) { - GST_ELEMENT_ERROR (dec, RESOURCE, WRITE, ("Could not initialise VDPAU"), - ("Could not open display")); - return GST_STATE_CHANGE_FAILURE; - } - - screen = DefaultScreen (display); - status = vdp_device_create_x11 (display, screen, &dec->device, NULL); - if (status != VDP_STATUS_OK) { - GST_ELEMENT_ERROR (dec, RESOURCE, WRITE, ("Could not initialise VDPAU"), - ("Could not create VDPAU device")); - XCloseDisplay (display); - - return GST_STATE_CHANGE_FAILURE; - } - XCloseDisplay (display); - break; - } - - default: - break; - } - - return GST_STATE_CHANGE_SUCCESS; + gst_vdpaudecoder_init_vdpau (dec); } static void gst_vdpaudecoder_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstVDPAUDecoder *dec = GST_VDPAUDECODER (object); + GstVdpauDecoder *dec = GST_VDPAU_DECODER (object); switch (prop_id) { case PROP_DISPLAY: @@ -195,7 +362,7 @@ static void gst_vdpaudecoder_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstVDPAUDecoder *dec = GST_VDPAUDECODER (object); + GstVdpauDecoder *dec = GST_VDPAU_DECODER (object); switch (prop_id) { case PROP_DISPLAY: @@ -209,15 +376,3 @@ gst_vdpaudecoder_get_property (GObject * object, guint prop_id, break; } } - -static gboolean -plugin_init (GstPlugin * plugin) -{ - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "vdpau", - "vdpau elements", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) -- cgit v1.2.1