mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-09-09 05:38:58 +00:00
New base class for vdpau decoders * mpeg2 ported and activated * h264 ported but deactivated * Uses GstMpegVideo meta
406 lines
12 KiB
C
406 lines
12 KiB
C
/*
|
|
* GStreamer
|
|
* Copyright (C) 2009 Carl-Anton Ingmarsson <ca.ingmarsson@gmail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstvdpoutputbuffer.h"
|
|
|
|
GST_DEBUG_CATEGORY_STATIC (gst_vdp_output_buffer_debug);
|
|
#define GST_CAT_DEFAULT gst_vdp_output_buffer_debug
|
|
|
|
#define DEBUG_INIT(bla) \
|
|
GST_DEBUG_CATEGORY_INIT (gst_vdp_output_buffer_debug, "vdpoutputbuffer", 0, "VDPAU output buffer");
|
|
|
|
GstVdpOutputBuffer *
|
|
gst_vdp_output_buffer_new (GstVdpDevice * device, VdpRGBAFormat rgba_format,
|
|
gint width, gint height, GError ** error)
|
|
{
|
|
GstVdpOutputBuffer *buffer;
|
|
VdpStatus status;
|
|
VdpOutputSurface surface;
|
|
|
|
status =
|
|
device->vdp_output_surface_create (device->device, rgba_format, width,
|
|
height, &surface);
|
|
if (status != VDP_STATUS_OK)
|
|
goto create_error;
|
|
|
|
buffer =
|
|
(GstVdpOutputBuffer *) gst_mini_object_new (GST_TYPE_VDP_OUTPUT_BUFFER);
|
|
|
|
buffer->device = g_object_ref (device);
|
|
buffer->rgba_format = rgba_format;
|
|
buffer->width = width;
|
|
buffer->height = height;
|
|
|
|
buffer->surface = surface;
|
|
|
|
return buffer;
|
|
|
|
create_error:
|
|
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
|
|
"Couldn't create a VdpOutputSurface, error returned from vdpau was: %s",
|
|
device->vdp_get_error_string (status));
|
|
return NULL;
|
|
}
|
|
|
|
static GObjectClass *gst_vdp_output_buffer_parent_class;
|
|
|
|
static void
|
|
gst_vdp_output_buffer_finalize (GstVdpOutputBuffer * buffer)
|
|
{
|
|
GstVdpDevice *device;
|
|
VdpStatus status;
|
|
|
|
if (gst_vdp_buffer_revive (GST_VDP_BUFFER_CAST (buffer)))
|
|
return;
|
|
|
|
device = buffer->device;
|
|
|
|
status = device->vdp_output_surface_destroy (buffer->surface);
|
|
if (status != VDP_STATUS_OK)
|
|
GST_ERROR
|
|
("Couldn't destroy the buffers VdpOutputSurface, error returned was: %s",
|
|
device->vdp_get_error_string (status));
|
|
|
|
g_object_unref (buffer->device);
|
|
|
|
GST_MINI_OBJECT_CLASS (gst_vdp_output_buffer_parent_class)->finalize
|
|
(GST_MINI_OBJECT (buffer));
|
|
}
|
|
|
|
static void
|
|
gst_vdp_output_buffer_init (GstVdpOutputBuffer * buffer, gpointer g_class)
|
|
{
|
|
buffer->device = NULL;
|
|
buffer->surface = VDP_INVALID_HANDLE;
|
|
}
|
|
|
|
static void
|
|
gst_vdp_output_buffer_class_init (gpointer g_class, gpointer class_data)
|
|
{
|
|
GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
|
|
|
|
gst_vdp_output_buffer_parent_class = g_type_class_peek_parent (g_class);
|
|
|
|
mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
|
|
gst_vdp_output_buffer_finalize;
|
|
}
|
|
|
|
|
|
GType
|
|
gst_vdp_output_buffer_get_type (void)
|
|
{
|
|
static GType _gst_vdp_output_buffer_type;
|
|
|
|
if (G_UNLIKELY (_gst_vdp_output_buffer_type == 0)) {
|
|
static const GTypeInfo info = {
|
|
sizeof (GstBufferClass),
|
|
NULL,
|
|
NULL,
|
|
gst_vdp_output_buffer_class_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof (GstVdpOutputBuffer),
|
|
0,
|
|
(GInstanceInitFunc) gst_vdp_output_buffer_init,
|
|
NULL
|
|
};
|
|
_gst_vdp_output_buffer_type = g_type_register_static (GST_TYPE_VDP_BUFFER,
|
|
"GstVdpOutputBuffer", &info, 0);
|
|
|
|
DEBUG_INIT ();
|
|
}
|
|
return _gst_vdp_output_buffer_type;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
VdpRGBAFormat format;
|
|
GstStaticCaps caps;
|
|
} GstVdpOutputBufferFormats;
|
|
|
|
GstVdpOutputBufferFormats rgba_formats[] = {
|
|
{VDP_RGBA_FORMAT_A8,
|
|
GST_STATIC_CAPS ("video/x-raw-rgb, "
|
|
"bpp = (int)8, "
|
|
"depth = (int)8, "
|
|
"endianness = (int)4321, "
|
|
"red_mask = (int)0x00, "
|
|
"green_mask = (int)0x00, "
|
|
"blue_mask = (int)0x00, " "alpha_mask = (int)0xff")},
|
|
{VDP_RGBA_FORMAT_B10G10R10A2,
|
|
GST_STATIC_CAPS ("video/x-raw-rgb, "
|
|
"bpp = (int)32, "
|
|
"depth = (int)30, "
|
|
"endianness = (int)4321, "
|
|
"red_mask = (int)0x000003fc, "
|
|
"green_mask = (int)0x003ff000, "
|
|
"blue_mask = (int)0xffc00000, " "alpha_mask = (int)0x00000003")},
|
|
{VDP_RGBA_FORMAT_B8G8R8A8,
|
|
GST_STATIC_CAPS ("video/x-raw-rgb, "
|
|
"bpp = (int)32, "
|
|
"depth = (int)24, "
|
|
"endianness = (int)4321, "
|
|
"red_mask = (int)0x0000ff00, "
|
|
"green_mask = (int)0x00ff0000, "
|
|
"blue_mask = (int)0xff000000, " "alpha_mask = (int)0x000000ff")},
|
|
{VDP_RGBA_FORMAT_R10G10B10A2,
|
|
GST_STATIC_CAPS ("video/x-raw-rgb, "
|
|
"bpp = (int)32, "
|
|
"depth = (int)30, "
|
|
"endianness = (int)4321, "
|
|
"red_mask = (int)0xffc00000, "
|
|
"green_mask = (int)0x003ff000, "
|
|
"blue_mask = (int)0x000003fc, " "alpha_mask = (int)0x00000003")},
|
|
{VDP_RGBA_FORMAT_R8G8B8A8,
|
|
GST_STATIC_CAPS ("video/x-raw-rgb, "
|
|
"bpp = (int)32, "
|
|
"depth = (int)24, "
|
|
"endianness = (int)4321, "
|
|
"red_mask = (int)0xff000000, "
|
|
"green_mask = (int)0x00ff0000, "
|
|
"blue_mask = (int)0x0000ff00, " "alpha_mask = (int)0x000000ff")},
|
|
};
|
|
|
|
|
|
GstCaps *
|
|
gst_vdp_output_buffer_get_template_caps (void)
|
|
{
|
|
GstCaps *caps, *rgb_caps;
|
|
gint i;
|
|
|
|
caps = gst_caps_new_empty ();
|
|
rgb_caps = gst_caps_new_empty ();
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (rgba_formats); i++) {
|
|
GstCaps *format_caps;
|
|
|
|
format_caps = gst_caps_new_simple ("video/x-vdpau-output",
|
|
"rgba-format", G_TYPE_INT, rgba_formats[i].format,
|
|
"width", GST_TYPE_INT_RANGE, 1, 8192,
|
|
"height", GST_TYPE_INT_RANGE, 1, 8192, NULL);
|
|
gst_caps_append (caps, format_caps);
|
|
|
|
format_caps = gst_static_caps_get (&rgba_formats[i].caps);
|
|
format_caps = gst_caps_copy (format_caps);
|
|
gst_caps_set_simple (format_caps,
|
|
"width", GST_TYPE_INT_RANGE, 1, 8192,
|
|
"height", GST_TYPE_INT_RANGE, 1, 8192, NULL);
|
|
gst_caps_append (rgb_caps, format_caps);
|
|
|
|
}
|
|
|
|
gst_caps_append (caps, rgb_caps);
|
|
|
|
return caps;
|
|
}
|
|
|
|
GstCaps *
|
|
gst_vdp_output_buffer_get_allowed_caps (GstVdpDevice * device)
|
|
{
|
|
GstCaps *caps, *rgb_caps;
|
|
gint i;
|
|
|
|
g_return_val_if_fail (GST_IS_VDP_DEVICE (device), NULL);
|
|
|
|
caps = gst_caps_new_empty ();
|
|
rgb_caps = gst_caps_new_empty ();
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (rgba_formats); i++) {
|
|
VdpStatus status;
|
|
VdpBool is_supported;
|
|
guint max_w, max_h;
|
|
|
|
status = device->vdp_output_surface_query_capabilities (device->device,
|
|
rgba_formats[i].format, &is_supported, &max_w, &max_h);
|
|
if (status != VDP_STATUS_OK && status != VDP_STATUS_INVALID_RGBA_FORMAT) {
|
|
GST_ERROR_OBJECT (device,
|
|
"Could not get query VDPAU output surface capabilites, "
|
|
"Error returned from vdpau was: %s",
|
|
device->vdp_get_error_string (status));
|
|
|
|
goto error;
|
|
}
|
|
|
|
if (is_supported) {
|
|
GstCaps *format_caps;
|
|
|
|
format_caps = gst_caps_new_simple ("video/x-vdpau-output",
|
|
"rgba-format", G_TYPE_INT, rgba_formats[i].format,
|
|
"width", GST_TYPE_INT_RANGE, 1, max_w,
|
|
"height", GST_TYPE_INT_RANGE, 1, max_h, NULL);
|
|
gst_caps_append (caps, format_caps);
|
|
|
|
format_caps = gst_static_caps_get (&rgba_formats[i].caps);
|
|
format_caps = gst_caps_copy (format_caps);
|
|
gst_caps_set_simple (format_caps,
|
|
"width", GST_TYPE_INT_RANGE, 1, 8192,
|
|
"height", GST_TYPE_INT_RANGE, 1, 8192, NULL);
|
|
gst_caps_append (rgb_caps, format_caps);
|
|
}
|
|
}
|
|
|
|
gst_caps_append (caps, rgb_caps);
|
|
|
|
error:
|
|
|
|
return caps;
|
|
}
|
|
|
|
gboolean
|
|
gst_vdp_caps_to_rgba_format (GstCaps * caps, VdpRGBAFormat * rgba_format)
|
|
{
|
|
GstStructure *structure;
|
|
gint c_bpp, c_depth, c_endianness, c_red_mask, c_green_mask, c_blue_mask,
|
|
c_alpha_mask;
|
|
|
|
gint i;
|
|
|
|
g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
|
|
|
|
if (!gst_caps_is_fixed (caps))
|
|
return FALSE;
|
|
|
|
structure = gst_caps_get_structure (caps, 0);
|
|
if (!gst_structure_has_name (structure, "video/x-raw-rgb"))
|
|
return FALSE;
|
|
|
|
if (!gst_structure_get_int (structure, "bpp", &c_bpp) ||
|
|
!gst_structure_get_int (structure, "depth", &c_depth) ||
|
|
!gst_structure_get_int (structure, "endianness", &c_endianness) ||
|
|
!gst_structure_get_int (structure, "red_mask", &c_red_mask) ||
|
|
!gst_structure_get_int (structure, "green_mask", &c_green_mask) ||
|
|
!gst_structure_get_int (structure, "blue_mask", &c_blue_mask) ||
|
|
!gst_structure_get_int (structure, "alpha_mask", &c_alpha_mask))
|
|
return FALSE;
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (rgba_formats); i++) {
|
|
gint bpp, depth, endianness, red_mask, green_mask, blue_mask, alpha_mask;
|
|
|
|
GstCaps *rgb_caps = gst_static_caps_get (&rgba_formats[i].caps);
|
|
structure = gst_caps_get_structure (rgb_caps, 0);
|
|
|
|
gst_structure_get_int (structure, "bpp", &bpp);
|
|
gst_structure_get_int (structure, "depth", &depth);
|
|
gst_structure_get_int (structure, "endianness", &endianness);
|
|
gst_structure_get_int (structure, "red_mask", &red_mask);
|
|
gst_structure_get_int (structure, "green_mask", &green_mask);
|
|
gst_structure_get_int (structure, "blue_mask", &blue_mask);
|
|
gst_structure_get_int (structure, "alpha_mask", &alpha_mask);
|
|
|
|
if (c_bpp == bpp && c_depth == depth && c_endianness == endianness &&
|
|
c_red_mask == red_mask && c_green_mask == green_mask &&
|
|
c_blue_mask == blue_mask && c_alpha_mask == alpha_mask) {
|
|
gst_caps_unref (rgb_caps);
|
|
*rgba_format = rgba_formats[i].format;
|
|
return TRUE;
|
|
}
|
|
|
|
gst_caps_unref (rgb_caps);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
gst_vdp_output_buffer_calculate_size (GstVdpOutputBuffer * output_buf,
|
|
guint * size)
|
|
{
|
|
g_return_val_if_fail (GST_IS_VDP_OUTPUT_BUFFER (output_buf), FALSE);
|
|
|
|
switch (output_buf->rgba_format) {
|
|
case VDP_RGBA_FORMAT_A8:
|
|
{
|
|
*size = output_buf->width * output_buf->height;
|
|
break;
|
|
}
|
|
|
|
case VDP_RGBA_FORMAT_B10G10R10A2:
|
|
case VDP_RGBA_FORMAT_B8G8R8A8:
|
|
case VDP_RGBA_FORMAT_R10G10B10A2:
|
|
case VDP_RGBA_FORMAT_R8G8B8A8:
|
|
{
|
|
*size = output_buf->width * output_buf->height * 4;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_vdp_output_buffer_download (GstVdpOutputBuffer * output_buf,
|
|
GstBuffer * outbuf, GError ** error)
|
|
{
|
|
guint8 *data[1];
|
|
guint32 stride[1];
|
|
GstVdpDevice *device;
|
|
VdpOutputSurface surface;
|
|
VdpStatus status;
|
|
|
|
g_return_val_if_fail (GST_IS_VDP_OUTPUT_BUFFER (output_buf), FALSE);
|
|
|
|
switch (output_buf->rgba_format) {
|
|
case VDP_RGBA_FORMAT_A8:
|
|
{
|
|
stride[0] = output_buf->width;
|
|
break;
|
|
}
|
|
|
|
case VDP_RGBA_FORMAT_B10G10R10A2:
|
|
case VDP_RGBA_FORMAT_B8G8R8A8:
|
|
case VDP_RGBA_FORMAT_R10G10B10A2:
|
|
case VDP_RGBA_FORMAT_R8G8B8A8:
|
|
{
|
|
stride[0] = output_buf->width * 4;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
device = output_buf->device;
|
|
surface = output_buf->surface;
|
|
data[0] = GST_BUFFER_DATA (outbuf);
|
|
|
|
GST_LOG_OBJECT (output_buf, "Entering vdp_output_surface_get_bits_native");
|
|
status =
|
|
device->vdp_output_surface_get_bits_native (surface, NULL, (void *) data,
|
|
stride);
|
|
GST_LOG_OBJECT (output_buf,
|
|
"Got status %d from vdp_output_get_bits_native", status);
|
|
|
|
if (G_UNLIKELY (status != VDP_STATUS_OK)) {
|
|
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_READ,
|
|
"Couldn't get data from vdpau, error returned from vdpau was: %s",
|
|
device->vdp_get_error_string (status));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|