diff options
Diffstat (limited to 'src/video_out')
-rw-r--r-- | src/video_out/Makefile.am | 9 | ||||
-rw-r--r-- | src/video_out/video_out_raw.c | 23 | ||||
-rw-r--r-- | src/video_out/video_out_vdpau.c | 2708 | ||||
-rw-r--r-- | src/video_out/video_out_xv.c | 2 |
4 files changed, 2734 insertions, 8 deletions
diff --git a/src/video_out/Makefile.am b/src/video_out/Makefile.am index bc6191b5d..7c049b257 100644 --- a/src/video_out/Makefile.am +++ b/src/video_out/Makefile.am @@ -38,6 +38,10 @@ endif endif endif +if ENABLE_VDPAU +vdpau_module = xineplug_vo_out_vdpau.la +endif + if ENABLE_XCB XCBOSD = xcbosd.c if ENABLE_XCBSHM @@ -109,9 +113,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 = video_out_vdpau.c +xineplug_vo_out_vdpau_la_LIBADD = libyuv2rgb.la $(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 = video_out_xcbshm.c $(XCBOSD) xineplug_vo_out_xcbshm_la_LIBADD = libyuv2rgb.la $(XINE_LIB) $(PTHREAD_LIBS) $(XCB_LIBS) $(XCBSHM_LIBS) $(LTLIBINTL) $(AVUTIL_LIBS) xineplug_vo_out_xcbshm_la_CFLAGS = $(AM_CFLAGS) $(XCB_CFLAGS) $(XCBSHM_CFLAGS) $(AVUTIL_CFLAGS) diff --git a/src/video_out/video_out_raw.c b/src/video_out/video_out_raw.c index ad7c783ef..fbb7fc5f0 100644 --- a/src/video_out/video_out_raw.c +++ b/src/video_out/video_out_raw.c @@ -166,11 +166,16 @@ static int raw_process_ovl( raw_driver_t *this_gen, vo_overlay_t *overlay ) 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; + if ( alpha == 0 ) { + rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0; + } + else { + rgba[0] = colors[clr].y; + rgba[1] = colors[clr].cr; + rgba[2] = colors[clr].cb; + rgba[3] = alpha*255/15; + } + rgba+= 4; ++pos; } ++rle; @@ -300,6 +305,9 @@ static vo_frame_t *raw_alloc_frame (vo_driver_t *this_gen) if (!frame) return NULL; + frame->vo_frame.base[0] = frame->vo_frame.base[1] = frame->vo_frame.base[2] = frame->rgb = NULL; + frame->width = frame->height = frame->format = frame->flags = 0; + pthread_mutex_init (&frame->vo_frame.mutex, NULL); /* @@ -333,8 +341,6 @@ static void raw_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_ge || (frame->flags != flags)) { /* lprintf ("updating frame to %d x %d (ratio=%g, format=%08x)\n", width, height, ratio, format); */ - flags &= VO_BOTH_FIELDS; - /* (re-) allocate render space */ av_free (frame->vo_frame.base[0]); av_free (frame->vo_frame.base[1]); @@ -357,7 +363,7 @@ static void raw_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_ge frame->rgb = av_mallocz (BYTES_PER_PIXEL*width*height); /* set up colorspace converter */ - switch (flags) { + switch (flags & VO_BOTH_FIELDS) { case VO_TOP_FIELD: case VO_BOTTOM_FIELD: frame->yuv2rgb->configure (frame->yuv2rgb, @@ -384,6 +390,7 @@ static void raw_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_ge frame->width = width; frame->height = height; frame->format = format; + frame->flags = flags; raw_frame_field ((vo_frame_t *)frame, flags); } diff --git a/src/video_out/video_out_vdpau.c b/src/video_out/video_out_vdpau.c new file mode 100644 index 000000000..618b0e142 --- /dev/null +++ b/src/video_out/video_out_vdpau.c @@ -0,0 +1,2708 @@ +/* + * Copyright (C) 2008 the xine project + * 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., 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) + * + * + */ + +/* #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 <xine/video_out.h> +#include <xine/vo_scale.h> +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include "yuv2rgb.h" + +#include <vdpau/vdpau_x11.h> +#include "accel_vdpau.h" + +#ifdef HAVE_FFMPEG_AVUTIL_H +# include <mem.h> +#else +# include <libavutil/mem.h> +#endif + +#define NUM_FRAMES_BACK 1 + +#define LOCKDISPLAY /*define this if you have a buggy libX11/xcb*/ + + +#define DEINT_BOB 1 +#define DEINT_HALF_TEMPORAL 2 +#define DEINT_HALF_TEMPORAL_SPATIAL 3 +#define DEINT_TEMPORAL 4 +#define DEINT_TEMPORAL_SPATIAL 5 + +#define NUMBER_OF_DEINTERLACERS 5 + +char *vdpau_deinterlacer_name[] = { + "bob", + "half temporal", + "half temporal_spatial", + "temporal", + "temporal_spatial", + NULL +}; + +char* vdpau_deinterlacer_description [] = { + "bob\nBasic deinterlacing, doing 50i->50p.\n\n", + "half temporal\nDisplays first field only, doing 50i->25p\n\n", + "half temporal_spatial\nDisplays first field only, doing 50i->25p\n\n", + "temporal\nVery good, 50i->50p\n\n", + "temporal_spatial\nThe best, but very GPU intensive.\n\n", + NULL +}; + + +VdpOutputSurfaceRenderBlendState blend = { + VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION, + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, + VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, + 0 +}; + + + +VdpDevice vdp_device; +VdpPresentationQueue vdp_queue; +VdpPresentationQueueTarget vdp_queue_target; + +VdpDeviceDestroy *vdp_device_destroy; + +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; +VdpVideoSurfaceGetBitsYCbCr *vdp_video_surface_getbits_ycbcr; + +VdpOutputSurfaceCreate *vdp_output_surface_create; +VdpOutputSurfaceDestroy *vdp_output_surface_destroy; +VdpOutputSurfaceRenderBitmapSurface *vdp_output_surface_render_bitmap_surface; +VdpOutputSurfacePutBitsNative *vdp_output_surface_put_bits; + +VdpVideoMixerCreate *vdp_video_mixer_create; +VdpVideoMixerDestroy *vdp_video_mixer_destroy; +VdpVideoMixerRender *vdp_video_mixer_render; +VdpVideoMixerSetAttributeValues *vdp_video_mixer_set_attribute_values; +VdpVideoMixerSetFeatureEnables *vdp_video_mixer_set_feature_enables; +VdpVideoMixerGetFeatureEnables *vdp_video_mixer_get_feature_enables; +VdpVideoMixerQueryFeatureSupport *vdp_video_mixer_query_feature_support; +VdpVideoMixerQueryParameterSupport *vdp_video_mixer_query_parameter_support; +VdpVideoMixerQueryAttributeSupport *vdp_video_mixer_query_attribute_support; +VdpVideoMixerQueryParameterValueRange *vdp_video_mixer_query_parameter_value_range; +VdpVideoMixerQueryAttributeValueRange *vdp_video_mixer_query_attribute_value_range; + +VdpGenerateCSCMatrix *vdp_generate_csc_matrix; + +VdpPresentationQueueTargetCreateX11 *vdp_queue_target_create_x11; +VdpPresentationQueueTargetDestroy *vdp_queue_target_destroy; +VdpPresentationQueueCreate *vdp_queue_create; +VdpPresentationQueueDestroy *vdp_queue_destroy; +VdpPresentationQueueDisplay *vdp_queue_display; +VdpPresentationQueueBlockUntilSurfaceIdle *vdp_queue_block; +VdpPresentationQueueSetBackgroundColor *vdp_queue_set_background_color; +VdpPresentationQueueGetTime *vdp_queue_get_time; +VdpPresentationQueueQuerySurfaceStatus *vdp_queue_query_surface_status; + +VdpBitmapSurfacePutBitsNative *vdp_bitmap_put_bits; +VdpBitmapSurfaceCreate *vdp_bitmap_create; +VdpBitmapSurfaceDestroy *vdp_bitmap_destroy; + +VdpDecoderQueryCapabilities *vdp_decoder_query_capabilities; +VdpDecoderCreate *vdp_decoder_create; +VdpDecoderDestroy *vdp_decoder_destroy; +VdpDecoderRender *vdp_decoder_render; + +VdpPreemptionCallbackRegister *vdp_preemption_callback_register; + +static void vdp_preemption_callback( VdpDevice device, void *context ); +static void vdpau_reinit( vo_driver_t *this_gen ); + +static VdpVideoSurfaceCreate *orig_vdp_video_surface_create; +static VdpVideoSurfaceDestroy *orig_vdp_video_surface_destroy; + +static VdpDecoderCreate *orig_vdp_decoder_create; +static VdpDecoderDestroy *orig_vdp_decoder_destroy; +static VdpDecoderRender *orig_vdp_decoder_render; + +static Display *guarded_display; + +static VdpStatus guarded_vdp_video_surface_create(VdpDevice device, VdpChromaType chroma_type, uint32_t width, uint32_t height,VdpVideoSurface *surface) +{ + VdpStatus r; +#ifdef LOCKDISPLAY + XLockDisplay(guarded_display); +#endif + r = orig_vdp_video_surface_create(device, chroma_type, width, height, surface); +#ifdef LOCKDISPLAY + XUnlockDisplay(guarded_display); +#endif + return r; +} + +static VdpStatus guarded_vdp_video_surface_destroy(VdpVideoSurface surface) +{ + VdpStatus r; + /*XLockDisplay(guarded_display);*/ + r = orig_vdp_video_surface_destroy(surface); + /*XUnlockDisplay(guarded_display);*/ + return r; +} + +static VdpStatus guarded_vdp_decoder_create(VdpDevice device, VdpDecoderProfile profile, uint32_t width, uint32_t height, uint32_t max_references, VdpDecoder *decoder) +{ + VdpStatus r; +#ifdef LOCKDISPLAY + XLockDisplay(guarded_display); +#endif + r = orig_vdp_decoder_create(device, profile, width, height, max_references, decoder); +#ifdef LOCKDISPLAY + XUnlockDisplay(guarded_display); +#endif + return r; +} + +static VdpStatus guarded_vdp_decoder_destroy(VdpDecoder decoder) +{ + VdpStatus r; +#ifdef LOCKDISPLAY + XLockDisplay(guarded_display); +#endif + r = orig_vdp_decoder_destroy(decoder); +#ifdef LOCKDISPLAY + XUnlockDisplay(guarded_display); +#endif + return r; +} + +static VdpStatus guarded_vdp_decoder_render(VdpDecoder decoder, VdpVideoSurface target, VdpPictureInfo const *picture_info, uint32_t bitstream_buffer_count, VdpBitstreamBuffer const *bitstream_buffers) +{ + VdpStatus r; +#ifdef LOCKDISPLAY + XLockDisplay(guarded_display); +#endif + r = orig_vdp_decoder_render(decoder, target, picture_info, bitstream_buffer_count, bitstream_buffers); +#ifdef LOCKDISPLAY + XUnlockDisplay(guarded_display); +#endif + return r; +} + + + +typedef struct { + VdpBitmapSurface ovl_bitmap; + uint32_t bitmap_width, bitmap_height; + int ovl_w, ovl_h; /* overlay's width and height */ + int ovl_x, ovl_y; /* overlay's top-left display position */ + int unscaled; + int expected_overlay_width; /*if >0 scale to video width*/ + int expected_overlay_height; /* if >0 scale to video height */ +} vdpau_overlay_t; + + +typedef struct { + int x; + int y; + int w; + int h; +} +argb_ovl_data_t; + + +typedef struct { + vo_frame_t vo_frame; + + int width, height, format, flags; + double ratio; + + vdpau_accel_t vdpau_accel_data; +} 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; + vdpau_overlay_t overlays[XINE_VORAW_MAX_OVL]; + yuv2rgb_factory_t *yuv2rgb_factory; + yuv2rgb_t *ovl_yuv2rgb; + VdpOutputSurface overlay_output; + uint32_t overlay_output_width; + uint32_t overlay_output_height; + int has_overlay; + + VdpOutputSurface overlay_unscaled; + uint32_t overlay_unscaled_width; + uint32_t overlay_unscaled_height; + int has_unscaled; + + VdpOutputSurface argb_overlay; + uint32_t argb_overlay_width; + uint32_t argb_overlay_height; + int has_argb_overlay; + int argb_ovl_count; + vo_overlay_t *argb_ovl[XINE_VORAW_MAX_OVL]; + int argb_ovl_data_count; + argb_ovl_data_t argb_ovl_data[XINE_VORAW_MAX_OVL]; + + int32_t video_window_x; + int32_t video_window_y; + int32_t video_window_width; + int32_t video_window_height; + + VdpVideoSurface soft_surface; + uint32_t soft_surface_width; + uint32_t soft_surface_height; + int soft_surface_format; + +#define NOUTPUTSURFACE 2 + VdpOutputSurface output_surface[NOUTPUTSURFACE]; + uint8_t current_output_surface; + uint32_t output_surface_width[NOUTPUTSURFACE]; + uint32_t output_surface_height[NOUTPUTSURFACE]; + uint8_t init_queue; + + VdpVideoMixer video_mixer; + VdpChromaType video_mixer_chroma; + uint32_t video_mixer_width; + uint32_t video_mixer_height; + VdpColorStandard color_standard; + VdpBool temporal_spatial_is_supported; + VdpBool temporal_is_supported; + VdpBool noise_reduction_is_supported; + VdpBool sharpness_is_supported; + VdpBool inverse_telecine_is_supported; + VdpBool skip_chroma_is_supported; + + char* deinterlacers_name[NUMBER_OF_DEINTERLACERS+1]; + int deinterlacers_method[NUMBER_OF_DEINTERLACERS]; + + int scaling_level_max; + int scaling_level_current; + + VdpColor back_color; + + vdpau_frame_t *back_frame[ NUM_FRAMES_BACK ]; + + uint32_t capabilities; + xine_t *xine; + + int hue; + int saturation; + int brightness; + int contrast; + int sharpness; + int noise; + int deinterlace; + int deinterlace_method; + int enable_inverse_telecine; + int honor_progressive; + int skip_chroma; + int studio_levels; + + int vdp_runtime_nr; + int reinit_needed; + + int allocated_surfaces; + int zoom_x; + int zoom_y; +} 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 void vdpau_process_argb_ovls(vdpau_driver_t *this_gen, vo_frame_t *frame_gen) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + int i, k; + + vo_overlay_t *ovl[XINE_VORAW_MAX_OVL]; + argb_ovl_data_t ovl_data[XINE_VORAW_MAX_OVL]; + int ovl_data_count = 0; + + int total_extent_width = 0, total_extent_height = 0; + this->video_window_x = 0; + this->video_window_y = 0; + this->video_window_width = 0; + this->video_window_height = 0; + + /* lock layers while processing and determine extent */ + for (i = 0; i < this->argb_ovl_count; i++) { + pthread_mutex_lock(&this->argb_ovl[i]->argb_layer->mutex); + + if (this->argb_ovl[i]->argb_layer->buffer != NULL) { + int extent_width = this->argb_ovl[i]->extent_width; + int extent_height = this->argb_ovl[i]->extent_height; + if (extent_width <= 0 || extent_height <= 0) { + extent_width = frame_gen->width; + extent_height = frame_gen->height; + } + if (extent_width > 0 && extent_height > 0) { + if (total_extent_width < extent_width) + total_extent_width = extent_width; + if (total_extent_height < extent_height) + total_extent_height = extent_height; + ovl_data[ovl_data_count].x = this->argb_ovl[i]->x; + ovl_data[ovl_data_count].y = this->argb_ovl[i]->y; + ovl_data[ovl_data_count].w = this->argb_ovl[i]->width; + ovl_data[ovl_data_count].h = this->argb_ovl[i]->height; + ovl[ovl_data_count++] = this->argb_ovl[i]; + } + if (this->argb_ovl[i]->video_window_width > 0 + && this->argb_ovl[i]->video_window_height > 0) { + /* last one wins */ + this->video_window_x = this->argb_ovl[i]->video_window_x; + this->video_window_y = this->argb_ovl[i]->video_window_y; + this->video_window_width = this->argb_ovl[i]->video_window_width; + this->video_window_height = this->argb_ovl[i]->video_window_height; + } + } + } + + /* adjust surface */ + if (total_extent_width > 0 && total_extent_height > 0) { + if (this->argb_overlay_width != total_extent_width || this->argb_overlay_height != total_extent_height || this->argb_overlay == VDP_INVALID_HANDLE) { + if (this->argb_overlay != VDP_INVALID_HANDLE) + vdp_output_surface_destroy(this->argb_overlay); + + VdpStatus st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, total_extent_width, total_extent_height, &this->argb_overlay); + if (st != VDP_STATUS_OK) + printf("vdpau_process_argb_ovl: vdp_output_surface_create failed : %s\n", vdp_get_error_string(st)); + + this->argb_overlay_width = total_extent_width; + this->argb_overlay_height = total_extent_height; + + /* change argb_ovl_data to wipe complete surface */ + this->argb_ovl_data_count = 1; + this->argb_ovl_data[0].x = 0; + this->argb_ovl_data[0].y = 0; + this->argb_ovl_data[0].w = total_extent_width; + this->argb_ovl_data[0].h = total_extent_height; + + /* extend dirty areas to maximum for filling wiped surface */ + for (i = 0; i < ovl_data_count; i++) { + ovl[i]->argb_layer->x1 = 0; + ovl[i]->argb_layer->y1 = 0; + ovl[i]->argb_layer->x2 = ovl[i]->width; + ovl[i]->argb_layer->y2 = ovl[i]->height; + } + } + } + + /* wipe surface for gone overlays */ + if (this->argb_overlay != VDP_INVALID_HANDLE) { + uint32_t *zeros = NULL; + for (i = 0; i < this->argb_ovl_data_count; i++) { + argb_ovl_data_t *curr_ovl_data = &this->argb_ovl_data[i]; + int ovl_gone = 1; + for (k = 0; k < ovl_data_count; k++) { + if (0 == memcmp(curr_ovl_data, &ovl_data[k], sizeof (*curr_ovl_data))) { + ovl_gone = 0; + break; + } + } + if (!ovl_gone) + continue; + if (!zeros) + zeros = calloc(4, this->argb_overlay_width * this->argb_overlay_height); + if (zeros) { + uint32_t pitch = curr_ovl_data->w * 4; + VdpRect dest = { curr_ovl_data->x, curr_ovl_data->y, curr_ovl_data->x + curr_ovl_data->w, curr_ovl_data->y + curr_ovl_data->h }; + VdpStatus st = vdp_output_surface_put_bits(this->argb_overlay, (void *)&zeros, &pitch, &dest); + if (st != VDP_STATUS_OK) + printf("vdpau_process_argb_ovl: vdp_output_surface_put_bits_native failed : %s\n", vdp_get_error_string(st)); + } + } + free(zeros); + } + + /* set destination area according to dirty area of argb layer and reset dirty area */ + for (i = 0; i < ovl_data_count; i++) { + uint32_t pitch = ovl[i]->width * 4; + uint32_t *buffer_start = ovl[i]->argb_layer->buffer + ovl[i]->argb_layer->y1 * ovl[i]->width + ovl[i]->argb_layer->x1; + VdpRect dest = { ovl[i]->x + ovl[i]->argb_layer->x1, ovl[i]->y + ovl[i]->argb_layer->y1, ovl[i]->x + ovl[i]->argb_layer->x2, ovl[i]->y + ovl[i]->argb_layer->y2 }; + ovl[i]->argb_layer->x1 = ovl[i]->width; + ovl[i]->argb_layer->y1 = ovl[i]->height; + ovl[i]->argb_layer->x2 = 0; + ovl[i]->argb_layer->y2 = 0; + + VdpStatus st = vdp_output_surface_put_bits(this->argb_overlay, (void *)&buffer_start, &pitch, &dest); + if (st != VDP_STATUS_OK) + printf( "vdpau_process_argb_ovl: vdp_output_surface_put_bits_native failed : %s\n", vdp_get_error_string(st)); + else + this->has_argb_overlay = 1; + } + + /* store ovl_data */ + memcpy(this->argb_ovl_data, ovl_data, sizeof (ovl_data)); + this->argb_ovl_data_count = ovl_data_count; + + /* unlock layers */ + for (i = 0; i < this->argb_ovl_count; i++) + pthread_mutex_unlock(&this->argb_ovl[i]->argb_layer->mutex); +} + + + +static int vdpau_process_ovl( vdpau_driver_t *this_gen, vo_overlay_t *overlay ) +{ + vdpau_overlay_t *ovl = &this_gen->overlays[this_gen->ovl_changed-1]; + + if ( overlay->width<=0 || overlay->height<=0 ) + return 0; + + if ( (ovl->bitmap_width < overlay->width ) || (ovl->bitmap_height < overlay->height) || (ovl->ovl_bitmap == VDP_INVALID_HANDLE) ) { + if (ovl->ovl_bitmap != VDP_INVALID_HANDLE) { + vdp_bitmap_destroy( ovl->ovl_bitmap ); + ovl->ovl_bitmap = VDP_INVALID_HANDLE; + } + VdpStatus st = vdp_bitmap_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, overlay->width, overlay->height, 0, &ovl->ovl_bitmap ); + if ( st != VDP_STATUS_OK ) { + printf( "vdpau_process_ovl: vdp_bitmap_create failed : %s\n", vdp_get_error_string(st) ); + } + ovl->bitmap_width = overlay->width; + ovl->bitmap_height = overlay->height; + } + ovl->ovl_w = overlay->width; + ovl->ovl_h = overlay->height; + ovl->ovl_x = overlay->x; + ovl->ovl_y = overlay->y; + ovl->unscaled = overlay->unscaled; + ovl->expected_overlay_width = overlay->extent_width; + ovl->expected_overlay_height = overlay->extent_height; + uint32_t *buf = (uint32_t*)malloc(ovl->ovl_w*ovl->ovl_h*4); + if ( !buf ) + return 0; + + int num_rle = overlay->num_rle; + rle_elem_t *rle = overlay->rle; + uint32_t *rgba = buf; + uint32_t red, green, blue, alpha; + 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; + 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; + for ( i=0; i<rlelen; ++i ) { + if ( trans[clr] == 0 ) { + alpha = red = green = blue = 0; + } + else { + red = colors[clr].y; /* red */ + green = colors[clr].cr; /* green */ + blue = colors[clr].cb; /* blue */ + alpha = trans[clr]*255/15; + } + *rgba = (alpha<<24) | (red<<16) | (green<<8) | blue; + rgba++; + ++pos; + } + ++rle; + --num_rle; + } + uint32_t pitch = ovl->ovl_w*4; + VdpRect dest = { 0, 0, ovl->ovl_w, ovl->ovl_h }; + VdpStatus st = vdp_bitmap_put_bits( ovl->ovl_bitmap, &buf, &pitch, &dest); + if ( st != VDP_STATUS_OK ) { + printf( "vdpau_process_ovl: vdp_bitmap_put_bits failed : %s\n", vdp_get_error_string(st) ); + } + free(buf); + 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->has_overlay = this->has_unscaled = 0; + this->has_argb_overlay = 0; + this->argb_ovl_count = 0; + ++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 (this->ovl_changed >= XINE_VORAW_MAX_OVL) + return; + if (!overlay->rgb_clut || !overlay->hili_rgb_clut) + vdpau_overlay_clut_yuv2rgb (this, overlay, frame); + if ( vdpau_process_ovl( this, overlay ) ) + ++this->ovl_changed; + } + + if (overlay->argb_layer) { + if (this->argb_ovl_count >= XINE_VORAW_MAX_OVL) + return; + this->argb_ovl[this->argb_ovl_count++] = overlay; + } +} + + + +static void vdpau_overlay_end (vo_driver_t *this_gen, vo_frame_t *frame) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + int i; + VdpStatus st; + + if ( !this->ovl_changed ) + return; + + if (this->argb_ovl_count || this->argb_ovl_data_count) + vdpau_process_argb_ovls(this, frame); + + if ( !(this->ovl_changed-1) ) { + this->ovl_changed = 0; + this->has_overlay = 0; + this->has_unscaled = 0; + return; + } + + int w=0, h=0; + int scaler = 0; + for ( i=0; i<this->ovl_changed-1; ++i ) { + if ( this->overlays[i].unscaled ) + continue; + if ( w < (this->overlays[i].ovl_x+this->overlays[i].ovl_w) ) + w = this->overlays[i].ovl_x+this->overlays[i].ovl_w; + if ( h < (this->overlays[i].ovl_y+this->overlays[i].ovl_h) ) + h = this->overlays[i].ovl_y+this->overlays[i].ovl_h; + if ( this->overlays[i].expected_overlay_width ) + scaler = 1; + if ( this->overlays[i].expected_overlay_height ) + scaler = 1; + } + + if ( scaler ) { + w = this->video_mixer_width; + h = this->video_mixer_height; + } + + int out_w = (w>frame->width) ? w : frame->width; + int out_h = (h>frame->height) ? h : frame->height; + + if ( (this->overlay_output_width!=out_w || this->overlay_output_height!=out_h) && this->overlay_output != VDP_INVALID_HANDLE ) { + st = vdp_output_surface_destroy( this->overlay_output ); + if ( st != VDP_STATUS_OK ) { + printf( "vdpau_overlay_end: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st) ); + } + this->overlay_output = VDP_INVALID_HANDLE; + } + + this->overlay_output_width = out_w; + this->overlay_output_height = out_h; + + w = 64; h = 64; + for ( i=0; i<this->ovl_changed-1; ++i ) { + if ( !this->overlays[i].unscaled ) + continue; + if ( w < (this->overlays[i].ovl_x+this->overlays[i].ovl_w) ) + w = this->overlays[i].ovl_x+this->overlays[i].ovl_w; + if ( h < (this->overlays[i].ovl_y+this->overlays[i].ovl_h) ) + h = this->overlays[i].ovl_y+this->overlays[i].ovl_h; + } + + if ( (this->overlay_unscaled_width!=w || this->overlay_unscaled_height!=h) && this->overlay_unscaled != VDP_INVALID_HANDLE ) { + st = vdp_output_surface_destroy( this->overlay_unscaled ); + if ( st != VDP_STATUS_OK ) { + printf( "vdpau_overlay_end: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st) ); + } + this->overlay_unscaled = VDP_INVALID_HANDLE; + } + + this->overlay_unscaled_width = w; + this->overlay_unscaled_height = h; + + if ( this->overlay_unscaled == VDP_INVALID_HANDLE ) { + st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->overlay_unscaled_width, this->overlay_unscaled_height, &this->overlay_unscaled ); + if ( st != VDP_STATUS_OK ) + printf( "vdpau_overlay_end: vdp_output_surface_create failed : %s\n", vdp_get_error_string(st) ); + } + + if ( this->overlay_output == VDP_INVALID_HANDLE ) { + st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->overlay_output_width, this->overlay_output_height, &this->overlay_output ); + if ( st != VDP_STATUS_OK ) + printf( "vdpau_overlay_end: vdp_output_surface_create failed : %s\n", vdp_get_error_string(st) ); + } + + w = (this->overlay_unscaled_width>this->overlay_output_width) ? this->overlay_unscaled_width : this->overlay_output_width; + h = (this->overlay_unscaled_height>this->overlay_output_height) ? this->overlay_unscaled_height : this->overlay_output_height; + + uint32_t *buf = (uint32_t*)calloc(w*4,h); + uint32_t pitch = w*4; + VdpRect clear = { 0, 0, this->overlay_output_width, this->overlay_output_height }; + st = vdp_output_surface_put_bits( this->overlay_output, &buf, &pitch, &clear ); + if ( st != VDP_STATUS_OK ) { + printf( "vdpau_overlay_end: vdp_output_surface_put_bits (clear) failed : %s\n", vdp_get_error_string(st) ); + } + clear.x1 = this->overlay_unscaled_width; clear.y1 = this->overlay_unscaled_height; + st = vdp_output_surface_put_bits( this->overlay_unscaled, &buf, &pitch, &clear ); + if ( st != VDP_STATUS_OK ) { + printf( "vdpau_overlay_end: vdp_output_surface_put_bits (clear) failed : %s\n", vdp_get_error_string(st) ); + } + free(buf); + + VdpOutputSurface *surface; + for ( i=0; i<this->ovl_changed-1; ++i ) { + VdpRect dest = { this->overlays[i].ovl_x, this->overlays[i].ovl_y, this->overlays[i].ovl_x+this->overlays[i].ovl_w, this->overlays[i].ovl_y+this->overlays[i].ovl_h }; + if ( this->overlays[i].expected_overlay_width ) { + double rx = (double)this->overlay_output_width/(double)this->overlays[i].expected_overlay_width; + double ry = (double)this->overlay_output_height/(double)this->overlays[i].expected_overlay_height; + dest.x0 *= rx; dest.y0 *= ry; dest.x1 *=rx; dest.y1 *= ry; + lprintf( "vdpau_overlay_end: overlay_width=%d overlay_height=%d rx=%f ry=%f\n", this->overlay_output_width, this->overlay_output_height, rx, ry ); + } + VdpRect src = { 0, 0, this->overlays[i].ovl_w, this->overlays[i].ovl_h }; + surface = (this->overlays[i].unscaled) ? &this->overlay_unscaled : &this->overlay_output; + st = vdp_output_surface_render_bitmap_surface( *surface, &dest, this->overlays[i].ovl_bitmap, &src, 0, &blend, 0 ); + if ( st != VDP_STATUS_OK ) { + printf( "vdpau_overlay_end: vdp_output_surface_render_bitmap_surface failed : %s\n", vdp_get_error_string(st) ); + } + } + this->has_overlay = 1; + 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; +} + + + +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 ; + + av_free (frame->vo_frame.base[0]); + av_free (frame->vo_frame.base[1]); + av_free (frame->vo_frame.base[2]); + if ( frame->vdpau_accel_data.surface != VDP_INVALID_HANDLE ) + vdp_video_surface_destroy( frame->vdpau_accel_data.surface ); + 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; + + lprintf( "vo_vdpau: vdpau_alloc_frame\n" ); + + frame = (vdpau_frame_t *) calloc(1, sizeof(vdpau_frame_t)); + + if (!frame) + return NULL; + + frame->vo_frame.base[0] = frame->vo_frame.base[1] = frame->vo_frame.base[2] = NULL; + frame->width = frame->height = frame->format = frame->flags = 0; + + frame->vo_frame.accel_data = &frame->vdpau_accel_data; + + pthread_mutex_init (&frame->vo_frame.mutex, NULL); + + /* + * supply required functions/fields + */ + frame->vo_frame.proc_duplicate_frame_data = NULL; + 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->vdpau_accel_data.vo_frame = &frame->vo_frame; + frame->vdpau_accel_data.vdp_device = vdp_device; + frame->vdpau_accel_data.surface = VDP_INVALID_HANDLE; + frame->vdpau_accel_data.chroma = VDP_CHROMA_TYPE_420; + frame->vdpau_accel_data.color_standard = this->color_standard; + frame->vdpau_accel_data.vdp_decoder_create = vdp_decoder_create; + frame->vdpau_accel_data.vdp_decoder_destroy = vdp_decoder_destroy; + frame->vdpau_accel_data.vdp_decoder_render = vdp_decoder_render; + frame->vdpau_accel_data.vdp_get_error_string = vdp_get_error_string; + frame->vdpau_accel_data.vdp_runtime_nr = this->vdp_runtime_nr; + frame->vdpau_accel_data.current_vdp_runtime_nr = &this->vdp_runtime_nr; + + return (vo_frame_t *) frame; +} + + + +static void vdpau_provide_standard_frame_data (vo_frame_t *this_gen, xine_current_frame_data_t *data) +{ + vdpau_frame_t *this = (vdpau_frame_t *)this_gen; + VdpStatus st; + VdpYCbCrFormat format; + + if (this->vo_frame.format != XINE_IMGFMT_VDPAU) { + fprintf(stderr, "vdpau_provide_standard_frame_data: unexpected frame format 0x%08x!\n", this->vo_frame.format); + return; + } + + if (!(this->flags & VO_CHROMA_422)) { + data->format = XINE_IMGFMT_YV12; + data->img_size = this->vo_frame.width * this->vo_frame.height + + ((this->vo_frame.width + 1) / 2) * ((this->vo_frame.height + 1) / 2) + + ((this->vo_frame.width + 1) / 2) * ((this->vo_frame.height + 1) / 2); + if (data->img) { + this->vo_frame.pitches[0] = 8*((this->vo_frame.width + 7) / 8); + this->vo_frame.pitches[1] = 8*((this->vo_frame.width + 15) / 16); + this->vo_frame.pitches[2] = 8*((this->vo_frame.width + 15) / 16); + this->vo_frame.base[0] = av_mallocz(this->vo_frame.pitches[0] * this->vo_frame.height); + this->vo_frame.base[1] = av_mallocz(this->vo_frame.pitches[1] * ((this->vo_frame.height+1)/2)); + this->vo_frame.base[2] = av_mallocz(this->vo_frame.pitches[2] * ((this->vo_frame.height+1)/2)); + format = VDP_YCBCR_FORMAT_YV12; + } + } else { + data->format = XINE_IMGFMT_YUY2; + data->img_size = this->vo_frame.width * this->vo_frame.height + + ((this->vo_frame.width + 1) / 2) * this->vo_frame.height + + ((this->vo_frame.width + 1) / 2) * this->vo_frame.height; + if (data->img) { + this->vo_frame.pitches[0] = 8*((this->vo_frame.width + 3) / 4); + this->vo_frame.base[0] = av_mallocz(this->vo_frame.pitches[0] * this->vo_frame.height); + format = VDP_YCBCR_FORMAT_YUYV; + } + } + + if (data->img) { + st = vdp_video_surface_getbits_ycbcr(this->vdpau_accel_data.surface, format, this->vo_frame.base, this->vo_frame.pitches); + if (st != VDP_STATUS_OK) + printf("vo_vdpau: failed to get surface bits !! %s\n", vdp_get_error_string(st)); + + if (format == VDP_YCBCR_FORMAT_YV12) { + yv12_to_yv12( + /* Y */ + this->vo_frame.base[0], this->vo_frame.pitches[0], + data->img, this->vo_frame.width, + /* U */ + this->vo_frame.base[2], this->vo_frame.pitches[2], + data->img+this->vo_frame.width*this->vo_frame.height, this->vo_frame.width/2, + /* V */ + this->vo_frame.base[1], this->vo_frame.pitches[1], + data->img+this->vo_frame.width*this->vo_frame.height+this->vo_frame.width*this->vo_frame.height/4, this->vo_frame.width/2, + /* width x height */ + this->vo_frame.width, this->vo_frame.height); + } else { + yuy2_to_yuy2( + /* src */ + this->vo_frame.base[0], this->vo_frame.pitches[0], + /* dst */ + data->img, this->vo_frame.width*2, + /* width x height */ + this->vo_frame.width, this->vo_frame.height); + } + + av_freep (&this->vo_frame.base[0]); + av_freep (&this->vo_frame.base[1]); + av_freep (&this->vo_frame.base[2]); + } +} + + + +static void vdpau_duplicate_frame_data (vo_frame_t *this_gen, vo_frame_t *original) +{ + vdpau_frame_t *this = (vdpau_frame_t *)this_gen; + vdpau_frame_t *orig = (vdpau_frame_t *)original; + VdpStatus st; + VdpYCbCrFormat format; + + if (orig->vo_frame.format != XINE_IMGFMT_VDPAU) { + fprintf(stderr, "vdpau_duplicate_frame_data: unexpected frame format 0x%08x!\n", orig->vo_frame.format); + return; + } + + if(orig->vdpau_accel_data.vdp_runtime_nr != this->vdpau_accel_data.vdp_runtime_nr) { + fprintf(stderr, "vdpau_duplicate_frame_data: called with invalid frame\n"); + return; + } + + if (!(orig->flags & VO_CHROMA_422)) { + this->vo_frame.pitches[0] = 8*((orig->vo_frame.width + 7) / 8); + this->vo_frame.pitches[1] = 8*((orig->vo_frame.width + 15) / 16); + this->vo_frame.pitches[2] = 8*((orig->vo_frame.width + 15) / 16); + this->vo_frame.base[0] = av_mallocz(this->vo_frame.pitches[0] * orig->vo_frame.height); + this->vo_frame.base[1] = av_mallocz(this->vo_frame.pitches[1] * ((orig->vo_frame.height+1)/2)); + this->vo_frame.base[2] = av_mallocz(this->vo_frame.pitches[2] * ((orig->vo_frame.height+1)/2)); + format = VDP_YCBCR_FORMAT_YV12; + } else { + this->vo_frame.pitches[0] = 8*((orig->vo_frame.width + 3) / 4); + this->vo_frame.base[0] = av_mallocz(this->vo_frame.pitches[0] * orig->vo_frame.height); + format = VDP_YCBCR_FORMAT_YUYV; + } + + st = vdp_video_surface_getbits_ycbcr(orig->vdpau_accel_data.surface, format, this->vo_frame.base, this->vo_frame.pitches); + if (st != VDP_STATUS_OK) + printf("vo_vdpau: failed to get surface bits !! %s\n", vdp_get_error_string(st)); + + st = vdp_video_surface_putbits_ycbcr(this->vdpau_accel_data.surface, format, this->vo_frame.base, this->vo_frame.pitches); + if (st != VDP_STATUS_OK) + printf("vo_vdpau: failed to put surface bits !! %s\n", vdp_get_error_string(st)); + + this->vdpau_accel_data.color_standard = orig->vdpau_accel_data.color_standard; + + av_freep (&this->vo_frame.base[0]); + av_freep (&this->vo_frame.base[1]); + av_freep (&this->vo_frame.base[2]); +} + + + +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_driver_t *this = (vdpau_driver_t *) this_gen; + vdpau_frame_t *frame = VDPAU_FRAME(frame_gen); + + VdpChromaType chroma = (flags & VO_CHROMA_422) ? VDP_CHROMA_TYPE_422 : VDP_CHROMA_TYPE_420; + + vo_frame_t orig_frame_content; + if (format == XINE_IMGFMT_VDPAU) { + if (frame_gen != &frame->vo_frame) { + /* this is an intercepted frame, so we need to detect and propagate any + * changes on the original vo_frame to all the intercepted frames */ + xine_fast_memcpy(&orig_frame_content, &frame->vo_frame, sizeof (vo_frame_t)); + } + } + + /* Check frame size and format and reallocate if necessary */ + if ( (frame->width != width) || (frame->height != height) || (frame->format != format) || (frame->format==XINE_IMGFMT_VDPAU && frame->vdpau_accel_data.chroma!=chroma) || + (frame->vdpau_accel_data.vdp_runtime_nr != this->vdp_runtime_nr)) { + + /* (re-) allocate render space */ + av_freep (&frame->vo_frame.base[0]); + av_freep (&frame->vo_frame.base[1]); + av_freep (&frame->vo_frame.base[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] = av_mallocz (frame->vo_frame.pitches[0] * height); + frame->vo_frame.base[1] = av_mallocz (frame->vo_frame.pitches[1] * ((height+1)/2)); + frame->vo_frame.base[2] = av_mallocz (frame->vo_frame.pitches[2] * ((height+1)/2)); + } else if (format == XINE_IMGFMT_YUY2){ + frame->vo_frame.pitches[0] = 8*((width + 3) / 4); + frame->vo_frame.base[0] = av_mallocz (frame->vo_frame.pitches[0] * height); + } + + if ( frame->vdpau_accel_data.vdp_runtime_nr != this->vdp_runtime_nr ) { + frame->vdpau_accel_data.surface = VDP_INVALID_HANDLE; + frame->vdpau_accel_data.vdp_runtime_nr = this->vdp_runtime_nr; + frame->vdpau_accel_data.vdp_device = vdp_device; + frame->vo_frame.proc_duplicate_frame_data = NULL; + frame->vo_frame.proc_provide_standard_frame_data = NULL; + } + + if ( frame->vdpau_accel_data.surface != VDP_INVALID_HANDLE ) { + if ( (frame->width != width) || (frame->height != height) || (format != XINE_IMGFMT_VDPAU) || frame->vdpau_accel_data.chroma != chroma ) { + lprintf("vo_vdpau: update_frame - destroy surface\n"); + vdp_video_surface_destroy( frame->vdpau_accel_data.surface ); + frame->vdpau_accel_data.surface = VDP_INVALID_HANDLE; + --this->allocated_surfaces; + frame->vo_frame.proc_duplicate_frame_data = NULL; + frame->vo_frame.proc_provide_standard_frame_data = NULL; + } + } + + if ( (format == XINE_IMGFMT_VDPAU) && (frame->vdpau_accel_data.surface == VDP_INVALID_HANDLE) ) { + VdpStatus st = vdp_video_surface_create( vdp_device, chroma, width, height, &frame->vdpau_accel_data.surface ); + if ( st!=VDP_STATUS_OK ) + printf( "vo_vdpau: failed to create surface !! %s\n", vdp_get_error_string( st ) ); + else { + frame->vdpau_accel_data.chroma = chroma; + ++this->allocated_surfaces; + frame->vo_frame.proc_duplicate_frame_data = vdpau_duplicate_frame_data; + frame->vo_frame.proc_provide_standard_frame_data = vdpau_provide_standard_frame_data; + } + } + + frame->width = width; + frame->height = height; + frame->format = format; + frame->flags = flags; + + vdpau_frame_field ((vo_frame_t *)frame, flags); + } + + frame->vdpau_accel_data.color_standard = VDP_COLOR_STANDARD_ITUR_BT_601; + frame->ratio = ratio; + frame->vo_frame.future_frame = NULL; + + if (format == XINE_IMGFMT_VDPAU) { + if (frame_gen != &frame->vo_frame) { + /* this is an intercepted frame, so we need to detect and propagate any + * changes on the original vo_frame to all the intercepted frames */ + unsigned char *p0 = (unsigned char *)&orig_frame_content; + unsigned char *p1 = (unsigned char *)&frame->vo_frame; + int i; + for (i = 0; i < sizeof (vo_frame_t); i++) { + if (*p0 != *p1) { + /* propagate the change */ + vo_frame_t *f = frame_gen; + while (f->next) { + /* serveral restrictions apply when intercepting VDPAU frames. So let's check + * the intercepted frames before modifing them and fail otherwise. */ + unsigned char *p = (unsigned char *)f + i; + if (*p != *p0) { + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "vdpau_update_frame_format: a post plugin violates the restrictions on intercepting VDPAU frames\n"); + _x_abort(); + } + + *p = *p1; + f = f->next; + } + } + p0++; + p1++; + } + } + } +} + + + +static int vdpau_redraw_needed (vo_driver_t *this_gen) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + _x_vo_scale_compute_ideal_size( &this->sc ); + if ( _x_vo_scale_redraw_needed( &this->sc ) ) { + _x_vo_scale_compute_output_size( &this->sc ); + return 1; + } + return 0; +} + + + +static void vdpau_release_back_frames( vo_driver_t *this_gen ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + int i; + + for ( i=0; i<NUM_FRAMES_BACK; ++i ) { + if ( this->back_frame[ i ]) + this->back_frame[ i ]->vo_frame.free( &this->back_frame[ i ]->vo_frame ); + this->back_frame[ i ] = NULL; + } +} + + + +static void vdpau_backup_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; + + int i; + if ( this->back_frame[NUM_FRAMES_BACK-1]) { + this->back_frame[NUM_FRAMES_BACK-1]->vo_frame.free (&this->back_frame[NUM_FRAMES_BACK-1]->vo_frame); + } + for ( i=NUM_FRAMES_BACK-1; i>0; i-- ) + this->back_frame[i] = this->back_frame[i-1]; + this->back_frame[0] = frame; +} + + + +static void vdpau_set_deinterlace( vo_driver_t *this_gen ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + VdpVideoMixerFeature features[2]; + VdpBool feature_enables[2]; + int features_count = 0; + if ( this->temporal_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL; + ++features_count; + } + if ( this->temporal_spatial_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL; + ++features_count; + } + + if ( !features_count ) + return; + + if ( this->deinterlace ) { + if ( this->video_mixer_width<800 ) { + feature_enables[0] = feature_enables[1] = 1; + if ( this->temporal_is_supported ) { + if ( this->temporal_spatial_is_supported ) + printf("vo_vdpau: deinterlace: temporal_spatial\n" ); + else + printf("vo_vdpau: deinterlace: temporal\n" ); + } + else + printf("vo_vdpau: deinterlace: bob\n" ); + } + else { + switch ( this->deinterlacers_method[this->deinterlace_method] ) { + case DEINT_BOB: + feature_enables[0] = feature_enables[1] = 0; + printf("vo_vdpau: deinterlace: bob\n" ); + break; + case DEINT_HALF_TEMPORAL: + feature_enables[0] = 1; feature_enables[1] = 0; + printf("vo_vdpau: deinterlace: half_temporal\n" ); + break; + case DEINT_TEMPORAL: + feature_enables[0] = 1; feature_enables[1] = 0; + printf("vo_vdpau: deinterlace: temporal\n" ); + break; + case DEINT_HALF_TEMPORAL_SPATIAL: + feature_enables[0] = feature_enables[1] = 1; + printf("vo_vdpau: deinterlace: half_temporal_spatial\n" ); + break; + case DEINT_TEMPORAL_SPATIAL: + feature_enables[0] = feature_enables[1] = 1; + printf("vo_vdpau: deinterlace: temporal_spatial\n" ); + break; + } + } + } + else { + feature_enables[0] = feature_enables[1] = 0; + printf("vo_vdpau: deinterlace: none\n" ); + } + + vdp_video_mixer_set_feature_enables( this->video_mixer, features_count, features, feature_enables ); +} + + + +static void vdpau_set_inverse_telecine( vo_driver_t *this_gen ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + if ( !this->inverse_telecine_is_supported ) + return; + + VdpVideoMixerFeature features[] = { VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE }; + VdpBool feature_enables[1]; + if ( this->deinterlace && this->enable_inverse_telecine ) + feature_enables[0] = 1; + else + feature_enables[0] = 0; + + vdp_video_mixer_set_feature_enables( this->video_mixer, 1, features, feature_enables ); + vdp_video_mixer_get_feature_enables( this->video_mixer, 1, features, feature_enables ); + printf("vo_vdpau: enabled features: inverse_telecine=%d\n", feature_enables[0] ); +} + + + +static void vdpau_update_deinterlace_method( void *this_gen, xine_cfg_entry_t *entry ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + this->deinterlace_method = entry->num_value; + printf( "vo_vdpau: deinterlace_method=%d\n", this->deinterlace_method ); + vdpau_set_deinterlace( (vo_driver_t*)this_gen ); +} + + + +static void vdpau_set_scaling_level( vo_driver_t *this_gen ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + int i; + VdpVideoMixerFeature features[9]; + VdpBool feature_enables[9]; +#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + for ( i=0; i<this->scaling_level_max; ++i ) { + features[i] = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + i; + feature_enables[i] = 0; + } + vdp_video_mixer_set_feature_enables( this->video_mixer, this->scaling_level_max, features, feature_enables ); + + if ( this->scaling_level_current ) { + features[0] = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 - 1 + this->scaling_level_current; + feature_enables[0] = 1; + vdp_video_mixer_set_feature_enables( this->video_mixer, 1, features, feature_enables ); + } + + printf( "vo_vdpau: set_scaling_level=%d\n", this->scaling_level_current ); +#endif +} + + + +static void vdpau_update_scaling_level( void *this_gen, xine_cfg_entry_t *entry ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + this->scaling_level_current = entry->num_value; + printf( "vo_vdpau: scaling_quality=%d\n", this->scaling_level_current ); + vdpau_set_scaling_level( (vo_driver_t*)this_gen ); +} + + + +static void vdpau_update_enable_inverse_telecine( void *this_gen, xine_cfg_entry_t *entry ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + this->enable_inverse_telecine = entry->num_value; + printf( "vo_vdpau: enable inverse_telecine=%d\n", this->enable_inverse_telecine ); + vdpau_set_inverse_telecine( (vo_driver_t*)this_gen ); +} + + + +static void vdpau_honor_progressive_flag( void *this_gen, xine_cfg_entry_t *entry ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + this->honor_progressive = entry->num_value; + printf( "vo_vdpau: honor_progressive=%d\n", this->honor_progressive ); +} + + + +static void vdpau_update_noise( vdpau_driver_t *this_gen ) +{ + if ( !this_gen->noise_reduction_is_supported ) + return; + + float value = this_gen->noise/100.0; + if ( value==0 ) { + VdpVideoMixerFeature features[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION }; + VdpBool feature_enables[] = { 0 }; + vdp_video_mixer_set_feature_enables( this_gen->video_mixer, 1, features, feature_enables ); + printf( "vo_vdpau: disable noise reduction.\n" ); + return; + } + else { + VdpVideoMixerFeature features[] = { VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION }; + VdpBool feature_enables[] = { 1 }; + vdp_video_mixer_set_feature_enables( this_gen->video_mixer, 1, features, feature_enables ); + printf( "vo_vdpau: enable noise reduction.\n" ); + } + + VdpVideoMixerAttribute attributes [] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL }; + void* attribute_values[] = { &value }; + VdpStatus st = vdp_video_mixer_set_attribute_values( this_gen->video_mixer, 1, attributes, attribute_values ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: error, can't set noise reduction level !!\n" ); +} + + + +static void vdpau_update_sharpness( vdpau_driver_t *this_gen ) +{ + if ( !this_gen->sharpness_is_supported ) + return; + + float value = this_gen->sharpness/100.0; + if ( value==0 ) { + VdpVideoMixerFeature features[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS }; + VdpBool feature_enables[] = { 0 }; + vdp_video_mixer_set_feature_enables( this_gen->video_mixer, 1, features, feature_enables ); + printf( "vo_vdpau: disable sharpness.\n" ); + return; + } + else { + VdpVideoMixerFeature features[] = { VDP_VIDEO_MIXER_FEATURE_SHARPNESS }; + VdpBool feature_enables[] = { 1 }; + vdp_video_mixer_set_feature_enables( this_gen->video_mixer, 1, features, feature_enables ); + printf( "vo_vdpau: enable sharpness.\n" ); + } + + VdpVideoMixerAttribute attributes [] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL }; + void* attribute_values[] = { &value }; + VdpStatus st = vdp_video_mixer_set_attribute_values( this_gen->video_mixer, 1, attributes, attribute_values ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: error, can't set sharpness level !!\n" ); +} + + + +static void vdpau_update_csc( vdpau_driver_t *this_gen ) +{ + float hue = this_gen->hue/100.0; + float saturation = this_gen->saturation/100.0; + float contrast = this_gen->contrast/100.0; + float brightness = this_gen->brightness/100.0; + + printf( "vo_vdpau: vdpau_update_csc: hue=%f, saturation=%f, contrast=%f, brightness=%f, color_standard=%d studio_levels=%d\n", hue, saturation, contrast, brightness, this_gen->color_standard, this_gen->studio_levels ); + + VdpStatus st; + VdpCSCMatrix matrix; + VdpProcamp procamp = { VDP_PROCAMP_VERSION, brightness, contrast, saturation, hue }; + + if ( this_gen->studio_levels ) { + int i; + float Kr, Kg, Kb; + float uvcos = procamp.saturation * cos(procamp.hue); + float uvsin = procamp.saturation * sin(procamp.hue); + int rgbmin = 16; + int rgbr = 235 - 16; + switch ( this_gen->color_standard ) { + case VDP_COLOR_STANDARD_SMPTE_240M: + Kr = 0.2122; + Kg = 0.7013; + Kb = 0.0865; + break; + case VDP_COLOR_STANDARD_ITUR_BT_709: + Kr = 0.2125; + Kg = 0.7154; + Kb = 0.0721; + break; + case VDP_COLOR_STANDARD_ITUR_BT_601: + default: + Kr = 0.299; + Kg = 0.587; + Kb = 0.114; + break; + } + float uv_coeffs[3][2] = {{ 0.000, (rgbr / 112.0) * (1 - Kr) }, + {-(rgbr / 112.0) * (1 - Kb) * Kb / Kg, -(rgbr / 112.0) * (1 - Kr) * Kr / Kg }, + { (rgbr / 112.0) * (1 - Kb), 0.000 }}; + for (i = 0; i < 3; ++i) { + matrix[i][3] = procamp.brightness; + matrix[i][0] = rgbr * procamp.contrast / 219; + matrix[i][3] += (-16 / 255.0) * matrix[i][0]; + matrix[i][1] = uv_coeffs[i][0] * uvcos + uv_coeffs[i][1] * uvsin; + matrix[i][3] += (-128 / 255.0) * matrix[i][1]; + matrix[i][2] = uv_coeffs[i][0] * uvsin + uv_coeffs[i][1] * uvcos; + matrix[i][3] += (-128 / 255.0) * matrix[i][2]; + matrix[i][3] += rgbmin / 255.0; + matrix[i][3] += 0.5 - procamp.contrast / 2.0; + } + } + else { + st = vdp_generate_csc_matrix( &procamp, this_gen->color_standard, &matrix ); + if ( st != VDP_STATUS_OK ) { + printf( "vo_vdpau: error, can't generate csc matrix !!\n" ); + return; + } + } + VdpVideoMixerAttribute attributes [] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX }; + void* attribute_values[] = { &matrix }; + st = vdp_video_mixer_set_attribute_values( this_gen->video_mixer, 1, attributes, attribute_values ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: error, can't set csc matrix !!\n" ); +} + + + +static void vdpau_update_skip_chroma( vdpau_driver_t *this_gen ) +{ + if ( !this_gen->skip_chroma_is_supported ) + return; + + VdpVideoMixerAttribute attributes [] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE }; + void* attribute_values[] = { &(this_gen->skip_chroma) }; + VdpStatus st = vdp_video_mixer_set_attribute_values( this_gen->video_mixer, 1, attributes, attribute_values ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: error, can't set skip_chroma !!\n" ); + else + printf( "vo_vdpau: skip_chroma = %d\n", this_gen->skip_chroma ); +} + + + +static void vdpau_set_skip_chroma( void *this_gen, xine_cfg_entry_t *entry ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + this->skip_chroma = entry->num_value; + vdpau_update_skip_chroma( this ); +} + + + +static void vdpau_set_studio_levels( void *this_gen, xine_cfg_entry_t *entry ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + this->studio_levels = entry->num_value; + vdpau_update_csc( this ); +} + + + +static void vdpau_shift_queue( vo_driver_t *this_gen ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + if ( this->init_queue<2 ) + ++this->init_queue; + ++this->current_output_surface; + if ( this->current_output_surface > (NOUTPUTSURFACE-1) ) + this->current_output_surface = 0; +} + + + +static void vdpau_check_output_size( vo_driver_t *this_gen ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + if ( (this->sc.gui_width > this->output_surface_width[this->current_output_surface]) || (this->sc.gui_height > this->output_surface_height[this->current_output_surface]) ) { + /* recreate output surface to match window size */ + lprintf( "vo_vdpau: output_surface size update\n" ); + this->output_surface_width[this->current_output_surface] = this->sc.gui_width; + this->output_surface_height[this->current_output_surface] = this->sc.gui_height; + + vdp_output_surface_destroy( this->output_surface[this->current_output_surface] ); + vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->output_surface_width[this->current_output_surface], this->output_surface_height[this->current_output_surface], &this->output_surface[this->current_output_surface] ); + } +} + + + +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; + VdpVideoSurface surface; + VdpChromaType chroma = this->video_mixer_chroma; + VdpColorStandard color_standard = this->color_standard; + uint32_t mix_w = this->video_mixer_width; + uint32_t mix_h = this->video_mixer_height; + VdpTime stream_speed; + + + if(this->reinit_needed) + vdpau_reinit(this_gen); + + if ( (frame->width != this->sc.delivered_width) || (frame->height != this->sc.delivered_height) || (frame->ratio != this->sc.delivered_ratio) ) { + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + + this->sc.delivered_height = frame->height; + this->sc.delivered_width = frame->width; + this->sc.delivered_ratio = frame->ratio; + this->sc.crop_left = frame->vo_frame.crop_left; + this->sc.crop_right = frame->vo_frame.crop_right; + this->sc.crop_top = frame->vo_frame.crop_top; + this->sc.crop_bottom = frame->vo_frame.crop_bottom; + + vdpau_redraw_needed( this_gen ); + + if ( (frame->format == XINE_IMGFMT_YV12) || (frame->format == XINE_IMGFMT_YUY2) ) { + chroma = ( frame->format==XINE_IMGFMT_YV12 )? VDP_CHROMA_TYPE_420 : VDP_CHROMA_TYPE_422; + if ( (frame->width != this->soft_surface_width) || (frame->height != this->soft_surface_height) || (frame->format != this->soft_surface_format) ) { + lprintf( "vo_vdpau: soft_surface size update\n" ); + /* recreate surface to match frame changes */ + this->soft_surface_width = frame->width; + this->soft_surface_height = frame->height; + this->soft_surface_format = frame->format; + vdp_video_surface_destroy( this->soft_surface ); + this->soft_surface = VDP_INVALID_HANDLE; + vdp_video_surface_create( vdp_device, chroma, this->soft_surface_width, this->soft_surface_height, &this->soft_surface ); + } + /* FIXME: have to swap U and V planes to get correct colors !! */ + 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 { + 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 ) ); + } + surface = this->soft_surface; + mix_w = this->soft_surface_width; + mix_h = this->soft_surface_height; + } + else if (frame->format == XINE_IMGFMT_VDPAU) { + surface = frame->vdpau_accel_data.surface; + mix_w = frame->width; + mix_h = frame->height; + chroma = (frame->vo_frame.flags & VO_CHROMA_422) ? VDP_CHROMA_TYPE_422 : VDP_CHROMA_TYPE_420; + color_standard = frame->vdpau_accel_data.color_standard; + } + else { + /* unknown format */ + printf( "vo_vdpau: got an unknown image -------------\n" ); + frame->vo_frame.free( &frame->vo_frame ); + return; + } + + if ( (mix_w != this->video_mixer_width) || (mix_h != this->video_mixer_height) || (chroma != this->video_mixer_chroma)) { + vdpau_release_back_frames( this_gen ); /* empty past frames array */ + lprintf("vo_vdpau: recreate mixer to match frames: width=%d, height=%d, chroma=%d\n", mix_w, mix_h, chroma); + vdp_video_mixer_destroy( this->video_mixer ); + this->video_mixer = VDP_INVALID_HANDLE; + VdpVideoMixerFeature features[15]; + int features_count = 0; + if ( this->noise_reduction_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; + ++features_count; + } + if ( this->sharpness_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS; + ++features_count; + } + if ( this->temporal_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL; + ++features_count; + } + if ( this->temporal_spatial_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL; + ++features_count; + } + if ( this->inverse_telecine_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE; + ++features_count; + } + int i; +#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + for ( i=0; i<this->scaling_level_max; ++i ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + i; + ++features_count; + } +#endif + VdpVideoMixerParameter params[] = { VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, + VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE, VDP_VIDEO_MIXER_PARAMETER_LAYERS }; + int num_layers = 3; + void const *param_values[] = { &mix_w, &mix_h, &chroma, &num_layers }; + vdp_video_mixer_create( vdp_device, features_count, features, 4, params, param_values, &this->video_mixer ); + this->video_mixer_chroma = chroma; + this->video_mixer_width = mix_w; + this->video_mixer_height = mix_h; + vdpau_set_deinterlace( this_gen ); + vdpau_set_scaling_level( this_gen ); + vdpau_set_inverse_telecine( this_gen ); + vdpau_update_noise( this ); + vdpau_update_sharpness( this ); + this->color_standard = color_standard; + vdpau_update_csc( this ); + vdpau_update_skip_chroma( this ); + } + + if (color_standard != this->color_standard) { + lprintf("vo_vdpau: update color_standard: %d\n", color_standard); + this->color_standard = color_standard; + vdpau_update_csc( this ); + } + + VdpRect vid_source, out_dest, vid_dest; + + vdpau_check_output_size( this_gen ); + vid_source.x0 = this->sc.displayed_xoffset; vid_source.y0 = this->sc.displayed_yoffset; + vid_source.x1 = this->sc.displayed_width+this->sc.displayed_xoffset; vid_source.y1 = this->sc.displayed_height+this->sc.displayed_yoffset; + out_dest.x0 = out_dest.y0 = 0; + out_dest.x1 = this->sc.gui_width; out_dest.y1 = this->sc.gui_height; + vid_dest.x0 = this->sc.output_xoffset; vid_dest.y0 = this->sc.output_yoffset; + vid_dest.x1 = this->sc.output_xoffset+this->sc.output_width; vid_dest.y1 = this->sc.output_yoffset+this->sc.output_height; + + /* prepare field delay calculation to not run into a deadlock while display locked */ + stream_speed = frame->vo_frame.stream ? xine_get_param(frame->vo_frame.stream, XINE_PARAM_FINE_SPEED) : 0; + if (stream_speed != 0) { + int vo_bufs_in_fifo = 0; + _x_query_buffer_usage(frame->vo_frame.stream, NULL, NULL, &vo_bufs_in_fifo, NULL); + /* fprintf(stderr, "vo_bufs: %d\n", vo_bufs_in_fifo); */ + if (vo_bufs_in_fifo <= 0) + stream_speed = 0; /* still image -> no delay */ + } + + VdpTime last_time; + + if ( this->init_queue>1 ) + vdp_queue_block( vdp_queue, this->output_surface[this->current_output_surface], &last_time ); + + uint32_t layer_count; + VdpLayer layer[3]; + VdpRect unscaledsrc; + if ( this->has_overlay ) { + layer_count = 2; + layer[0].struct_version = VDP_LAYER_VERSION; layer[0].source_surface = this->overlay_output; layer[0].source_rect = &vid_source; layer[0].destination_rect = &vid_dest; + unscaledsrc.x0 = 0; unscaledsrc.y0 = 0; unscaledsrc.x1 = this->overlay_unscaled_width; unscaledsrc.y1 = this->overlay_unscaled_height; + layer[1].struct_version = VDP_LAYER_VERSION; layer[1].source_surface = this->overlay_unscaled; layer[1].source_rect = &unscaledsrc; layer[1].destination_rect = &unscaledsrc; + } + else { + layer_count = 0; + } + + VdpRect argb_dest; + VdpRect argb_rect = { 0, 0, this->argb_overlay_width, this->argb_overlay_height }; + if( this->has_argb_overlay ) { + layer_count++; + memcpy(&argb_dest, &vid_dest, sizeof (vid_dest)); + layer[layer_count-1].destination_rect = &argb_dest; + layer[layer_count-1].source_rect = &argb_rect; + layer[layer_count-1].source_surface = this->argb_overlay; + layer[layer_count-1].struct_version = VDP_LAYER_VERSION; + /* recalculate video destination window to match osd's specified video window */ + if (this->video_window_width > 0 && this->video_window_height > 0) { + VdpRect win_rect = { this->video_window_x, this->video_window_y, this->video_window_x + this->video_window_width, this->video_window_y + this->video_window_height }; + vid_dest.x0 = ((win_rect.x0 - argb_rect.x0) * (argb_dest.x1 - argb_dest.x0) + argb_dest.x0 * (argb_rect.x1 - argb_rect.x0)) / (argb_rect.x1 - argb_rect.x0); + vid_dest.y0 = ((win_rect.y0 - argb_rect.y0) * (argb_dest.y1 - argb_dest.y0) + argb_dest.y0 * (argb_rect.y1 - argb_rect.y0)) / (argb_rect.y1 - argb_rect.y0); + vid_dest.x1 = ((win_rect.x1 - argb_rect.x0) * (argb_dest.x1 - argb_dest.x0) + argb_dest.x0 * (argb_rect.x1 - argb_rect.x0)) / (argb_rect.x1 - argb_rect.x0); + vid_dest.y1 = ((win_rect.y1 - argb_rect.y0) * (argb_dest.y1 - argb_dest.y0) + argb_dest.y0 * (argb_rect.y1 - argb_rect.y0)) / (argb_rect.y1 - argb_rect.y0); + } + } + + /* try to get frame duration from previous img->pts when frame->duration is 0 */ + int frame_duration = frame->vo_frame.duration; + if ( !frame_duration && this->back_frame[0] ) { + int duration = frame->vo_frame.pts - this->back_frame[0]->vo_frame.pts; + if ( duration>0 && duration<4000 ) + frame_duration = duration; + } + int non_progressive = (this->honor_progressive && !frame->vo_frame.progressive_frame) || !this->honor_progressive; + +#ifdef LOCKDISPLAY + XLockDisplay( this->display ); +#endif + + if ( frame->format==XINE_IMGFMT_VDPAU && this->deinterlace && non_progressive /*&& stream_speed*/ && frame_duration>2500 ) { + VdpTime current_time = 0; + VdpVideoSurface past[2]; + VdpVideoSurface future[1]; + VdpVideoMixerPictureStructure picture_structure; + + past[1] = past[0] = (this->back_frame[0] && (this->back_frame[0]->format==XINE_IMGFMT_VDPAU)) ? this->back_frame[0]->vdpau_accel_data.surface : VDP_INVALID_HANDLE; + future[0] = surface; + picture_structure = ( frame->vo_frame.top_field_first ) ? VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD : VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD; + + st = vdp_video_mixer_render( this->video_mixer, VDP_INVALID_HANDLE, 0, picture_structure, + 2, past, surface, 1, future, &vid_source, this->output_surface[this->current_output_surface], &out_dest, &vid_dest, layer_count, layer_count?layer:NULL ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: vdp_video_mixer_render error : %s\n", vdp_get_error_string( st ) ); + + vdp_queue_get_time( vdp_queue, ¤t_time ); + vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, 0 ); /* display _now_ */ + vdpau_shift_queue( this_gen ); + + int dm = this->deinterlacers_method[this->deinterlace_method]; + if ( (dm != DEINT_HALF_TEMPORAL) && (dm != DEINT_HALF_TEMPORAL_SPATIAL) && frame->vo_frame.future_frame ) { /* process second field */ + if ( this->init_queue>1 ) { +#ifdef LOCKDISPLAY + XUnlockDisplay(this->display); +#endif + vdp_queue_block( vdp_queue, this->output_surface[this->current_output_surface], &last_time ); +#ifdef LOCKDISPLAY + XLockDisplay(this->display); +#endif + } + + vdpau_check_output_size( this_gen ); + + picture_structure = ( frame->vo_frame.top_field_first ) ? VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD : VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; + past[0] = surface; + if ( frame->vo_frame.future_frame!=NULL && ((vdpau_frame_t*)(frame->vo_frame.future_frame))->format==XINE_IMGFMT_VDPAU ) + future[0] = ((vdpau_frame_t*)(frame->vo_frame.future_frame))->vdpau_accel_data.surface; + else + future[0] = VDP_INVALID_HANDLE; + + st = vdp_video_mixer_render( this->video_mixer, VDP_INVALID_HANDLE, 0, picture_structure, + 2, past, surface, 1, future, &vid_source, this->output_surface[this->current_output_surface], &out_dest, &vid_dest, layer_count, layer_count?layer:NULL ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: vdp_video_mixer_render error : %s\n", vdp_get_error_string( st ) ); + + /* calculate delay for second field: there should be no delay for still images otherwise, take replay speed into account */ + if (stream_speed > 0) + current_time += frame->vo_frame.duration * 1000000ull * XINE_FINE_SPEED_NORMAL / (180 * stream_speed); + else + current_time = 0; /* immediately i. e. no delay */ + + //current_time = 0; + //printf( "vo_vdpau: deint delay = %d\n", frame_duration *1ull * XINE_FINE_SPEED_NORMAL / (180 * stream_speed) ); + vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, current_time ); + vdpau_shift_queue( this_gen ); + } + } + else { + st = vdp_video_mixer_render( this->video_mixer, VDP_INVALID_HANDLE, 0, VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME, + 0, 0, surface, 0, 0, &vid_source, this->output_surface[this->current_output_surface], &out_dest, &vid_dest, layer_count, layer_count?layer:NULL ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: vdp_video_mixer_render error : %s\n", vdp_get_error_string( st ) ); + + vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, 0 ); + vdpau_shift_queue( this_gen ); + } + +#ifdef LOCKDISPLAY + XUnlockDisplay( this->display ); +#endif + + if ( stream_speed ) /* do not release past frame if paused, it will be used for redrawing */ + vdpau_backup_frame( this_gen, frame_gen ); + else + frame->vo_frame.free( &frame->vo_frame ); +} + + + +static int vdpau_get_property (vo_driver_t *this_gen, int property) +{ + vdpau_driver_t *this = (vdpau_driver_t*)this_gen; + + switch (property) { + case VO_PROP_MAX_NUM_FRAMES: + return 30; + case VO_PROP_WINDOW_WIDTH: + return this->sc.gui_width; + case VO_PROP_WINDOW_HEIGHT: + return this->sc.gui_height; + case VO_PROP_OUTPUT_WIDTH: + return this->sc.output_width; + case VO_PROP_OUTPUT_HEIGHT: + return this->sc.output_height; + case VO_PROP_OUTPUT_XOFFSET: + return this->sc.output_xoffset; + case VO_PROP_OUTPUT_YOFFSET: + return this->sc.output_yoffset; + case VO_PROP_HUE: + return this->hue; + case VO_PROP_SATURATION: + return this->saturation; + case VO_PROP_CONTRAST: + return this->contrast; + case VO_PROP_BRIGHTNESS: + return this->brightness; + case VO_PROP_SHARPNESS: + return this->sharpness; + case VO_PROP_NOISE_REDUCTION: + return this->noise; + case VO_PROP_ZOOM_X: + return this->zoom_x; + case VO_PROP_ZOOM_Y: + return this->zoom_y; + case VO_PROP_ASPECT_RATIO: + return this->sc.user_ratio; + } + + return -1; +} + + + +static int vdpau_set_property (vo_driver_t *this_gen, int property, int value) +{ + vdpau_driver_t *this = (vdpau_driver_t*)this_gen; + + printf("vdpau_set_property: property=%d, value=%d\n", property, value ); + + switch (property) { + case VO_PROP_INTERLACED: + this->deinterlace = value; + vdpau_set_deinterlace( this_gen ); + break; + case VO_PROP_ZOOM_X: + if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { + this->zoom_x = value; + this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP; + _x_vo_scale_compute_ideal_size( &this->sc ); + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + break; + case VO_PROP_ZOOM_Y: + if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { + this->zoom_y = value; + this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP; + _x_vo_scale_compute_ideal_size( &this->sc ); + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + break; + case VO_PROP_ASPECT_RATIO: + if ( value>=XINE_VO_ASPECT_NUM_RATIOS ) + value = XINE_VO_ASPECT_AUTO; + this->sc.user_ratio = value; + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + break; + case VO_PROP_HUE: this->hue = value; vdpau_update_csc( this ); break; + case VO_PROP_SATURATION: this->saturation = value; vdpau_update_csc( this ); break; + case VO_PROP_CONTRAST: this->contrast = value; vdpau_update_csc( this ); break; + case VO_PROP_BRIGHTNESS: this->brightness = value; vdpau_update_csc( this ); break; + case VO_PROP_SHARPNESS: this->sharpness = value; vdpau_update_sharpness( this ); break; + case VO_PROP_NOISE_REDUCTION: this->noise = value; vdpau_update_noise( this ); break; + } + + return value; +} + + + +static void vdpau_get_property_min_max (vo_driver_t *this_gen, int property, int *min, int *max) +{ + switch ( property ) { + case VO_PROP_HUE: + *max = 314; *min = -314; break; + case VO_PROP_SATURATION: + *max = 1000; *min = 0; break; + case VO_PROP_CONTRAST: + *max = 1000; *min = 0; break; + case VO_PROP_BRIGHTNESS: + *max = 100; *min = -100; break; + case VO_PROP_SHARPNESS: + *max = 100; *min = -100; break; + case VO_PROP_NOISE_REDUCTION: + *max = 100; *min = 0; break; + default: + *max = 0; *min = 0; + } +} + + + +static int vdpau_gui_data_exchange (vo_driver_t *this_gen, int data_type, void *data) +{ + vdpau_driver_t *this = (vdpau_driver_t*)this_gen; + + switch (data_type) { +#ifndef XINE_DISABLE_DEPRECATED_FEATURES + case XINE_GUI_SEND_COMPLETION_EVENT: + break; +#endif + + case XINE_GUI_SEND_EXPOSE_EVENT: { + if ( this->init_queue ) { +#ifdef LOCKDISPLAY + XLockDisplay( this->display ); +#endif + int previous = this->current_output_surface - 1; + if ( previous < 0 ) + previous = NOUTPUTSURFACE - 1; + vdp_queue_display( vdp_queue, this->output_surface[previous], 0, 0, 0 ); +#ifdef LOCKDISPLAY + XUnlockDisplay( this->display ); +#endif + } + break; + } + + case XINE_GUI_SEND_DRAWABLE_CHANGED: { + VdpStatus st; +#ifdef LOCKDISPLAY + XLockDisplay( this->display ); +#endif + this->drawable = (Drawable) data; + vdp_queue_destroy( vdp_queue ); + vdp_queue_target_destroy( vdp_queue_target ); + st = vdp_queue_target_create_x11( vdp_device, this->drawable, &vdp_queue_target ); + if ( st != VDP_STATUS_OK ) { + printf( "vo_vdpau: FATAL !! Can't recreate presentation queue target after drawable change !!\n" ); +#ifdef LOCKDISPLAY + XUnlockDisplay( this->display ); +#endif + break; + } + st = vdp_queue_create( vdp_device, vdp_queue_target, &vdp_queue ); + if ( st != VDP_STATUS_OK ) { + printf( "vo_vdpau: FATAL !! Can't recreate presentation queue after drawable change !!\n" ); +#ifdef LOCKDISPLAY + XUnlockDisplay( this->display ); +#endif + break; + } + vdp_queue_set_background_color( vdp_queue, &this->back_color ); +#ifdef LOCKDISPLAY + XUnlockDisplay( this->display ); +#endif + this->sc.force_redraw = 1; + break; + } + + case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: { + int x1, y1, x2, y2; + x11_rectangle_t *rect = data; + + _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, &x1, &y1); + _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, &x2, &y2); + rect->x = x1; + rect->y = y1; + rect->w = x2-x1; + rect->h = y2-y1; + break; + } + + default: + return -1; + } + + return 0; +} + + + +static uint32_t vdpau_get_capabilities (vo_driver_t *this_gen) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + return this->capabilities; +} + + + +static void vdpau_dispose (vo_driver_t *this_gen) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + int i; + + this->ovl_yuv2rgb->dispose(this->ovl_yuv2rgb); + this->yuv2rgb_factory->dispose (this->yuv2rgb_factory); + + for ( i=0; i<XINE_VORAW_MAX_OVL; ++i ) { + if ( this->overlays[i].ovl_bitmap != VDP_INVALID_HANDLE ) + vdp_bitmap_destroy( this->overlays[i].ovl_bitmap ); + } + + if ( this->video_mixer!=VDP_INVALID_HANDLE ) + vdp_video_mixer_destroy( this->video_mixer ); + if ( this->soft_surface != VDP_INVALID_HANDLE ) + vdp_video_surface_destroy( this->soft_surface ); + + if ( vdp_output_surface_destroy ) { + if (this->argb_overlay != VDP_INVALID_HANDLE) + vdp_output_surface_destroy(this->argb_overlay); + if ( this->overlay_unscaled!=VDP_INVALID_HANDLE ) + vdp_output_surface_destroy( this->overlay_unscaled ); + if ( this->overlay_output!=VDP_INVALID_HANDLE ) + vdp_output_surface_destroy( this->overlay_output ); + for ( i=0; i<NOUTPUTSURFACE; ++i ) { + if ( this->output_surface[i]!=VDP_INVALID_HANDLE ) + vdp_output_surface_destroy( this->output_surface[i] ); + } + } + + if ( vdp_queue != VDP_INVALID_HANDLE ) + vdp_queue_destroy( vdp_queue ); + if ( vdp_queue_target != VDP_INVALID_HANDLE ) + vdp_queue_target_destroy( vdp_queue_target ); + + for ( i=0; i<NUM_FRAMES_BACK; i++ ) + if ( this->back_frame[i] ) + this->back_frame[i]->vo_frame.dispose( &this->back_frame[i]->vo_frame ); + + if ( (vdp_device != VDP_INVALID_HANDLE) && vdp_device_destroy ) + vdp_device_destroy( vdp_device ); + + free (this); +} + + + +static int vdpau_reinit_error( VdpStatus st, const char *msg ) +{ + if ( st != VDP_STATUS_OK ) { + printf( "vo_vdpau: %s : %s\n", msg, vdp_get_error_string( st ) ); + return 1; + } + return 0; +} + + + +static void vdpau_reinit( vo_driver_t *this_gen ) +{ + printf("vo_vdpau: VDPAU was pre-empted. Reinit.\n"); + vdpau_driver_t *this = (vdpau_driver_t *)this_gen; + +#ifdef LOCKDISPLAY + XLockDisplay(guarded_display); +#endif + vdpau_release_back_frames(this_gen); + + VdpStatus st = vdp_device_create_x11( this->display, this->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" ); + return; + } + + st = vdp_queue_target_create_x11( vdp_device, this->drawable, &vdp_queue_target ); + if ( vdpau_reinit_error( st, "Can't create presentation queue target !!" ) ) + return; + st = vdp_queue_create( vdp_device, vdp_queue_target, &vdp_queue ); + if ( vdpau_reinit_error( st, "Can't create presentation queue !!" ) ) + return; + vdp_queue_set_background_color( vdp_queue, &this->back_color ); + + + VdpChromaType chroma = VDP_CHROMA_TYPE_420; + st = orig_vdp_video_surface_create( vdp_device, chroma, this->soft_surface_width, this->soft_surface_height, &this->soft_surface ); + if ( vdpau_reinit_error( st, "Can't create video surface !!" ) ) + return; + + this->current_output_surface = 0; + this->init_queue = 0; + int i; + for ( i=0; i<NOUTPUTSURFACE; ++i ) { + st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->output_surface_width[i], this->output_surface_height[i], &this->output_surface[i] ); + if ( vdpau_reinit_error( st, "Can't create output surface !!" ) ) { + int j; + for ( j=0; j<i; ++j ) + vdp_output_surface_destroy( this->output_surface[j] ); + vdp_video_surface_destroy( this->soft_surface ); + return; + } + } + + /* osd overlays need to be recreated */ + for ( i=0; i<XINE_VORAW_MAX_OVL; ++i ) { + this->overlays[i].ovl_bitmap = VDP_INVALID_HANDLE; + this->overlays[i].bitmap_width = 0; + this->overlays[i].bitmap_height = 0; + } + this->overlay_output = VDP_INVALID_HANDLE; + this->overlay_output_width = this->overlay_output_height = 0; + this->overlay_unscaled = VDP_INVALID_HANDLE; + this->overlay_unscaled_width = this->overlay_unscaled_height = 0; + this->ovl_changed = 0; + this->has_overlay = 0; + this->has_unscaled = 0; + + this->argb_overlay = VDP_INVALID_HANDLE; + this->argb_overlay_width = this->argb_overlay_height = 0; + this->has_argb_overlay = 0; + + VdpVideoMixerFeature features[15]; + int features_count = 0; + if ( this->noise_reduction_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; + ++features_count; + } + if ( this->sharpness_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS; + ++features_count; + } + if ( this->temporal_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL; + ++features_count; + } + if ( this->temporal_spatial_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL; + ++features_count; + } + if ( this->inverse_telecine_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE; + ++features_count; + } +#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + for ( i=0; i<this->scaling_level_max; ++i ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + i; + ++features_count; + } +#endif + VdpVideoMixerParameter params[] = { VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE, VDP_VIDEO_MIXER_PARAMETER_LAYERS }; + int num_layers = 3; + void const *param_values[] = { &this->video_mixer_width, &this->video_mixer_height, &chroma, &num_layers }; + st = vdp_video_mixer_create( vdp_device, features_count, features, 4, params, param_values, &this->video_mixer ); + if ( vdpau_reinit_error( st, "Can't create video mixer !!" ) ) { + orig_vdp_video_surface_destroy( this->soft_surface ); + for ( i=0; i<NOUTPUTSURFACE; ++i ) + vdp_output_surface_destroy( this->output_surface[i] ); + return; + } + this->video_mixer_chroma = chroma; + vdpau_set_deinterlace( this_gen ); + vdpau_set_scaling_level( this_gen ); + vdpau_set_inverse_telecine( this_gen ); + vdpau_update_noise( this ); + vdpau_update_sharpness( this ); + vdpau_update_csc( this ); + vdpau_update_skip_chroma( this ); + + vdp_preemption_callback_register(vdp_device, &vdp_preemption_callback, (void*)this); + + this->vdp_runtime_nr++; + this->reinit_needed = 0; +#ifdef LOCKDISPLAY + XUnlockDisplay(guarded_display); +#endif + printf("vo_vdpau: Reinit done.\n"); +} + + + +static void vdp_preemption_callback(VdpDevice device, void *context) +{ + printf("vo_vdpau: VDPAU preemption callback\n"); + vdpau_driver_t *this = (vdpau_driver_t *)context; + this->reinit_needed = 1; +} + + + +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; + + guarded_display = visual->display; + this->display = visual->display; + this->screen = visual->screen; + this->drawable = visual->d; + + _x_vo_scale_init(&this->sc, 1, 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->zoom_x = 100; + this->zoom_y = 100; + + 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->video_mixer = VDP_INVALID_HANDLE; + for ( i=0; i<NOUTPUTSURFACE; ++i ) + this->output_surface[i] = VDP_INVALID_HANDLE; + this->soft_surface = VDP_INVALID_HANDLE; + vdp_queue = VDP_INVALID_HANDLE; + vdp_queue_target = VDP_INVALID_HANDLE; + vdp_device = VDP_INVALID_HANDLE; + + vdp_output_surface_destroy = NULL; + vdp_device_destroy = NULL; + + this->sharpness_is_supported = 0; + this->noise_reduction_is_supported = 0; + this->temporal_is_supported = 0; + this->temporal_spatial_is_supported = 0; + this->inverse_telecine_is_supported = 0; + this->skip_chroma_is_supported = 0; + + for ( i=0; i<XINE_VORAW_MAX_OVL; ++i ) { + this->overlays[i].ovl_w = this->overlays[i].ovl_h = 0; + this->overlays[i].bitmap_width = this->overlays[i].bitmap_height = 0; + this->overlays[i].ovl_bitmap = VDP_INVALID_HANDLE; + this->overlays[i].ovl_x = this->overlays[i].ovl_y = 0; + } + this->overlay_output = VDP_INVALID_HANDLE; + this->overlay_output_width = this->overlay_output_height = 0; + this->overlay_unscaled = VDP_INVALID_HANDLE; + this->overlay_unscaled_width = this->overlay_unscaled_height = 0; + this->ovl_changed = 0; + this->has_overlay = 0; + this->has_unscaled = 0; + + this->argb_overlay = VDP_INVALID_HANDLE; + this->argb_overlay_width = this->argb_overlay_height = 0; + this->has_argb_overlay = 0; + + /* overlay converter */ + this->yuv2rgb_factory = yuv2rgb_factory_init (MODE_24_BGR, 0, NULL); + this->ovl_yuv2rgb = this->yuv2rgb_factory->create_converter( this->yuv2rgb_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_DEVICE_DESTROY , (void*)&vdp_device_destroy ); + if ( vdpau_init_error( st, "Can't get DEVICE_DESTROY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE , (void*)&orig_vdp_video_surface_create ); vdp_video_surface_create = guarded_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*)&orig_vdp_video_surface_destroy ); vdp_video_surface_destroy = guarded_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_VIDEO_SURFACE_GET_BITS_Y_CB_CR , (void*)&vdp_video_surface_getbits_ycbcr ); + if ( vdpau_init_error( st, "Can't get VIDEO_SURFACE_GET_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_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE , (void*)&vdp_output_surface_render_bitmap_surface ); + if ( vdpau_init_error( st, "Can't get OUTPUT_SURFACE_RENDER_BITMAP_SURFACE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , (void*)&vdp_output_surface_put_bits ); + if ( vdpau_init_error( st, "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE 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_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , (void*)&vdp_video_mixer_set_attribute_values ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_SET_ATTRIBUTE_VALUES proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , (void*)&vdp_video_mixer_set_feature_enables ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_SET_FEATURE_ENABLES proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_ENABLES , (void*)&vdp_video_mixer_get_feature_enables ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_GET_FEATURE_ENABLES proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , (void*)&vdp_video_mixer_query_feature_support ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_QUERY_FEATURE_SUPPORT proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , (void*)&vdp_video_mixer_query_parameter_support ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_QUERY_PARAMETER_SUPPORT proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT , (void*)&vdp_video_mixer_query_attribute_support ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE , (void*)&vdp_video_mixer_query_parameter_value_range ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE , (void*)&vdp_video_mixer_query_attribute_value_range ); + if ( vdpau_init_error( st, "Can't get VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_GENERATE_CSC_MATRIX , (void*)&vdp_generate_csc_matrix ); + if ( vdpau_init_error( st, "Can't get GENERATE_CSC_MATRIX 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_BLOCK_UNTIL_SURFACE_IDLE , (void*)&vdp_queue_block ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE 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_background_color ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_SET_BACKGROUND_COLOR proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , (void*)&vdp_queue_get_time ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_GET_TIME proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , (void*)&vdp_queue_query_surface_status ); + if ( vdpau_init_error( st, "Can't get PRESENTATION_QUEUE_QUERY_SURFACE_STATUS proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , (void*)&vdp_decoder_query_capabilities ); + if ( vdpau_init_error( st, "Can't get DECODER_QUERY_CAPABILITIES proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_DECODER_CREATE , (void*)&orig_vdp_decoder_create ); vdp_decoder_create = guarded_vdp_decoder_create; + if ( vdpau_init_error( st, "Can't get DECODER_CREATE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_DECODER_DESTROY , (void*)&orig_vdp_decoder_destroy ); vdp_decoder_destroy = guarded_vdp_decoder_destroy; + if ( vdpau_init_error( st, "Can't get DECODER_DESTROY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_DECODER_RENDER , (void*)&orig_vdp_decoder_render ); vdp_decoder_render = guarded_vdp_decoder_render; + if ( vdpau_init_error( st, "Can't get DECODER_RENDER proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_BITMAP_SURFACE_CREATE , (void*)&vdp_bitmap_create ); + if ( vdpau_init_error( st, "Can't get BITMAP_SURFACE_CREATE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_BITMAP_SURFACE_DESTROY , (void*)&vdp_bitmap_destroy ); + if ( vdpau_init_error( st, "Can't get BITMAP_SURFACE_DESTROY proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE , (void*)&vdp_bitmap_put_bits ); + if ( vdpau_init_error( st, "Can't get BITMAP_SURFACE_PUT_BITS_NATIVE proc address !!", &this->vo_driver, 1 ) ) + return NULL; + st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER, (void*)&vdp_preemption_callback_register ); + if ( vdpau_init_error( st, "Can't get PREEMPTION_CALLBACK_REGISTER proc address !!", &this->vo_driver, 1 ) ) + return NULL; + + st = vdp_preemption_callback_register(vdp_device, &vdp_preemption_callback, (void*)this); + if ( vdpau_init_error( st, "Can't register preemption callback !!", &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; + + /* choose almost black as backcolor for color keying */ + this->back_color.red = 0.02; + this->back_color.green = 0.01; + this->back_color.blue = 0.03; + this->back_color.alpha = 1; + vdp_queue_set_background_color( vdp_queue, &this->back_color ); + + this->soft_surface_width = 320; + this->soft_surface_height = 240; + this->soft_surface_format = XINE_IMGFMT_YV12; + VdpChromaType chroma = VDP_CHROMA_TYPE_420; + st = vdp_video_surface_create( vdp_device, chroma, 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; + + for ( i=0; i<NOUTPUTSURFACE; ++i ) { + this->output_surface_width[i] = 320; + this->output_surface_height[i] = 240; + } + this->current_output_surface = 0; + this->init_queue = 0; + for ( i=0; i<NOUTPUTSURFACE; ++i ) { + st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, this->output_surface_width[i], this->output_surface_height[i], &this->output_surface[i] ); + if ( vdpau_init_error( st, "Can't create output surface !!", &this->vo_driver, 1 ) ) { + int j; + for ( j=0; j<i; ++j ) + vdp_output_surface_destroy( this->output_surface[j] ); + vdp_video_surface_destroy( this->soft_surface ); + return NULL; + } + } + + this->scaling_level_max = this->scaling_level_current = 0; +#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + VdpBool hqscaling; + for ( i=0; i<9; ++i ) { + st = vdp_video_mixer_query_feature_support( vdp_device, VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + i, &hqscaling ); + if ( ( st != VDP_STATUS_OK ) || !hqscaling ) { + //printf("unsupported scaling quality=%d\n", i); + break; + } + else { + //printf("supported scaling quality=%d\n", i); + ++this->scaling_level_max; + } + } +#endif + + vdp_video_mixer_query_feature_support( vdp_device, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL, &this->temporal_is_supported ); + vdp_video_mixer_query_feature_support( vdp_device, VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL, &this->temporal_spatial_is_supported ); + vdp_video_mixer_query_feature_support( vdp_device, VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION, &this->noise_reduction_is_supported ); + vdp_video_mixer_query_feature_support( vdp_device, VDP_VIDEO_MIXER_FEATURE_SHARPNESS, &this->sharpness_is_supported ); + vdp_video_mixer_query_feature_support( vdp_device, VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE, &this->inverse_telecine_is_supported ); + vdp_video_mixer_query_attribute_support( vdp_device, VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE, &this->skip_chroma_is_supported ); + + this->color_standard = VDP_COLOR_STANDARD_ITUR_BT_601; + this->video_mixer_chroma = chroma; + this->video_mixer_width = this->soft_surface_width; + this->video_mixer_height = this->soft_surface_height; + VdpVideoMixerFeature features[15]; + int features_count = 0; + if ( this->noise_reduction_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; + ++features_count; + } + if ( this->sharpness_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS; + ++features_count; + } + if ( this->temporal_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL; + ++features_count; + } + if ( this->temporal_spatial_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL; + ++features_count; + } + if ( this->inverse_telecine_is_supported ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE; + ++features_count; + } +#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + for ( i=0; i<this->scaling_level_max; ++i ) { + features[features_count] = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + i; + ++features_count; + } +#endif + VdpVideoMixerParameter params[] = { VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, + VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE, VDP_VIDEO_MIXER_PARAMETER_LAYERS }; + int num_layers = 3; + void const *param_values[] = { &this->video_mixer_width, &this->video_mixer_height, &chroma, &num_layers }; + st = vdp_video_mixer_create( vdp_device, features_count, features, 4, 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 ); + for ( i=0; i<NOUTPUTSURFACE; ++i ) + vdp_output_surface_destroy( this->output_surface[i] ); + return NULL; + } + + char deinterlacers_description[1024]; + memset( deinterlacers_description, 0, 1024 ); + int deint_count = 0; + int deint_default = 0; + this->deinterlacers_name[deint_count] = vdpau_deinterlacer_name[0]; + this->deinterlacers_method[deint_count] = DEINT_BOB; + strcat( deinterlacers_description, vdpau_deinterlacer_description[0] ); + ++deint_count; + if ( this->temporal_is_supported ) { + this->deinterlacers_name[deint_count] = vdpau_deinterlacer_name[1]; + this->deinterlacers_method[deint_count] = DEINT_HALF_TEMPORAL; + strcat( deinterlacers_description, vdpau_deinterlacer_description[1] ); + ++deint_count; + } + if ( this->temporal_spatial_is_supported ) { + this->deinterlacers_name[deint_count] = vdpau_deinterlacer_name[2]; + this->deinterlacers_method[deint_count] = DEINT_HALF_TEMPORAL_SPATIAL; + strcat( deinterlacers_description, vdpau_deinterlacer_description[2] ); + ++deint_count; + } + if ( this->temporal_is_supported ) { + this->deinterlacers_name[deint_count] = vdpau_deinterlacer_name[3]; + this->deinterlacers_method[deint_count] = DEINT_TEMPORAL; + strcat( deinterlacers_description, vdpau_deinterlacer_description[3] ); + deint_default = deint_count; + ++deint_count; + } + if ( this->temporal_spatial_is_supported ) { + this->deinterlacers_name[deint_count] = vdpau_deinterlacer_name[4]; + this->deinterlacers_method[deint_count] = DEINT_TEMPORAL_SPATIAL; + strcat( deinterlacers_description, vdpau_deinterlacer_description[4] ); + ++deint_count; + } + this->deinterlacers_name[deint_count] = NULL; + + if ( this->scaling_level_max ) { + this->scaling_level_current = config->register_range( config, "video.output.vdpau_scaling_quality", 0, + 0, this->scaling_level_max, _("vdpau: Scaling Quality"), + _("Scaling Quality Level"), + 10, vdpau_update_scaling_level, this ); + } + + this->deinterlace_method = config->register_enum( config, "video.output.vdpau_deinterlace_method", deint_default, + this->deinterlacers_name, _("vdpau: HD deinterlace method"), + deinterlacers_description, + 10, vdpau_update_deinterlace_method, this ); + + if ( this->inverse_telecine_is_supported ) { + this->enable_inverse_telecine = config->register_bool( config, "video.output.vdpau_enable_inverse_telecine", 1, + _("vdpau: Try to recreate progressive frames from pulldown material"), + _("Enable this to detect bad-flagged progressive content to which\n" + "a 2:2 or 3:2 pulldown was applied.\n\n"), + 10, vdpau_update_enable_inverse_telecine, this ); + } + + this->honor_progressive = config->register_bool( config, "video.output.vdpau_honor_progressive", 0, + _("vdpau: disable deinterlacing when progressive_frame flag is set"), + _("Set to true if you want to trust the progressive_frame stream's flag.\n" + "This flag is not always reliable.\n\n"), + 10, vdpau_honor_progressive_flag, this ); + + if ( this->skip_chroma_is_supported ) { + this->skip_chroma = config->register_bool( config, "video.output.vdpau_skip_chroma_deinterlace", 0, + _("vdpau: disable advanced deinterlacers chroma filter"), + _("Setting to true may help if your video card isn't able to run advanced deinterlacers.\n\n"), + 10, vdpau_set_skip_chroma, this ); + } + + this->studio_levels = config->register_bool( config, "video.output.vdpau_studio_levels", 0, + _("vdpau: disable studio level"), + _("Setting to true enables studio levels (16-219) instead of PC levels (0-255) in RGB colors.\n\n"), + 10, vdpau_set_studio_levels, this ); + + /* number of video frames from config - register it with the default value. */ + int frame_num = config->register_num (config, "engine.buffers.video_num_frames", 15, /* default */ + _("default number of video frames"), + _("The default number of video frames to request " + "from xine video out driver. Some drivers will " + "override this setting with their own values."), + 20, NULL, this); + + /* now make sure we have at least 22 frames, to prevent + * locks with vdpau_h264 */ + if(frame_num < 22) + config->update_num(config,"engine.buffers.video_num_frames",22); + + this->capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP | VO_CAP_UNSCALED_OVERLAY | VO_CAP_CUSTOM_EXTENT_OVERLAY | VO_CAP_ARGB_LAYER_OVERLAY | VO_CAP_VIDEO_WINDOW_OVERLAY; + ok = 0; + uint32_t mw, mh, ml, mr; + st = vdp_decoder_query_capabilities( vdp_device, VDP_DECODER_PROFILE_H264_MAIN, &ok, &ml, &mr, &mw, &mh ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: getting h264_supported failed! : %s\n", vdp_get_error_string( st ) ); + else if ( !ok ) + printf( "vo_vdpau: this hardware doesn't support h264.\n" ); + else + this->capabilities |= VO_CAP_VDPAU_H264; + + st = vdp_decoder_query_capabilities( vdp_device, VDP_DECODER_PROFILE_VC1_MAIN, &ok, &ml, &mr, &mw, &mh ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: getting vc1_supported failed! : %s\n", vdp_get_error_string( st ) ); + else if ( !ok ) + printf( "vo_vdpau: this hardware doesn't support vc1.\n" ); + else + this->capabilities |= VO_CAP_VDPAU_VC1; + + st = vdp_decoder_query_capabilities( vdp_device, VDP_DECODER_PROFILE_MPEG2_MAIN, &ok, &ml, &mr, &mw, &mh ); + if ( st != VDP_STATUS_OK ) + printf( "vo_vdpau: getting mpeg12_supported failed! : %s\n", vdp_get_error_string( st ) ); + else if ( !ok ) + printf( "vo_vdpau: this hardware doesn't support mpeg1/2.\n" ); + else + this->capabilities |= VO_CAP_VDPAU_MPEG12; + + for ( i=0; i<NUM_FRAMES_BACK; i++) + this->back_frame[i] = NULL; + + this->hue = 0; + this->saturation = 100; + this->contrast = 100; + this->brightness = 0; + this->sharpness = 0; + this->noise = 0; + this->deinterlace = 0; + + this->allocated_surfaces = 0; + + this->vdp_runtime_nr = 1; + + return &this->vo_driver; +} + +/* + * class functions + */ + +static char* vdpau_get_identifier (video_driver_class_t *this_gen) +{ +} + + + +static char* vdpau_get_description (video_driver_class_t *this_gen) +{ +} + + + +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.identifier = "vdpau"; + this->driver_class.description = N_("xine video output plugin using VDPAU hardware acceleration"); + this->driver_class.dispose = default_video_driver_class_dispose; + 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, 22, "vdpau", XINE_VERSION_CODE, &vo_info_vdpau, vdpau_init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c index a10e8bd36..0856cd308 100644 --- a/src/video_out/video_out_xv.c +++ b/src/video_out/video_out_xv.c @@ -778,6 +778,8 @@ static int xv_set_property (vo_driver_t *this_gen, int property, int value) { xv_driver_t *this = (xv_driver_t *) this_gen; + printf("xv_set_property: property=%d, value=%d\n", property, value ); + if (this->props[property].atom != None) { /* value is out of bound */ |