vdpau: create VdpDecoder in set_caps add more functions for parsing mpeg

This commit is contained in:
Carl-Anton Ingmarsson 2009-03-29 15:28:06 +02:00 committed by Jan Schmidt
parent 584b000583
commit f70ddb6605
6 changed files with 275 additions and 47 deletions

View file

@ -26,10 +26,8 @@
#include <gst/gst.h>
#include <gst/controller/gstcontroller.h>
#include <X11/Xlib.h>
#include <vdpau/vdpau_x11.h>
#include "gstvdpaudecoder.h"
#include <vdpau/vdpau_x11.h>
GST_DEBUG_CATEGORY_STATIC (gst_vdpaudecoder_debug);
#define GST_CAT_DEFAULT gst_vdpaudecoder_debug
@ -173,8 +171,9 @@ gst_vdpaudecoder_get_vdpau_support (GstVdpauDecoder * dec)
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"));
("Could not get query VDPAU video surface capabilites"),
("Error returned from vdpau was: %s",
f->vdp_get_error_string (status)));
return NULL;
}
@ -191,8 +190,9 @@ gst_vdpaudecoder_get_vdpau_support (GstVdpauDecoder * dec)
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"));
("Could not query VDPAU YCbCr capabilites"),
("Error returned from vdpau was: %s",
f->vdp_get_error_string (status)));
return NULL;
}
@ -220,15 +220,45 @@ gst_vdpaudecoder_get_vdpau_support (GstVdpauDecoder * dec)
static gboolean
gst_vdpaudecoder_init_vdpau (GstVdpauDecoder * dec)
{
Display *display;
int screen;
VdpauFunctions *f;
gint screen;
VdpStatus status;
gint i;
VdpauFunctions *f;
GstCaps *caps;
typedef struct
{
int id;
void *func;
} VdpFunction;
VdpFunction vdp_function[] = {
{VDP_FUNC_ID_DEVICE_DESTROY, &dec->functions->vdp_device_destroy},
{VDP_FUNC_ID_VIDEO_SURFACE_CREATE,
&dec->functions->vdp_video_surface_create},
{VDP_FUNC_ID_VIDEO_SURFACE_DESTROY,
&dec->functions->vdp_video_surface_destroy},
{VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES,
&dec->functions->vdp_video_surface_query_capabilities},
{VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES,
&dec->functions->vdp_video_surface_query_ycbcr_capabilities},
{VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR,
&dec->functions->vdp_video_surface_get_bits_ycbcr},
{VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS,
&dec->functions->vdp_video_surface_get_parameters},
{VDP_FUNC_ID_DECODER_CREATE, &dec->functions->vdp_decoder_create},
{VDP_FUNC_ID_DECODER_RENDER, &dec->functions->vdp_decoder_render},
{VDP_FUNC_ID_DECODER_DESTROY, &dec->functions->vdp_decoder_destroy},
{VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES,
&dec->functions->vdp_decoder_query_capabilities},
{VDP_FUNC_ID_DECODER_GET_PARAMETERS,
&dec->functions->vdp_decoder_get_parameters},
{0, NULL}
};
/* FIXME: We probably want to use the same VdpDevice for every VDPAU element */
display = XOpenDisplay (dec->display);
if (!display) {
dec->display = XOpenDisplay (dec->display_name);
if (!dec->display) {
GST_ELEMENT_ERROR (dec, RESOURCE, READ, ("Could not initialise VDPAU"),
("Could not open display"));
return FALSE;
@ -236,55 +266,78 @@ gst_vdpaudecoder_init_vdpau (GstVdpauDecoder * dec)
f = dec->functions;
screen = DefaultScreen (display);
screen = DefaultScreen (dec->display);
status =
vdp_device_create_x11 (display, screen, &dec->device,
vdp_device_create_x11 (dec->display, screen, &dec->device,
&f->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);
XCloseDisplay (dec->display);
dec->display = NULL;
return FALSE;
}
XCloseDisplay (display);
f->vdp_get_proc_address (dec->device,
VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES,
(void **) &f->vdp_video_surface_query_capabilities);
f->vdp_get_proc_address (dec->device,
VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES,
(void **) &f->vdp_video_surface_query_ycbcr_capabilities);
f->vdp_get_proc_address (dec->device,
VDP_FUNC_ID_DEVICE_DESTROY, (void **) &f->vdp_device_destroy);
f->vdp_get_proc_address (dec->device,
VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR,
(void **) &f->vdp_video_surface_get_bits_ycbcr);
status = f->vdp_get_proc_address (dec->device,
VDP_FUNC_ID_GET_ERROR_STRING, (void **) &f->vdp_get_error_string);
if (status != VDP_STATUS_OK) {
GST_ELEMENT_ERROR (dec, RESOURCE, READ,
("Could'nt get function pointer from vdpau"),
("Couldn't get vdp_get_error_string function pointer"));
goto error;
}
for (i = 0; vdp_function[i].func != NULL; i++) {
status = f->vdp_get_proc_address (dec->device,
vdp_function[i].id, vdp_function[i].func);
if (status != VDP_STATUS_OK) {
GST_ELEMENT_ERROR (dec, RESOURCE, READ,
("Could not get function pointer from vdpau"),
("Error returned from vdpau was: %s",
f->vdp_get_error_string (status)));
goto error;
}
}
caps = gst_vdpaudecoder_get_vdpau_support (dec);
if (!caps) {
f->vdp_device_destroy (dec->device);
dec->device = 0;
return FALSE;
}
if (!caps)
goto error;
dec->src_caps = caps;
return TRUE;
error:
f->vdp_device_destroy (dec->device);
dec->device = VDP_INVALID_HANDLE;
return FALSE;
}
static GstStateChangeReturn
gst_vdpaudecoder_change_state (GstElement * element, GstStateChange transition)
{
GstVdpauDecoder *dec;
VdpauFunctions *f;
dec = GST_VDPAU_DECODER (element);
f = dec->functions;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!gst_vdpaudecoder_init_vdpau (dec))
return GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
f->vdp_device_destroy (dec->device);
XCloseDisplay (dec->display);
dec->device = VDP_INVALID_HANDLE;
dec->display = NULL;
break;
default:
break;
}
@ -403,8 +456,9 @@ gst_vdpaudecoder_class_init (GstVdpauDecoderClass * klass)
static void
gst_vdpaudecoder_init (GstVdpauDecoder * dec, GstVdpauDecoderClass * klass)
{
dec->display_name = NULL;
dec->display = NULL;
dec->device = 0;
dec->device = VDP_INVALID_HANDLE;
dec->silent = FALSE;
dec->src_caps = NULL;
@ -433,8 +487,8 @@ gst_vdpaudecoder_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_DISPLAY:
g_free (dec->display);
dec->display = g_value_dup_string (value);
g_free (dec->display_name);
dec->display_name = g_value_dup_string (value);
break;
case PROP_SILENT:
dec->silent = g_value_get_boolean (value);
@ -453,7 +507,7 @@ gst_vdpaudecoder_get_property (GObject * object, guint prop_id,
switch (prop_id) {
case PROP_DISPLAY:
g_value_set_string (value, dec->display);
g_value_set_string (value, dec->display_name);
break;
case PROP_SILENT:
g_value_set_boolean (value, dec->silent);

View file

@ -25,6 +25,7 @@
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <X11/Xlib.h>
#include <vdpau/vdpau.h>
G_BEGIN_DECLS
@ -43,7 +44,8 @@ typedef struct _VdpauFunctions VdpauFunctions;
struct _GstVdpauDecoder {
GstElement element;
gchar *display;
gchar *display_name;
Display *display;
VdpDevice device;
VdpauFunctions *functions;
@ -66,17 +68,22 @@ struct _GstVdpauDecoderClass {
};
struct _VdpauFunctions {
VdpDeviceDestroy *vdp_device_destroy;
VdpGetProcAddress *vdp_get_proc_address;
VdpGetErrorString *vdp_get_error_string;
VdpVideoSurfaceCreate *vdp_video_surface_create;
VdpVideoSurfaceDestroy *vdp_video_surface_destroy;
VdpVideoSurfaceQueryCapabilities *vdp_video_surface_query_capabilities;
VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *vdp_video_surface_query_ycbcr_capabilities;
VdpVideoSurfaceGetParameters *vdp_video_surface_get_parameters;
VdpVideoSurfaceGetBitsYCbCr *vdp_video_surface_get_bits_ycbcr;
VdpDeviceDestroy *vdp_device_destroy;
VdpDecoderCreate *vdp_decoder_create;
VdpDecoderDestroy *vdp_decoder_destroy;
VdpDecoderRender *vdp_decoder_render;
VdpDecoderQueryCapabilities *vdp_decoder_query_capabilities;
VdpDecoderGetParameters *vdp_decoder_get_parameters;
};
GType gst_vdpaudecoder_get_type (void);

View file

@ -104,13 +104,16 @@ gst_vdpau_mpeg_decoder_set_caps (GstVdpauDecoder * dec, GstCaps * caps)
GstVdpauMpegDecoder *mpeg_dec;
GstStructure *structure;
gint version;
VdpDecoderProfile profile;
VdpauFunctions *f;
VdpStatus status;
mpeg_dec = GST_VDPAU_MPEG_DECODER (dec);
structure = gst_caps_get_structure (caps, 0);
gst_structure_get_int (structure, "mpegversion", &version);
if (version == 1)
mpeg_dec->profile = VDP_DECODER_PROFILE_MPEG1;
profile = VDP_DECODER_PROFILE_MPEG1;
else {
const GValue *value;
@ -123,14 +126,24 @@ gst_vdpau_mpeg_decoder_set_caps (GstVdpauDecoder * dec, GstCaps * caps)
GST_BUFFER_DATA (codec_data) + GST_BUFFER_SIZE (codec_data));
switch (hdr.profile) {
case 5:
mpeg_dec->profile = VDP_DECODER_PROFILE_MPEG2_SIMPLE;
profile = VDP_DECODER_PROFILE_MPEG2_SIMPLE;
break;
default:
mpeg_dec->profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
break;
}
}
f = dec->functions;
status = f->vdp_decoder_create (dec->device, profile, dec->width,
dec->height, 2, &mpeg_dec->decoder);
if (status != VDP_STATUS_OK) {
GST_ELEMENT_ERROR (mpeg_dec, RESOURCE, READ,
("Could not create vdpau decoder"),
("Error returned from vdpau was: %s",
f->vdp_get_error_string (status)));
return FALSE;
}
return TRUE;
}
@ -174,10 +187,12 @@ gst_vdpau_mpeg_decoder_class_init (GstVdpauMpegDecoderClass * klass)
}
static void
gst_vdpau_mpeg_decoder_init (GstVdpauMpegDecoder * filter,
gst_vdpau_mpeg_decoder_init (GstVdpauMpegDecoder * mpeg_dec,
GstVdpauMpegDecoderClass * gclass)
{
filter->silent = FALSE;
mpeg_dec->silent = FALSE;
mpeg_dec->decoder = VDP_INVALID_HANDLE;
}
static void

View file

@ -66,7 +66,7 @@ struct _GstVdpauMpegDecoder
gboolean silent;
VdpDecoderProfile profile;
VdpDecoder decoder;
};
struct _GstVdpauMpegDecoderClass

View file

@ -18,8 +18,41 @@
* Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include "mpegutil.h"
/* default intra quant matrix, in zig-zag order */
static const guint8 default_intra_quantizer_matrix[64] = {
8,
16, 16,
19, 16, 19,
22, 22, 22, 22,
22, 22, 26, 24, 26,
27, 27, 27, 26, 26, 26,
26, 27, 27, 27, 29, 29, 29,
34, 34, 34, 29, 29, 29, 27, 27,
29, 29, 32, 32, 34, 34, 37,
38, 37, 35, 35, 34, 35,
38, 38, 40, 40, 40,
48, 48, 46, 46,
56, 56, 58,
69, 69,
83
};
guint8 mpeg2_scan[64] = {
/* Zig-Zag scan pattern */
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
guint8 bits[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
guint32
@ -133,6 +166,7 @@ mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end)
/* Parse a Sequence Extension */
guint8 horiz_size_ext, vert_size_ext;
guint8 fps_n_ext, fps_d_ext;
gint i, offset;
if (G_UNLIKELY ((end - data) < 6))
/* need at least 10 bytes, minus 4 for the start code 000001b5 */
@ -148,6 +182,23 @@ mpeg_util_parse_extension_packet (MPEGSeqHdr * hdr, guint8 * data, guint8 * end)
hdr->fps_d *= (fps_d_ext + 1);
hdr->width += (horiz_size_ext << 12);
hdr->height += (vert_size_ext << 12);
if (read_bits (data + 7, 6, 1)) {
for (i = 0; i < 64; i++)
hdr->intra_quantizer_matrix[mpeg2_scan[i]] =
read_bits (data + 7 + i, 7, 8);
offset = 64;
} else
memcpy (hdr->intra_quantizer_matrix, default_intra_quantizer_matrix,
64);
if (read_bits (data + 7 + offset, 7, 1)) {
for (i = 0; i < 64; i++)
hdr->non_intra_quantizer_matrix[mpeg2_scan[i]] =
read_bits (data + 8 + offset + i, 0, 8);
} else
memset (hdr->non_intra_quantizer_matrix, 0, 64);
break;
}
default:
@ -225,3 +276,67 @@ mpeg_util_parse_sequence_hdr (MPEGSeqHdr * hdr, guint8 * data, guint8 * end)
return TRUE;
}
gboolean
mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end)
{
guint32 code;
if (G_UNLIKELY ((end - data) < 6))
return FALSE; /* Packet too small */
code = GST_READ_UINT32_BE (data);
if (G_UNLIKELY (code != (0x00000100 | MPEG_PACKET_PICTURE)))
return FALSE;
/* Skip the start code */
data += 4;
hdr->pic_type = (data[1] >> 3) & 0x07;
if (hdr->pic_type == 0 || hdr->pic_type > 4)
return FALSE; /* Corrupted picture packet */
if (hdr->pic_type == P_FRAME || hdr->pic_type == B_FRAME) {
if (G_UNLIKELY ((end - data) < 7))
return FALSE; /* packet too small */
hdr->full_pel_forward_vector = read_bits (data + 3, 5, 1);
hdr->f_code[0][0] = hdr->f_code[0][1] = read_bits (data + 3, 6, 3);
if (hdr->pic_type == B_FRAME) {
hdr->full_pel_backward_vector = read_bits (data + 4, 1, 1);
hdr->f_code[1][0] = hdr->f_code[1][1] = read_bits (data + 4, 2, 3);
}
} else {
hdr->full_pel_forward_vector = 0;
hdr->full_pel_backward_vector = 0;
}
return TRUE;
}
gboolean
mpeg_util_parse_picture_coding_extension (MPEGPictureExt * ext, guint8 * data,
guint8 * end)
{
if (G_UNLIKELY ((end - data) < 7))
return FALSE; /* Packet too small */
if (G_UNLIKELY (read_bits (data, 0, 4) != MPEG_PACKET_EXT_PICTURE_CODING))
return FALSE;
ext->f_code[0][0] = read_bits (data, 4, 4);
ext->f_code[0][1] = read_bits (data + 1, 0, 4);
ext->f_code[1][0] = read_bits (data + 1, 4, 4);
ext->f_code[1][1] = read_bits (data + 2, 0, 4);
ext->intra_dc_precision = read_bits (data + 2, 4, 2);
ext->picture_structure = read_bits (data + 2, 6, 2);
ext->top_field_first = read_bits (data + 3, 0, 1);
ext->frame_pred_frame_dct = read_bits (data + 3, 1, 1);
ext->concealment_motion_vectors = read_bits (data + 3, 2, 1);
ext->q_scale_type = read_bits (data + 3, 3, 1);
ext->intra_vlc_format = read_bits (data + 3, 4, 1);
return TRUE;
}

