diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/video_out/Makefile.am | 9 | ||||
-rw-r--r-- | src/video_out/video_out_vdpau.c | 743 |
2 files changed, 752 insertions, 0 deletions
diff --git a/src/video_out/Makefile.am b/src/video_out/Makefile.am index 80dd1e92c..8d8753659 100644 --- a/src/video_out/Makefile.am +++ b/src/video_out/Makefile.am @@ -36,6 +36,10 @@ endif endif endif +if HAVE_VDPAU +vdpau_module = xineplug_vo_out_vdpau.la +endif + if HAVE_XCB XCBOSD = xcbosd.c if HAVE_XCBSHM @@ -100,9 +104,14 @@ xineplug_LTLIBRARIES = $(xshm_module) $(xv_module) $(xvmc_module) \ $(xxmc_module) \ $(xcbshm_module) \ $(xcbxv_module) \ + $(vdpau_module) \ xineplug_vo_out_raw.la \ xineplug_vo_out_none.la +xineplug_vo_out_vdpau_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c yuv2rgb_mlib.c video_out_vdpau.c +xineplug_vo_out_vdpau_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) $(PTHREAD_LIBS) $(X_LIBS) $(LTLIBINTL) -lvdpau +xineplug_vo_out_vdpau_la_CFLAGS = $(VISIBILITY_FLAG) $(MLIB_CFLAGS) $(X_CFLAGS) + xineplug_vo_out_xcbshm_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c yuv2rgb_mlib.c video_out_xcbshm.c $(XCBOSD) xineplug_vo_out_xcbshm_la_LIBADD = $(XINE_LIB) $(MLIB_LIBS) $(PTHREAD_LIBS) $(XCB_LIBS) $(XCBSHM_LIBS) $(LTLIBINTL) xineplug_vo_out_xcbshm_la_CFLAGS = $(VISIBILITY_FLAG) $(MLIB_CFLAGS) $(XCB_CFLAGS) $(XCBSHM_CFLAGS) diff --git a/src/video_out/video_out_vdpau.c b/src/video_out/video_out_vdpau.c new file mode 100644 index 000000000..ccda264bd --- /dev/null +++ b/src/video_out/video_out_vdpau.c @@ -0,0 +1,743 @@ +/* + * Copyright (C) 2008 the xine project + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * + * video_out_vdpau.c, a video output plugin using VDPAU (Video Decode and Presentation Api for Unix) + * + * Christophe Thommeret <hftom@free.fr> + * + */ + +/* #define LOG */ +#define LOG_MODULE "video_out_vdpau" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <math.h> +#include <errno.h> +#include <ctype.h> +#include <pthread.h> + +#include "xine.h" +#include "video_out.h" +#include "vo_scale.h" +#include "xine_internal.h" +#include "yuv2rgb.h" +#include "xineutils.h" + +#include <vdpau/vdpau_x11.h> + + + +VdpDevice vdp_device; +VdpPresentationQueue vdp_queue; +VdpPresentationQueueTarget vdp_queue_target; + +VdpGetProcAddress *vdp_get_proc_address; + +VdpGetApiVersion *vdp_get_api_version; +VdpGetInformationString *vdp_get_information_string; +VdpGetErrorString *vdp_get_error_string; + +VdpVideoSurfaceQueryGetPutBitsYCbCrCapabilities *vdp_video_surface_query_get_put_bits_ycbcr_capabilities; +VdpVideoSurfaceCreate *vdp_video_surface_create; +VdpVideoSurfaceDestroy *vdp_video_surface_destroy; +VdpVideoSurfacePutBitsYCbCr *vdp_video_surface_putbits_ycbcr; + +VdpOutputSurfaceCreate *vdp_output_surface_create; +VdpOutputSurfaceDestroy *vdp_output_surface_destroy; + +VdpVideoMixerCreate *vdp_video_mixer_create; +VdpVideoMixerDestroy *vdp_video_mixer_destroy; +VdpVideoMixerRender *vdp_video_mixer_render; + +VdpPresentationQueueTargetCreateX11 *vdp_queue_target_create_x11; +VdpPresentationQueueTargetDestroy *vdp_queue_target_destroy; +VdpPresentationQueueCreate *vdp_queue_create; +VdpPresentationQueueDestroy *vdp_queue_destroy; +VdpPresentationQueueDisplay *vdp_queue_display; +VdpPresentationQueueSetBackgroundColor *vdp_queue_set_backgroung_color; + + +typedef struct { + vo_frame_t vo_frame; + + int width, height, format, flags; + double ratio; + uint8_t *chunk[3]; /* mem alloc by xmalloc_aligned */ +} vdpau_frame_t; + + +typedef struct { + vo_driver_t vo_driver; + vo_scale_t sc; + + Display *display; + int screen; + Drawable drawable; + + config_values_t *config; + + int ovl_changed; + raw_overlay_t overlay; + yuv2rgb_t *ovl_yuv2rgb; + + VdpVideoSurface soft_surface; + uint32_t soft_surface_width; + uint32_t soft_surface_height; + int soft_surface_format; + + VdpOutputSurface output_surface; + + VdpVideoMixer video_mixer; + + xine_t *xine; +} vdpau_driver_t; + + +typedef struct { + video_driver_class_t driver_class; + xine_t *xine; +} vdpau_class_t; + + + +static void vdpau_overlay_clut_yuv2rgb(vdpau_driver_t *this, vo_overlay_t *overlay, vdpau_frame_t *frame) +{ + int i; + clut_t* clut = (clut_t*) overlay->color; + + if (!overlay->rgb_clut) { + for ( i=0; i<sizeof(overlay->color)/sizeof(overlay->color[0]); i++ ) { + *((uint32_t *)&clut[i]) = this->ovl_yuv2rgb->yuv2rgb_single_pixel_fun(this->ovl_yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr); + } + overlay->rgb_clut++; + } + if (!overlay->hili_rgb_clut) { + clut = (clut_t*) overlay->hili_color; + for ( i=0; i<sizeof(overlay->color)/sizeof(overlay->color[0]); i++) { + *((uint32_t *)&clut[i]) = this->ovl_yuv2rgb->yuv2rgb_single_pixel_fun(this->ovl_yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr); + } + overlay->hili_rgb_clut++; + } +} + + +static int vdpau_process_ovl( vdpau_driver_t *this_gen, vo_overlay_t *overlay ) +{ + raw_overlay_t *ovl = &this_gen->overlay; + + if ( overlay->width<=0 || overlay->height<=0 ) + return 0; + + if ( (overlay->width*overlay->height)!=(ovl->ovl_w*ovl->ovl_h) ) + ovl->ovl_rgba = (uint8_t*)realloc( ovl->ovl_rgba, overlay->width*overlay->height*4 ); + ovl->ovl_w = overlay->width; + ovl->ovl_h = overlay->height; + ovl->ovl_x = overlay->x; + ovl->ovl_y = overlay->y; + + int num_rle = overlay->num_rle; + rle_elem_t *rle = overlay->rle; + uint8_t *rgba = ovl->ovl_rgba; + clut_t *low_colors = (clut_t*)overlay->color; + clut_t *hili_colors = (clut_t*)overlay->hili_color; + uint8_t *low_trans = overlay->trans; + uint8_t *hili_trans = overlay->hili_trans; + clut_t *colors; + uint8_t *trans; + uint8_t alpha; + int rlelen = 0; + uint8_t clr = 0; + int i, pos=0, x, y; + + while ( num_rle>0 ) { + x = pos%ovl->ovl_w; + y = pos/ovl->ovl_w; + if ( (x>=overlay->hili_left && x<=overlay->hili_right) && (y>=overlay->hili_top && y<=overlay->hili_bottom) ) { + colors = hili_colors; + trans = hili_trans; + } + else { + colors = low_colors; + trans = low_trans; + } + rlelen = rle->len; + clr = rle->color; + alpha = trans[clr]; + for ( i=0; i<rlelen; ++i ) { + rgba[0] = colors[clr].y; + rgba[1] = colors[clr].cr; + rgba[2] = colors[clr].cb; + rgba[3] = alpha*255/15; + rgba+= 4; + ++pos; + } + ++rle; + --num_rle; + } + return 1; +} + + +static void vdpau_overlay_begin (vo_driver_t *this_gen, vo_frame_t *frame_gen, int changed) +{ + /*vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + if ( !changed ) + return; + + ++this->ovl_changed;*/ +} + + +static void vdpau_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay) +{ + /*vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + vdpau_frame_t *frame = (vdpau_frame_t *) frame_gen; + + if ( !this->ovl_changed ) + return; + + if (overlay->rle) { + if (!overlay->rgb_clut || !overlay->hili_rgb_clut) + vdpau_overlay_clut_yuv2rgb (this, overlay, frame); + if ( vdpau_process_ovl( this, overlay ) ) + ++this->ovl_changed; + }*/ +} + + +static void vdpau_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img) +{ + /*vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + if ( !this->ovl_changed ) + return; + + this->raw_overlay_cb( this->user_data, this->ovl_changed-1, this->overlays ); + + this->ovl_changed = 0;*/ +} + + +static void vdpau_frame_proc_slice (vo_frame_t *vo_img, uint8_t **src) +{ + vdpau_frame_t *frame = (vdpau_frame_t *) vo_img ; + + vo_img->proc_called = 1; + + if( frame->vo_frame.crop_left || frame->vo_frame.crop_top || + frame->vo_frame.crop_right || frame->vo_frame.crop_bottom ) + { + /* TODO: ?!? */ + return; + } +} + + + +static void vdpau_frame_field (vo_frame_t *vo_img, int which_field) +{ +} + + + +static void vdpau_frame_dispose (vo_frame_t *vo_img) +{ + vdpau_frame_t *frame = (vdpau_frame_t *) vo_img ; + + free (frame->chunk[0]); + free (frame->chunk[1]); + free (frame->chunk[2]); + free (frame); +} + + + +static vo_frame_t *vdpau_alloc_frame (vo_driver_t *this_gen) +{ + vdpau_frame_t *frame; + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + frame = (vdpau_frame_t *) calloc(1, sizeof(vdpau_frame_t)); + + if (!frame) + return NULL; + + pthread_mutex_init (&frame->vo_frame.mutex, NULL); + + /* + * supply required functions/fields + */ + frame->vo_frame.proc_slice = vdpau_frame_proc_slice; + frame->vo_frame.proc_frame = NULL; + frame->vo_frame.field = vdpau_frame_field; + frame->vo_frame.dispose = vdpau_frame_dispose; + frame->vo_frame.driver = this_gen; + + frame->width = frame->height = 0; + + return (vo_frame_t *) frame; +} + + + +static void vdpau_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_gen, + uint32_t width, uint32_t height, double ratio, int format, int flags) +{ + vdpau_frame_t *frame = (vdpau_frame_t *) frame_gen; + + /* Check frame size and format and reallocate if necessary */ + if ( (frame->width != width) || (frame->height != height) || (frame->format != format) || (frame->flags != flags)) { + /*lprintf ("updating frame to %d x %d (ratio=%g, format=%08x)\n", width, height, ratio, format); */ + + /* (re-) allocate render space */ + free (frame->chunk[0]); + free (frame->chunk[1]); + free (frame->chunk[2]); + + if (format == XINE_IMGFMT_YV12) { + frame->vo_frame.pitches[0] = 8*((width + 7) / 8); + frame->vo_frame.pitches[1] = 8*((width + 15) / 16); + frame->vo_frame.pitches[2] = 8*((width + 15) / 16); + frame->vo_frame.base[0] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, (void **) &frame->chunk[0]); + frame->vo_frame.base[1] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[1] * ((height+1)/2), (void **) &frame->chunk[1]); + frame->vo_frame.base[2] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[2] * ((height+1)/2), (void **) &frame->chunk[2]); + } else { + frame->vo_frame.pitches[0] = 8*((width + 3) / 4); + frame->vo_frame.base[0] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, (void **) &frame->chunk[0]); + frame->chunk[1] = NULL; + frame->chunk[2] = NULL; + } + + frame->width = width; + frame->height = height; + frame->format = format; + + vdpau_frame_field ((vo_frame_t *)frame, flags); + } + + frame->ratio = ratio; +} + + + +static int vdpau_redraw_needed (vo_driver_t *this_gen) +{ + return 0; +} + + + +static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + vdpau_frame_t *frame = (vdpau_frame_t *) frame_gen; + VdpStatus st; + + if ( frame->width != this->soft_surface_width || frame->height != this->soft_surface_height || frame->format != this->soft_surface_format ) { + /* recreate the surface to match frame changes */ + vdp_video_surface_destroy( this->soft_surface ); + VdpChromaType chroma = ( frame->format==XINE_IMGFMT_YV12 )? VDP_CHROMA_TYPE_420 : VDP_CHROMA_TYPE_422; + vdp_video_surface_create( vdp_device, chroma, frame->width, frame->height, &this->soft_surface ); + this->soft_surface_format = frame->format; + this->soft_surface_width = frame->width; + this->soft_surface_height = frame->height; + printf( "vo_vdpau: soft_surface redim\n" ); + + /* recreate video mixer to match video surface */ + vdp_video_mixer_destroy( this->video_mixer ); + VdpVideoMixerParameter params[] = { VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE }; + void const *param_values[] = { &this->soft_surface_width, &this->soft_surface_height, &chroma }; + st = vdp_video_mixer_create( vdp_device, 0, 0, 3, params, param_values, &this->video_mixer ); + } + + /* FIXME: have to swap U and V planes to get correct colors !! nvidia ? */ + uint32_t pitches[] = { frame->vo_frame.pitches[0], frame->vo_frame.pitches[2], frame->vo_frame.pitches[1] }; + void* data[] = { frame->vo_frame.base[0], frame->vo_frame.base[2], frame->vo_frame.base[1] }; + if ( frame->format==XINE_IMGFMT_YV12 ) { + st = vdp_video_surface_putbits_ycbcr( this->soft_surface, VDP_YCBCR_FORMAT_YV12, &data, &pitches ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: vdp_video_surface_putbits_ycbcr YV12 error : %s\n", vdp_get_error_string( st ) ); + } + else if ( frame->format==XINE_IMGFMT_YUY2 ){ + st = vdp_video_surface_putbits_ycbcr( this->soft_surface, VDP_YCBCR_FORMAT_YUYV, &data, &pitches ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: vdp_video_surface_putbits_ycbcr YUY2 error : %s\n", vdp_get_error_string( st ) ); + } + + VdpRect rect; + rect.x0 = 0; + rect.y0 = 0; + rect.x1 = 800; + rect.y1 = 600; + st = vdp_video_mixer_render( this->video_mixer, VDP_INVALID_HANDLE, 0, VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME, 0, 0, this->soft_surface, 0, 0, 0, this->output_surface, &rect, &rect, 0, 0 ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: vdp_video_mixer_render error : %s\n", vdp_get_error_string( st ) ); + + XLockDisplay( this->display ); + vdp_queue_display( vdp_queue, this->output_surface, 0, 0, 0 ) ; + XUnlockDisplay( this->display ); + + frame->vo_frame.free( &frame->vo_frame ); +} + + + +static int vdpau_get_property (vo_driver_t *this_gen, int property) +{ + switch (property) { + case VO_PROP_ASPECT_RATIO: + return XINE_VO_ASPECT_AUTO; + case VO_PROP_MAX_NUM_FRAMES: + return 15; + case VO_PROP_BRIGHTNESS: + return 0; + case VO_PROP_CONTRAST: + return 128; + case VO_PROP_SATURATION: + return 128; + case VO_PROP_WINDOW_WIDTH: + return 0; + case VO_PROP_WINDOW_HEIGHT: + return 0; + default: + return 0; + } +} + + + +static int vdpau_set_property (vo_driver_t *this_gen, int property, int value) +{ + return value; +} + + + +static void vdpau_get_property_min_max (vo_driver_t *this_gen, int property, int *min, int *max) +{ + *min = 0; + *max = 0; +} + + + +static int vdpau_gui_data_exchange (vo_driver_t *this_gen, int data_type, void *data) +{ + return 0; +} + + + +static uint32_t vdpau_get_capabilities (vo_driver_t *this_gen) +{ + uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP; + return capabilities; +} + + + +static void vdpau_dispose (vo_driver_t *this_gen) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + int i; + + free( this->overlay.ovl_rgba ); + + free (this); +} + + + +static int vdpau_init_error( VdpStatus st, const char *msg, vo_driver_t *driver, int error_string ) +{ + if ( st != VDP_STATUS_OK ) { + if ( error_string ) + printf( "vo_vdpau: %s : %s\n", msg, vdp_get_error_string( st ) ); + else + printf( "vo_vdpau: %s\n", msg ); + vdpau_dispose( driver ); + return 1; + } + return 0; +} + + + +static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const void *visual_gen) +{ + vdpau_class_t *class = (vdpau_class_t *) class_gen; + x11_visual_t *visual = (x11_visual_t *) visual_gen; + vdpau_driver_t *this; + config_values_t *config = class->xine->config; + int i; + + this = (vdpau_driver_t *) calloc(1, sizeof(vdpau_driver_t)); + + if (!this) + return NULL; + + this->display = visual->display; + this->screen = visual->screen; + this->drawable = visual->d; + + _x_vo_scale_init (&this->sc, 0, 0, config); + this->sc.frame_output_cb = visual->frame_output_cb; + this->sc.dest_size_cb = visual->dest_size_cb; + this->sc.user_data = visual->user_data; + this->sc.user_ratio = XINE_VO_ASPECT_AUTO; + + this->ovl_changed = 0; + this->xine = class->xine; + this->config = config; + + this->vo_driver.get_capabilities = vdpau_get_capabilities; + this->vo_driver.alloc_frame = vdpau_alloc_frame; + this->vo_driver.update_frame_format = vdpau_update_frame_format; + this->vo_driver.overlay_begin = vdpau_overlay_begin; + this->vo_driver.overlay_blend = vdpau_overlay_blend; + this->vo_driver.overlay_end = vdpau_overlay_end; + this->vo_driver.display_frame = vdpau_display_frame; + this->vo_driver.get_property = vdpau_get_property; + this->vo_driver.set_property = vdpau_set_property; + this->vo_driver.get_property_min_max = vdpau_get_property_min_max; + this->vo_driver.gui_data_exchange = vdpau_gui_data_exchange; + this->vo_driver.dispose = vdpau_dispose; + this->vo_driver.redraw_needed = vdpau_redraw_needed; + + this->overlay.ovl_w = this->overlay.ovl_h = 2; + this->overlay.ovl_rgba = (uint8_t*)malloc(2*2*4); + this->overlay.ovl_x = this->overlay.ovl_y = 0; + + /* overlay converter */ + yuv2rgb_factory_t *factory = yuv2rgb_factory_init (MODE_24_BGR, 0, NULL); + this->ovl_yuv2rgb = factory->create_converter( factory ); + factory->dispose( factory ); + + VdpStatus st = vdp_device_create_x11( visual->display, visual->screen, &vdp_device, &vdp_get_proc_address ); + if ( st != VDP_STATUS_OK ) { + printf( "vo_vdpau: Can't create vdp device : " ); + if ( st == VDP_STATUS_NO_IMPLEMENTATION ) + printf( "No vdpau implementation.\n" ); + else + printf( "unsupported GPU?\n" ); + vdpau_dispose( &this->vo_driver ); + return NULL; + } + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_GET_ERROR_STRING , (void*)&vdp_get_error_string ); + if ( vdpau_init_error( st, "Can't get GET_ERROR_STRING proc address !!", &this->vo_driver, 0 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_GET_API_VERSION , (void*)&vdp_get_api_version ); + if ( vdpau_init_error( st, "Can't get GET_API_VERSION proc address !!", &this->vo_driver, 1 ) ) + return NULL; + uint32_t tmp; + vdp_get_api_version( &tmp ); + printf( "vo_vdpau: vdpau API version : %d\n", tmp ); + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_GET_INFORMATION_STRING , (void*)&vdp_get_information_string ); + if ( vdpau_init_error( st, "Can't get GET_INFORMATION_STRING proc address !!", &this->vo_driver, 1 ) ) + return NULL; + const char *s; + st = vdp_get_information_string( &s ); + printf( "vo_vdpau: vdpau implementation description : %s\n", s ); + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES , (void*)&vdp_video_surface_query_get_put_bits_ycbcr_capabilities ); + if ( vdpau_init_error( st, "Can't get VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + VdpBool ok; + st = vdp_video_surface_query_get_put_bits_ycbcr_capabilities( vdp_device, VDP_CHROMA_TYPE_422, VDP_YCBCR_FORMAT_YUYV, &ok ); + if ( vdpau_init_error( st, "Failed to check vdpau yuy2 capability", &this->vo_driver, 1 ) ) + return NULL; + if ( !ok ) { + printf( "vo_vdpau: VideoSurface doesn't support yuy2, sorry.\n"); + vdpau_dispose( &this->vo_driver ); + return NULL; + } + + st = vdp_video_surface_query_get_put_bits_ycbcr_capabilities( vdp_device, VDP_CHROMA_TYPE_420, VDP_YCBCR_FORMAT_YV12, &ok ); + if ( vdpau_init_error( st, "Failed to check vdpau yv12 capability", &this->vo_driver, 1 ) ) + return NULL; + if ( !ok ) { + printf( "vo_vdpau: VideoSurface doesn't support yv12, sorry.\n"); + vdpau_dispose( &this->vo_driver ); + return NULL; + } + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE , (void*)&vdp_video_surface_create ); + if ( vdpau_init_error( st, "Can't get VIDEO_SURFACE_CREATE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , (void*)&vdp_video_surface_destroy ); + if ( vdpau_init_error( st, "Can't get VIDEO_SURFACE_DESTROY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , (void*)&vdp_video_surface_putbits_ycbcr ); + if ( vdpau_init_error( st, "Can't get VIDEO_SURFACE_PUT_BITS_Y_CB_CR proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , (void*)&vdp_output_surface_create ); + if ( vdpau_init_error( st, "Can't get OUTPUT_SURFACE_CREATE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , (void*)&vdp_output_surface_destroy ); + if ( vdpau_init_error( st, "Can't get OUTPUT_SURFACE_DESTROY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_CREATE , (void*)&vdp_video_mixer_create ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_CREATE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_DESTROY , (void*)&vdp_video_mixer_destroy ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_DESTROY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_RENDER , (void*)&vdp_video_mixer_render ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_RENDER proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , (void*)&vdp_queue_target_create_x11 ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_TARGET_CREATE_X11 proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , (void*)&vdp_queue_target_destroy ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_TARGET_DESTROY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , (void*)&vdp_queue_create ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_CREATE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , (void*)&vdp_queue_destroy ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_DESTROY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , (void*)&vdp_queue_display ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_DISPLAY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_SET_BACKGROUND_COLOR , (void*)&vdp_queue_set_backgroung_color ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_SET_BACKGROUND_COLOR proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_queue_target_create_x11( vdp_device, this->drawable, &vdp_queue_target ); + if ( vdpau_init_error( st, "Can't create presentation queue target !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_queue_create( vdp_device, vdp_queue_target, &vdp_queue ); + if ( vdpau_init_error( st, "Can't create presentation queue !!", &this->vo_driver, 1 ) ) + return NULL; + + VdpColor backColor; + backColor.red = backColor.green = backColor.blue = 0; + backColor.alpha = 1; + vdp_queue_set_backgroung_color( vdp_queue, &backColor ); + + this->soft_surface_width = 800; + this->soft_surface_height = 600; + this->soft_surface_format = XINE_IMGFMT_YV12; + st = vdp_video_surface_create( vdp_device, VDP_CHROMA_TYPE_420, this->soft_surface_width, this->soft_surface_height, &this->soft_surface ); + if ( vdpau_init_error( st, "Can't create video surface !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, 800, 600, &this->output_surface ); + if ( vdpau_init_error( st, "Can't create output surface !!", &this->vo_driver, 1 ) ) { + vdp_video_surface_destroy( this->soft_surface ); + return NULL; + } + + VdpChromaType chroma = VDP_CHROMA_TYPE_420; + VdpVideoMixerParameter params[] = { VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE }; + void const *param_values[] = { &this->soft_surface_width, &this->soft_surface_height, &chroma }; + st = vdp_video_mixer_create( vdp_device, 0, 0, 3, params, param_values, &this->video_mixer ); + if ( vdpau_init_error( st, "Can't create video mixer !!", &this->vo_driver, 1 ) ) { + vdp_video_surface_destroy( this->soft_surface ); + vdp_output_surface_destroy( this->output_surface ); + return NULL; + } + + return &this->vo_driver; +} + +/* + * class functions + */ + +static char* vdpau_get_identifier (video_driver_class_t *this_gen) +{ + return "vdpau"; +} + + + +static char* vdpau_get_description (video_driver_class_t *this_gen) +{ + return _("xine video output plugin using VDPAU hardware acceleration"); +} + + + +static void vdpau_dispose_class (video_driver_class_t *this_gen) +{ + vdpau_class_t *this = (vdpau_class_t *) this_gen; + free (this); +} + + + +static void *vdpau_init_class (xine_t *xine, void *visual_gen) +{ + vdpau_class_t *this = (vdpau_class_t *) calloc(1, sizeof(vdpau_class_t)); + + this->driver_class.open_plugin = vdpau_open_plugin; + this->driver_class.get_identifier = vdpau_get_identifier; + this->driver_class.get_description = vdpau_get_description; + this->driver_class.dispose = vdpau_dispose_class; + this->xine = xine; + + return this; +} + + + +static const vo_info_t vo_info_vdpau = { + 11, /* priority */ + XINE_VISUAL_TYPE_X11 /* visual type */ +}; + + +/* + * exported plugin catalog entry + */ + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_VIDEO_OUT, 21, "vdpau", XINE_VERSION_CODE, &vo_info_vdpau, vdpau_init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +};
\ No newline at end of file |