summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libvdpau/Makefile.am7
-rw-r--r--src/libvdpau/vdpau_vc1.c618
-rw-r--r--src/xine-engine/video_out.h1
3 files changed, 625 insertions, 1 deletions
diff --git a/src/libvdpau/Makefile.am b/src/libvdpau/Makefile.am
index dc7ace0a7..140168483 100644
--- a/src/libvdpau/Makefile.am
+++ b/src/libvdpau/Makefile.am
@@ -8,9 +8,11 @@ vdpau_h264_module = xineplug_decode_vdpau_h264.la
VDPAU_CFLAGS = -D_ISOC99_SOURCE
vdpau_mpeg12_module = xineplug_decode_vdpau_mpeg12.la
+
+vdpau_vc1_module = xineplug_decode_vdpau_vc1.la
endif
-xineplug_LTLIBRARIES = $(vdpau_h264_module) $(vdpau_mpeg12_module)
+xineplug_LTLIBRARIES = $(vdpau_h264_module) $(vdpau_mpeg12_module) $(vdpau_vc1_module)
xineplug_decode_vdpau_h264_la_SOURCES = nal.c dpb.c h264_parser.c vdpau_h264.c
xineplug_decode_vdpau_h264_la_CFLAGS = $(AM_CFLAGS) $(VDPAU_CFLAGS)
@@ -20,3 +22,6 @@ xineplug_decode_vdpau_mpeg12_la_SOURCES = vdpau_mpeg12.c
xineplug_decode_vdpau_mpeg12_la_CFLAGS = $(AM_CFLAGS)
xineplug_decode_vdpau_mpeg12_la_LIBADD = $(XINE_LIB) $(DYNAMIC_LD_LIBS)
+xineplug_decode_vdpau_vc1_la_SOURCES = vdpau_vc1.c
+xineplug_decode_vdpau_vc1_la_CFLAGS = $(AM_CFLAGS)
+xineplug_decode_vdpau_vc1_la_LIBADD = $(XINE_LIB) $(DYNAMIC_LD_LIBS)
diff --git a/src/libvdpau/vdpau_vc1.c b/src/libvdpau/vdpau_vc1.c
new file mode 100644
index 000000000..74b70d8ff
--- /dev/null
+++ b/src/libvdpau/vdpau_vc1.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2008 Christophe Thommeret <hftom@free.fr>
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * vdpau_vc1.c, a vc1 video stream parser using VDPAU hardware decoder
+ *
+ */
+
+#define LOG
+#define LOG_MODULE "vdpau_vc1"
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "xine_internal.h"
+#include "video_out.h"
+#include "buffer.h"
+#include "xineutils.h"
+#include "accel_vdpau.h"
+
+#include <vdpau/vdpau.h>
+
+#define sequence_header_code 0x0f
+#define sequence_end_code 0x0a
+#define entry_point_code 0x0e
+#define frame_start_code 0x0d
+#define field_start_code 0x0c
+#define slice_start_code 0x0b
+
+#define PICTURE_FRAME 0
+#define PICTURE_FRAME_INTERLACE 2
+#define PICTURE_FIELD_INTERLACE 3
+
+#define WANT_HEADER 1
+#define WANT_EXT 2
+#define WANT_SLICE 3
+
+
+
+typedef struct {
+ VdpPictureInfoVC1 vdp_infos;
+
+ int progressive_frame;
+ int state;
+} picture_t;
+
+
+
+typedef struct {
+ uint32_t coded_width;
+ uint32_t coded_height;
+
+ uint64_t video_step; /* frame duration in pts units */
+ double ratio;
+ VdpDecoderProfile profile;
+
+ int have_header;
+
+ uint8_t *buf; /* accumulate data */
+ uint32_t bufsize;
+ uint32_t bufpos;
+
+ picture_t picture;
+ vo_frame_t *forward_ref;
+ vo_frame_t *backward_ref;
+
+ int64_t seq_pts;
+ int64_t cur_pts;
+
+ vdpau_accel_t *accel_vdpau;
+
+ int vdp_runtime_nr;
+
+} sequence_t;
+
+
+
+typedef struct {
+ video_decoder_class_t decoder_class;
+} vdpau_vc1_class_t;
+
+
+
+typedef struct vdpau_vc1_decoder_s {
+ video_decoder_t video_decoder; /* parent video decoder structure */
+
+ vdpau_vc1_class_t *class;
+ xine_stream_t *stream;
+
+ sequence_t sequence;
+
+ VdpDecoder decoder;
+ VdpDecoderProfile decoder_profile;
+ uint32_t decoder_width;
+ uint32_t decoder_height;
+
+} vdpau_vc1_decoder_t;
+
+
+
+static void reset_picture( picture_t *pic )
+{
+ lprintf( "reset_picture\n" );
+ /*pic->vdp_infos.picture_structure = 0;
+ pic->vdp_infos2.intra_dc_precision = pic->vdp_infos.intra_dc_precision = 0;
+ pic->vdp_infos2.frame_pred_frame_dct = pic->vdp_infos.frame_pred_frame_dct = 1;
+ pic->vdp_infos2.concealment_motion_vectors = pic->vdp_infos.concealment_motion_vectors = 0;
+ pic->vdp_infos2.intra_vlc_format = pic->vdp_infos.intra_vlc_format = 0;
+ pic->vdp_infos2.alternate_scan = pic->vdp_infos.alternate_scan = 0;
+ pic->vdp_infos2.q_scale_type = pic->vdp_infos.q_scale_type = 0;
+ pic->vdp_infos2.top_field_first = pic->vdp_infos.top_field_first = 0;
+ pic->slices_count = 0;
+ pic->slices_count2 = 0;
+ pic->slices_pos = 0;
+ pic->slices_pos_top = 0;
+ pic->state = WANT_HEADER;*/
+}
+
+
+
+static void init_picture( picture_t *pic )
+{
+ reset_picture( pic );
+}
+
+
+
+static void init_sequence( sequence_t *sequence )
+{
+ lprintf( "init_sequence\n" );
+ sequence->have_header = 0;
+ sequence->bufpos = 0;
+ sequence->seq_pts = sequence->cur_pts = 0;
+ sequence->profile = VDP_DECODER_PROFILE_VC1_SIMPLE;
+ sequence->ratio = 0;
+ sequence->video_step = 0;
+ if ( sequence->forward_ref )
+ sequence->forward_ref->free( sequence->forward_ref );
+ sequence->forward_ref = NULL;
+ if ( sequence->backward_ref )
+ sequence->backward_ref->free( sequence->backward_ref );
+ sequence->backward_ref = NULL;
+}
+
+
+
+static uint32_t get_bits( uint8_t *b, int offbits, int nbits )
+{
+ int i, nbytes;
+ uint32_t ret = 0;
+ uint8_t *buf;
+
+ buf = b+(offbits/8);
+ offbits %=8;
+ nbytes = (offbits+nbits)/8;
+ if ( ((offbits+nbits)%8)>0 )
+ nbytes++;
+ for ( i=0; i<nbytes; i++ )
+ ret += buf[i]<<((nbytes-i-1)*8);
+ i = (4-nbytes)*8+offbits;
+ ret = ((ret<<i)>>i)>>((nbytes*8)-nbits-offbits);
+
+ return ret;
+}
+
+
+
+static void sequence_header_advanced( vdpau_vc1_decoder_t *this_gen, uint8_t *buf, int len )
+{
+}
+
+
+
+static void sequence_header( vdpau_vc1_decoder_t *this_gen, uint8_t *buf, int len )
+{
+ sequence_t *sequence = (sequence_t*)&this_gen->sequence;
+
+ if ( len < 4 )
+ return;
+
+ lprintf( "sequence_header\n" );
+
+ switch ( get_bits(buf,0,2) ) {
+ case 0: sequence->profile = VDP_DECODER_PROFILE_VC1_SIMPLE; break;
+ case 1: sequence->profile = VDP_DECODER_PROFILE_VC1_MAIN; break;
+ case 3: return sequence_header_advanced( this_gen, buf, len ); break;
+ default: return; /* illegal value, broken header? */
+ }
+
+ sequence->picture.vdp_infos.loopfilter = get_bits(buf,12,1);
+ sequence->picture.vdp_infos.multires = get_bits(buf,14,1);
+ sequence->picture.vdp_infos.fastuvmc = get_bits(buf,16,1);
+ sequence->picture.vdp_infos.extended_mv = get_bits(buf,17,1);
+ sequence->picture.vdp_infos.dquant = get_bits(buf,18,2);
+ sequence->picture.vdp_infos.vstransform = get_bits(buf,20,1);
+ sequence->picture.vdp_infos.overlap = get_bits(buf,22,1);
+ sequence->picture.vdp_infos.syncmarker = get_bits(buf,23,1);
+ sequence->picture.vdp_infos.rangered = get_bits(buf,24,1);
+ sequence->picture.vdp_infos.maxbframes = get_bits(buf,25,3);
+ sequence->picture.vdp_infos.quantizer = get_bits(buf,28,2);
+ sequence->picture.vdp_infos.finterpflag = get_bits(buf,30,1);
+
+ if ( !sequence->have_header ) {
+ sequence->have_header = 1;
+ _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_VIDEO_WIDTH, sequence->coded_width );
+ _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, sequence->coded_height );
+ _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_VIDEO_RATIO, ((double)10000*sequence->ratio) );
+ _x_stream_info_set( this_gen->stream, XINE_STREAM_INFO_FRAME_DURATION, sequence->video_step );
+ _x_meta_info_set_utf8( this_gen->stream, XINE_META_INFO_VIDEOCODEC, "VC1/WMV9 (vdpau)" );
+ xine_event_t event;
+ xine_format_change_data_t data;
+ event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
+ event.stream = this_gen->stream;
+ event.data = &data;
+ event.data_length = sizeof(data);
+ data.width = sequence->coded_width;
+ data.height = sequence->coded_height;
+ data.aspect = sequence->ratio;
+ xine_event_send( this_gen->stream, &event );
+ }
+}
+
+
+
+static void picture_header( vdpau_vc1_decoder_t *this_gen, uint8_t *buf, int len )
+{
+ sequence_t *sequence = (sequence_t*)&this_gen->sequence;
+ VdpPictureInfoVC1 *info = &(sequence->picture.vdp_infos);
+
+ int off=2;
+
+ if ( info->finterpflag )
+ ++off;
+ if ( info->rangered )
+ ++off;
+ if ( !info->maxbframes )
+ info->picture_type = get_bits( buf,off,1 );
+ else {
+ int ptype = get_bits( buf,off,1 );
+ if ( ptype ) {
+ info->picture_type = ptype;
+ ++off;
+ }
+ else {
+ info->picture_type = get_bits( buf,off,2 );
+ off += 2;
+ }
+ }
+
+}
+
+
+
+static void decode_render( vdpau_vc1_decoder_t *vd, vdpau_accel_t *accel )
+{
+ sequence_t *seq = (sequence_t*)&vd->sequence;
+ picture_t *pic = (picture_t*)&seq->picture;
+
+ VdpStatus st;
+ if ( vd->decoder==VDP_INVALID_HANDLE || vd->decoder_profile!=seq->profile || vd->decoder_width!=seq->coded_width || vd->decoder_height!=seq->coded_height ) {
+ if ( vd->decoder!=VDP_INVALID_HANDLE ) {
+ accel->vdp_decoder_destroy( vd->decoder );
+ vd->decoder = VDP_INVALID_HANDLE;
+ }
+ st = accel->vdp_decoder_create( accel->vdp_device, seq->profile, seq->coded_width, seq->coded_height, 2, &vd->decoder);
+ if ( st!=VDP_STATUS_OK )
+ lprintf( "failed to create decoder !! %s\n", accel->vdp_get_error_string( st ) );
+ else {
+ lprintf( "decoder created.\n" );
+ vd->decoder_profile = seq->profile;
+ vd->decoder_width = seq->coded_width;
+ vd->decoder_height = seq->coded_height;
+ seq->vdp_runtime_nr = accel->vdp_runtime_nr;
+ }
+ }
+
+ VdpBitstreamBuffer vbit;
+ vbit.struct_version = VDP_BITSTREAM_BUFFER_VERSION;
+ vbit.bitstream = seq->buf;
+ vbit.bitstream_bytes = seq->bufpos;
+ st = accel->vdp_decoder_render( vd->decoder, accel->surface, (VdpPictureInfo*)&pic->vdp_infos, 1, &vbit );
+ if ( st!=VDP_STATUS_OK )
+ lprintf( "decoder failed : %d!! %s\n", st, accel->vdp_get_error_string( st ) );
+ else {
+ lprintf( "DECODER SUCCESS : slices=%d, slices_bytes=%d, current=%d, forwref:%d, backref:%d, pts:%lld\n",
+ pic->vdp_infos.slice_count, vbit.bitstream_bytes, accel->surface, pic->vdp_infos.forward_reference, pic->vdp_infos.backward_reference, seq->seq_pts );
+ }
+}
+
+
+
+static void decode_picture( vdpau_vc1_decoder_t *vd )
+{
+ sequence_t *seq = (sequence_t*)&vd->sequence;
+
+ seq->picture.vdp_infos.picture_type = 1;
+ VdpPictureInfoVC1 *info = &(seq->picture.vdp_infos);
+ info->forward_reference = VDP_INVALID_HANDLE;
+ info->backward_reference = VDP_INVALID_HANDLE;
+ printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n\n", info->slice_count, info->picture_type, info->frame_coding_mode, info->postprocflag, info->pulldown, info->interlace, info->tfcntrflag, info->finterpflag, info->psf, info->dquant, info->panscan_flag, info->refdist_flag, info->quantizer, info->extended_mv, info->extended_dmv, info->overlap, info->vstransform, info->loopfilter, info->fastuvmc, info->range_mapy_flag, info->range_mapy, info->range_mapuv_flag, info->range_mapuv, info->multires, info->syncmarker, info->rangered, info->maxbframes, info->deblockEnable, info->pquant );
+
+ vo_frame_t *img = vd->stream->video_out->get_frame( vd->stream->video_out, seq->coded_width, seq->coded_height,
+ seq->ratio, XINE_IMGFMT_VDPAU, VO_BOTH_FIELDS );
+ vdpau_accel_t *accel = (vdpau_accel_t*)img->accel_data;
+ if ( !seq->accel_vdpau )
+ seq->accel_vdpau = accel;
+
+ if( seq->vdp_runtime_nr != *(seq->accel_vdpau->current_vdp_runtime_nr) ) {
+ seq->accel_vdpau = accel;
+ if ( seq->forward_ref )
+ seq->forward_ref->free( seq->forward_ref );
+ seq->forward_ref = NULL;
+ if ( seq->backward_ref )
+ seq->backward_ref->free( seq->backward_ref );
+ seq->backward_ref = NULL;
+ vd->decoder = VDP_INVALID_HANDLE;
+ }
+
+ decode_render( vd, accel );
+
+ img->pts = seq->seq_pts;
+ img->draw( img, vd->stream );
+ img->free( img );
+}
+
+
+
+/*
+ * This function receives a buffer of data from the demuxer layer and
+ * figures out how to handle it based on its header flags.
+ */
+static void vdpau_vc1_decode_data (video_decoder_t *this_gen, buf_element_t *buf)
+{
+ vdpau_vc1_decoder_t *this = (vdpau_vc1_decoder_t *) this_gen;
+ sequence_t *seq = (sequence_t*)&this->sequence;
+
+ /* a video decoder does not care about this flag (?) */
+ if (buf->decoder_flags & BUF_FLAG_PREVIEW) {
+ lprintf("BUF_FLAG_PREVIEW\n");
+ return;
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_FRAMERATE) {
+ lprintf("BUF_FLAG_FRAMERATE=%d\n", buf->decoder_info[0]);
+ if ( buf->decoder_info[0] > 0 ) {
+ this->sequence.video_step = buf->decoder_info[0];
+ _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->sequence.video_step);
+ }
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_HEADER) {
+ lprintf("BUF_FLAG_HEADER\n");
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_ASPECT) {
+ lprintf("BUF_FLAG_ASPECT\n");
+ seq->ratio = (double)buf->decoder_info[1]/(double)buf->decoder_info[2];
+ lprintf("arx=%d ary=%d ratio=%f\n", buf->decoder_info[1], buf->decoder_info[2], seq->ratio);
+ }
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_START) {
+ lprintf("BUF_FLAG_FRAME_START\n");
+ seq->seq_pts = buf->pts;
+ }
+
+ if ( !buf->size )
+ return;
+
+ //printf("vdpau_vc1_decode_data: new pts : %lld\n", buf->pts );
+ seq->cur_pts = buf->pts;
+
+ if (buf->decoder_flags & BUF_FLAG_STDHEADER) {
+ lprintf("BUF_FLAG_STDHEADER\n");
+ xine_bmiheader *bih = (xine_bmiheader *) buf->content;
+ int bs = sizeof( xine_bmiheader );
+ seq->coded_width = bih->biWidth;
+ seq->coded_height = bih->biHeight;
+ lprintf( "width=%d height=%d\n", bih->biWidth, bih->biHeight );
+ if ( buf->size > bs ) {
+ sequence_header( this, buf->content+bs, buf->size-bs );
+ }
+ int i;
+ for ( i=0; i<buf->size; ++i )
+ printf("%02X ", buf->content[i] );
+ printf("\n\n");
+ return;
+ }
+
+ int size = seq->bufpos+buf->size;
+ if ( seq->bufsize < size ) {
+ seq->bufsize = size+10000;
+ seq->buf = realloc( seq->buf, seq->bufsize );
+ lprintf("sequence buffer realloced = %d\n", seq->bufsize );
+ }
+ xine_fast_memcpy( seq->buf+seq->bufpos, buf->content, buf->size );
+ seq->bufpos += buf->size;
+
+ if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
+ lprintf("BUF_FLAG_FRAME_END\n");
+ seq->picture.vdp_infos.slice_count = 1;
+ decode_picture( this );
+ seq->bufpos = 0;
+ }
+
+
+ /*int i;
+ for ( i=0; i<buf->size; ++i )
+ printf("%02X ", buf->content[i] );
+ printf("\n\n");
+
+ uint8_t *buffer = buf->content;
+ for ( i=0; i<buf->size-4; ++i ) {
+ if ( buffer[i]==0 && buffer[i+1]==0 && buffer[i+2]==1 )
+ printf("start code\n");
+ }*/
+}
+
+
+/*
+ * This function is called when xine needs to flush the system.
+ */
+static void vdpau_vc1_flush (video_decoder_t *this_gen) {
+ vdpau_vc1_decoder_t *this = (vdpau_vc1_decoder_t *) this_gen;
+
+ lprintf( "vdpau_vc1_flush\n" );
+}
+
+/*
+ * This function resets the video decoder.
+ */
+static void vdpau_vc1_reset (video_decoder_t *this_gen) {
+ vdpau_vc1_decoder_t *this = (vdpau_vc1_decoder_t *) this_gen;
+
+ lprintf( "vdpau_vc1_reset\n" );
+ init_sequence( &this->sequence );
+
+ //this->size = 0;
+}
+
+/*
+ * The decoder should forget any stored pts values here.
+ */
+static void vdpau_vc1_discontinuity (video_decoder_t *this_gen) {
+ vdpau_vc1_decoder_t *this = (vdpau_vc1_decoder_t *) this_gen;
+
+ lprintf( "vdpau_vc1_discontinuity\n" );
+ init_sequence( &this->sequence );
+
+}
+
+/*
+ * This function frees the video decoder instance allocated to the decoder.
+ */
+static void vdpau_vc1_dispose (video_decoder_t *this_gen) {
+
+ vdpau_vc1_decoder_t *this = (vdpau_vc1_decoder_t *) this_gen;
+
+ lprintf( "vdpau_vc1_dispose\n" );
+
+ if ( this->decoder!=VDP_INVALID_HANDLE && this->sequence.accel_vdpau ) {
+ this->sequence.accel_vdpau->vdp_decoder_destroy( this->decoder );
+ this->decoder = VDP_INVALID_HANDLE;
+ }
+
+ this->stream->video_out->close( this->stream->video_out, this->stream );
+
+ free( this->sequence.buf );
+ free( this_gen );
+}
+
+/*
+ * This function allocates, initializes, and returns a private video
+ * decoder structure.
+ */
+static video_decoder_t *open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream) {
+
+ vdpau_vc1_decoder_t *this ;
+
+ lprintf( "open_plugin\n" );
+
+ /* the videoout must be vdpau-capable to support this decoder */
+ if ( !(stream->video_driver->get_capabilities(stream->video_driver) & VO_CAP_VDPAU_VC1) )
+ return NULL;
+
+ /* now check if vdpau has free decoder resource */
+ vo_frame_t *img = stream->video_out->get_frame( stream->video_out, 1920, 1080, 1, XINE_IMGFMT_VDPAU, VO_BOTH_FIELDS );
+ vdpau_accel_t *accel = (vdpau_accel_t*)img->accel_data;
+ img->free(img);
+ VdpDecoder decoder;
+ VdpStatus st = accel->vdp_decoder_create( accel->vdp_device, VDP_DECODER_PROFILE_VC1_MAIN, 1920, 1080, 2, &decoder );
+ if ( st!=VDP_STATUS_OK ) {
+ lprintf( "can't create vdpau decoder.\n" );
+ return NULL;
+ }
+
+ accel->vdp_decoder_destroy( decoder );
+
+ this = (vdpau_vc1_decoder_t *) calloc(1, sizeof(vdpau_vc1_decoder_t));
+
+ this->video_decoder.decode_data = vdpau_vc1_decode_data;
+ this->video_decoder.flush = vdpau_vc1_flush;
+ this->video_decoder.reset = vdpau_vc1_reset;
+ this->video_decoder.discontinuity = vdpau_vc1_discontinuity;
+ this->video_decoder.dispose = vdpau_vc1_dispose;
+
+ this->stream = stream;
+ this->class = (vdpau_vc1_class_t *) class_gen;
+
+ this->sequence.bufsize = 10000;
+ this->sequence.buf = (uint8_t*)malloc(this->sequence.bufsize);
+ this->sequence.forward_ref = 0;
+ this->sequence.backward_ref = 0;
+ this->sequence.vdp_runtime_nr = 1;
+ init_sequence( &this->sequence );
+
+ init_picture( &this->sequence.picture );
+
+ this->decoder = VDP_INVALID_HANDLE;
+ this->sequence.accel_vdpau = NULL;
+
+ (stream->video_out->open)(stream->video_out, stream);
+
+ return &this->video_decoder;
+}
+
+/*
+ * This function returns a brief string that describes (usually with the
+ * decoder's most basic name) the video decoder plugin.
+ */
+static char *get_identifier (video_decoder_class_t *this) {
+ return "vdpau_vc1";
+}
+
+/*
+ * This function returns a slightly longer string describing the video
+ * decoder plugin.
+ */
+static char *get_description (video_decoder_class_t *this) {
+ return "vdpau_vc1: vc1 decoder plugin using VDPAU hardware decoding.\n"
+ "Must be used along with video_out_vdpau.";
+}
+
+/*
+ * This function frees the video decoder class and any other memory that was
+ * allocated.
+ */
+static void dispose_class (video_decoder_class_t *this) {
+ free (this);
+}
+
+/*
+ * This function allocates a private video decoder class and initializes
+ * the class's member functions.
+ */
+static void *init_plugin (xine_t *xine, void *data) {
+
+ vdpau_vc1_class_t *this;
+
+ this = (vdpau_vc1_class_t *) calloc(1, sizeof(vdpau_vc1_class_t));
+
+ this->decoder_class.open_plugin = open_plugin;
+ this->decoder_class.get_identifier = get_identifier;
+ this->decoder_class.get_description = get_description;
+ this->decoder_class.dispose = dispose_class;
+
+ return this;
+}
+
+/*
+ * This is a list of all of the internal xine video buffer types that
+ * this decoder is able to handle. Check src/xine-engine/buffer.h for a
+ * list of valid buffer types (and add a new one if the one you need does
+ * not exist). Terminate the list with a 0.
+ */
+static const uint32_t video_types[] = {
+ BUF_VIDEO_VC1, BUF_VIDEO_WMV9,
+ 0
+};
+
+/*
+ * This data structure combines the list of supported xine buffer types and
+ * the priority that the plugin should be given with respect to other
+ * plugins that handle the same buffer type. A plugin with priority (n+1)
+ * will be used instead of a plugin with priority (n).
+ */
+static const decoder_info_t dec_info_video = {
+ video_types, /* supported types */
+ 8 /* priority */
+};
+
+/*
+ * The plugin catalog entry. This is the only information that this plugin
+ * will export to the public.
+ */
+const plugin_info_t xine_plugin_info[] EXPORTED = {
+ /* { type, API, "name", version, special_info, init_function } */
+ { PLUGIN_VIDEO_DECODER, 18, "vdpau_vc1", XINE_VERSION_CODE, &dec_info_video, init_plugin },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h
index 845ab0079..bbf0dcc35 100644
--- a/src/xine-engine/video_out.h
+++ b/src/xine-engine/video_out.h
@@ -296,6 +296,7 @@ struct xine_video_port_s {
#define VO_CAP_XXMC 0x00000040 /* driver can use extended XvMC */
#define VO_CAP_VDPAU_H264 0x00000080 /* driver can use VDPAU for H264 */
#define VO_CAP_VDPAU_MPEG12 0x00000100 /* driver can use VDPAU for mpeg1/2 */
+#define VO_CAP_VDPAU_VC1 0x00000200 /* driver can use VDPAU for mpeg1/2 */
#define VO_CAP_CUSTOM_EXTENT_OVERLAY 0x01000000 /* driver can blend custom extent overlay to output extent */
#define VO_CAP_ARGB_LAYER_OVERLAY 0x02000000 /* driver supports true color overlay */