View file

@ -24,6 +24,8 @@
#include <gst/gst.h>
typedef struct MPEGSeqHdr MPEGSeqHdr;
typedef struct MPEGPictureHdr MPEGPictureHdr;
typedef struct MPEGPictureExt MPEGPictureExt;
/* Packet ID codes for different packet types we
* care about */
@ -40,6 +42,12 @@ typedef struct MPEGSeqHdr MPEGSeqHdr;
#define MPEG_PACKET_EXT_SEQUENCE 0x01
#define MPEG_PACKET_EXT_SEQUENCE_DISPLAY 0x02
#define MPEG_PACKET_EXT_QUANT_MATRIX 0x03
#define MPEG_PACKET_EXT_PICTURE_CODING 0x08
/* frame types */
#define I_FRAME 1
#define P_FRAME 2
#define B_FRAME 3
struct MPEGSeqHdr
{
@ -55,9 +63,38 @@ struct MPEGSeqHdr
/* mpeg2 decoder profile */
gint profile;
guint8 intra_quantizer_matrix[64];
guint8 non_intra_quantizer_matrix[64];
};
struct MPEGPictureHdr
{
guint8 pic_type;
guint8 full_pel_forward_vector, full_pel_backward_vector;
guint8 f_code[2][2];
};
struct MPEGPictureExt
{
guint8 f_code[2][2];
guint8 intra_dc_precision;
guint8 picture_structure;
guint8 top_field_first;
guint8 frame_pred_frame_dct;
guint8 concealment_motion_vectors;
guint8 q_scale_type;
guint8 intra_vlc_format;
};
gboolean mpeg_util_parse_sequence_hdr (MPEGSeqHdr *hdr,
guint8 *data, guint8 *end);
gboolean mpeg_util_parse_picture_hdr (MPEGPictureHdr * hdr, guint8 * data, guint8 * end);
gboolean mpeg_util_parse_picture_coding_extension (MPEGPictureExt *ext, guint8 *data, guint8 *end);
#endif