diff -Naur xine-lib-1.2_orig/include/xine/vdr.h xine-lib-1.2/include/xine/vdr.h --- xine-lib-1.2_orig/include/xine/vdr.h 2010-01-24 22:47:00.000000000 +0100 +++ xine-lib-1.2/include/xine/vdr.h 2010-01-24 22:52:20.108397432 +0100 @@ -45,6 +45,7 @@ , func_start , func_wait , func_setup + , func_grab_image_vdpau , func_grab_image , func_get_pts , func_flush @@ -412,6 +413,19 @@ +typedef struct __attribute__((packed)) data_grab_image_vdpau_s +{ + data_header_t header; + + uint16_t width; + uint16_t height; + uint16_t jpeg; + uint16_t quality; +} +data_grab_image_vdpau_t; + + + typedef struct __attribute__((packed)) data_grab_image_s { data_header_t header; @@ -616,6 +630,7 @@ data_start_t start; data_wait_t wait; data_setup_t setup; + data_grab_image_vdpau_t grab_image_vdpau; data_grab_image_t grab_image; data_get_pts_t get_pts; data_first_frame_t first_frame; diff -Naur xine-lib-1.2_orig/include/xine.h xine-lib-1.2/include/xine.h --- xine-lib-1.2_orig/include/xine.h 2010-01-24 22:47:00.000000000 +0100 +++ xine-lib-1.2/include/xine.h 2010-01-24 22:52:20.108397432 +0100 @@ -1392,6 +1392,28 @@ #endif /* WIN32 */ + +/* + * frame structure used for grabbing raw RGB output frames + */ +typedef struct { + /* Cropping of source image */ + int crop_left; + int crop_right; + int crop_top; + int crop_bottom; + + /* Parameters of returned image */ + int width; + int height; + uint8_t *img; + uint64_t vpts; + + int timeout; /* Max. time to wait for next frame in milliseconds */ + +} xine_grab_frame_t; + + /* * "type" constants for xine_port_send_gui_data(...) */ @@ -1421,6 +1443,18 @@ /* Gui is about to destroy drawable */ #define XINE_GUI_SEND_WILL_DESTROY_DRAWABLE 9 +/* Allocate grab frame */ +/* xine_grab_frame_t **data */ +#define XINE_GUI_SEND_ALLOC_GRAB_FRAME 10 + +/* Free grab frame */ +/* xine_grab_frame_t *data */ +#define XINE_GUI_SEND_FREE_GRAB_FRAME 11 + +/* Grab image of last displayed frame */ +/* xine_grab_frame_t *data */ +#define XINE_GUI_SEND_GRAB_FRAME 12 + /********************************************************************* * xine health check stuff * diff -Naur xine-lib-1.2_orig/src/vdr/Makefile.am xine-lib-1.2/src/vdr/Makefile.am --- xine-lib-1.2_orig/src/vdr/Makefile.am 2010-01-24 22:47:07.000000000 +0100 +++ xine-lib-1.2/src/vdr/Makefile.am 2010-01-24 22:52:20.118397559 +0100 @@ -9,4 +9,5 @@ endif xineplug_vdr_la_SOURCES = combined_vdr.c combined_vdr.h input_vdr.c post_vdr_video.c post_vdr_audio.c -xineplug_vdr_la_LIBADD = $(XINE_LIB) $(PTHREAD_LIBS) +xineplug_vdr_la_LIBADD = $(XINE_LIB) $(PTHREAD_LIBS) -ljpeg + diff -Naur xine-lib-1.2_orig/src/vdr/input_vdr.c xine-lib-1.2/src/vdr/input_vdr.c --- xine-lib-1.2_orig/src/vdr/input_vdr.c 2010-01-24 22:47:10.000000000 +0100 +++ xine-lib-1.2/src/vdr/input_vdr.c 2010-01-24 22:52:20.118397559 +0100 @@ -50,6 +50,14 @@ +#ifdef boolean +# define HAVE_BOOLEAN +#endif +#include +#undef boolean + + + #define VDR_MAX_NUM_WINDOWS 16 #define VDR_ABS_FIFO_DIR "/var/vdr/xine" @@ -184,6 +192,53 @@ +#define JPEGCOMPRESSMEM 500000 + +typedef struct tJpegCompressData_s { + int size; + unsigned char *mem; +} tJpegCompressData; + +static void JpegCompressInitDestination(const j_compress_ptr cinfo) +{ + tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; + if (jcd) { + cinfo->dest->free_in_buffer = jcd->size = JPEGCOMPRESSMEM; + cinfo->dest->next_output_byte = jcd->mem = + (unsigned char *)malloc(jcd->size); + } +} + +static boolean JpegCompressEmptyOutputBuffer(const j_compress_ptr cinfo) +{ + tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; + if (jcd) { + int Used = jcd->size; + jcd->size += JPEGCOMPRESSMEM; + jcd->mem = (unsigned char *)realloc(jcd->mem, jcd->size); + if (jcd->mem) { + cinfo->dest->next_output_byte = jcd->mem + Used; + cinfo->dest->free_in_buffer = jcd->size - Used; + return TRUE; + } + } + return FALSE; +} + +static void JpegCompressTermDestination(const j_compress_ptr cinfo) +{ + tJpegCompressData *jcd = (tJpegCompressData *)cinfo->client_data; + if (jcd) { + int Used = cinfo->dest->next_output_byte - jcd->mem; + if (Used < jcd->size) { + jcd->size = Used; + jcd->mem = (unsigned char *)realloc(jcd->mem, jcd->size); + } + } +} + + + static int vdr_write(int f, void *b, int n) { int t = 0, r; @@ -427,6 +482,12 @@ if (this->osd_supports_custom_extent && data->w_ref > 0 && data->h_ref > 0) xine_osd_set_extent(this->osd[ data->window ].window, data->w_ref, data->h_ref); + + /* + * We use a new object type id for osd objects coming from this input plugin so that + * post plugins like autocrop can do special handling + */ + this->osd[ data->window ].window->osd.renderer->event.object.object_type = 2; } break; @@ -1088,6 +1149,137 @@ } break; +/* --- neu --- */ + + case func_grab_image_vdpau: + { + off_t ret_val = -1; + xine_grab_frame_t *grab_frame; + + READ_DATA_OR_FAIL(grab_image_vdpau, lprintf("got VDPAU-GRABIMAGE\n")); + + if (!data->jpeg) /* convert to PNM */ + { + if (!xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_ALLOC_GRAB_FRAME, &grab_frame)) + { + int size; + result_grab_image_t result_grab_image; + + grab_frame->width = data->width; + grab_frame->height = data->height; + if (xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_GRAB_FRAME, grab_frame)) + { + xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_FREE_GRAB_FRAME, grab_frame); + return ret_val; + } + + /* allocate memory for result */ + size_t bytes = data->width * data->height * 3; + uint8_t *pnm = malloc(bytes + 64); + if (!pnm) + { + xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_FREE_GRAB_FRAME, grab_frame); + return ret_val; + } + + /* PNM header */ + sprintf((char*)pnm, "P6\n%d\n%d\n255\n", data->width, data->height); + int hdrlen = strlen((char*)pnm); + + /* copy image */ + xine_fast_memcpy(pnm + hdrlen, grab_frame->img, bytes); + + size = bytes + hdrlen; + + xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_FREE_GRAB_FRAME, grab_frame); + + result_grab_image.header.func = data->header.func; + result_grab_image.header.len = sizeof (result_grab_image) + size; + + result_grab_image.width = data->width; + result_grab_image.height = data->height; + + if (sizeof (result_grab_image) == vdr_write(this->fh_result, &result_grab_image, sizeof (result_grab_image))) + { + if (!size || (size == vdr_write(this->fh_result, (char*) pnm, size))) + ret_val = 0; + } + + free(pnm); + } + } + else /* JPEG */ + { + if (!xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_ALLOC_GRAB_FRAME, &grab_frame)) + { + int size; + result_grab_image_t result_grab_image; + + grab_frame->width = data->width; + grab_frame->height = data->height; + if (xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_GRAB_FRAME, grab_frame)) + { + xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_FREE_GRAB_FRAME, grab_frame); + return ret_val; + } + + /* Compress JPEG */ + struct jpeg_destination_mgr jdm; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + tJpegCompressData jcd; + + jdm.init_destination = JpegCompressInitDestination; + jdm.empty_output_buffer = JpegCompressEmptyOutputBuffer; + jdm.term_destination = JpegCompressTermDestination; + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + cinfo.dest = &jdm; + cinfo.client_data = &jcd; + cinfo.image_width = data->width; + cinfo.image_height = data->height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, data->quality, TRUE); + jpeg_start_compress(&cinfo, TRUE); + + JSAMPROW rp[data->height]; + int rs = data->width * 3; + int k; + for (k = 0; k < data->height; k++) + rp[k] = grab_frame->img + k * rs; + jpeg_write_scanlines(&cinfo, rp, data->height); + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + size = jcd.size; + + xine_port_send_gui_data(this->stream->video_out, XINE_GUI_SEND_FREE_GRAB_FRAME, grab_frame); + + result_grab_image.header.func = data->header.func; + result_grab_image.header.len = sizeof (result_grab_image) + size; + result_grab_image.width = data->width; + result_grab_image.height = data->height; + + if (sizeof (result_grab_image) == vdr_write(this->fh_result, &result_grab_image, sizeof (result_grab_image))) + { + if (!size || (size == vdr_write(this->fh_result, (char*) jcd.mem, size))) + ret_val = 0; + } + free(jcd.mem); + } + } + + if (ret_val != 0) + return ret_val; + } + break; + +/* --- */ + case func_grab_image: { READ_DATA_OR_FAIL(grab_image, lprintf("got GRABIMAGE\n")); diff -Naur xine-lib-1.2_orig/src/video_out/video_out_vdpau.c xine-lib-1.2/src/video_out/video_out_vdpau.c --- xine-lib-1.2_orig/src/video_out/video_out_vdpau.c 2010-01-24 22:47:08.000000000 +0100 +++ xine-lib-1.2/src/video_out/video_out_vdpau.c 2010-01-24 22:54:20.358397699 +0100 @@ -89,6 +89,14 @@ }; +char *vdpau_sd_only_properties[] = { + "none", + "noise", + "sharpness", + "noise+sharpness", + NULL +}; + VdpOutputSurfaceRenderBlendState blend = { VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION, VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, @@ -123,7 +131,9 @@ VdpOutputSurfaceCreate *vdp_output_surface_create; VdpOutputSurfaceDestroy *vdp_output_surface_destroy; VdpOutputSurfaceRenderBitmapSurface *vdp_output_surface_render_bitmap_surface; +VdpOutputSurfaceRenderOutputSurface *vdp_output_surface_render_output_surface; VdpOutputSurfacePutBitsNative *vdp_output_surface_put_bits; +VdpOutputSurfaceGetBitsNative *vdp_output_surface_get_bits; VdpVideoMixerCreate *vdp_video_mixer_create; VdpVideoMixerDestroy *vdp_video_mixer_destroy; @@ -292,15 +302,6 @@ 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; @@ -311,12 +312,17 @@ uint32_t soft_surface_height; int soft_surface_format; -#define NOUTPUTSURFACE 2 +#define NOUTPUTSURFACE 4 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; + uint8_t queue_length; + uint64_t output_surface_vpts[NOUTPUTSURFACE]; + pthread_mutex_t output_surface_lock[NOUTPUTSURFACE]; + pthread_cond_t queue_changed; + pthread_mutex_t queue_lock; VdpVideoMixer video_mixer; VdpChromaType video_mixer_chroma; @@ -356,6 +362,7 @@ int honor_progressive; int skip_chroma; int studio_levels; + int sd_only_properties; int background; int vdp_runtime_nr; @@ -398,139 +405,6 @@ -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) - fprintf(stderr, "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) - fprintf(stderr, "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) - fprintf(stderr, "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]; @@ -538,6 +412,22 @@ if ( overlay->width<=0 || overlay->height<=0 ) return 0; + 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; + + if (overlay->video_window_width > 0 && overlay->video_window_height > 0) { + /* last one wins */ + this_gen->video_window_x = overlay->video_window_x; + this_gen->video_window_y = overlay->video_window_y; + this_gen->video_window_width = overlay->video_window_width; + this_gen->video_window_height = overlay->video_window_height; + } + 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 ); @@ -546,17 +436,13 @@ VdpStatus st = vdp_bitmap_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, overlay->width, overlay->height, 0, &ovl->ovl_bitmap ); if ( st != VDP_STATUS_OK ) { fprintf(stderr, "vdpau_process_ovl: vdp_bitmap_create failed : %s\n", vdp_get_error_string(st) ); + return 0; } 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; + + if (overlay->rle) { uint32_t *buf = (uint32_t*)malloc(ovl->ovl_w*ovl->ovl_h*4); if ( !buf ) return 0; @@ -612,6 +498,20 @@ fprintf(stderr, "vdpau_process_ovl: vdp_bitmap_put_bits failed : %s\n", vdp_get_error_string(st) ); } free(buf); + } + else if (overlay->argb_layer) { + pthread_mutex_lock(&overlay->argb_layer->mutex); + if (overlay->argb_layer->buffer) { + 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, &overlay->argb_layer->buffer, &pitch, &dest); + if ( st != VDP_STATUS_OK ) { + printf( "vdpau_process_ovl: vdp_bitmap_put_bits failed : %s\n", vdp_get_error_string(st) ); + } + } + pthread_mutex_unlock(&overlay->argb_layer->mutex); + } + return 1; } @@ -625,8 +525,10 @@ return; this->has_overlay = this->has_unscaled = 0; - this->has_argb_overlay = 0; - this->argb_ovl_count = 0; + this->video_window_x = 0; + this->video_window_y = 0; + this->video_window_width = 0; + this->video_window_height = 0; ++this->ovl_changed; } @@ -640,20 +542,15 @@ if (!this->ovl_changed) return; - if (overlay->rle) { if (this->ovl_changed >= XINE_VORAW_MAX_OVL) return; + + if (overlay->rle) { if (!overlay->rgb_clut || !overlay->hili_rgb_clut) vdpau_overlay_clut_yuv2rgb (this, overlay, frame); - if ( vdpau_process_ovl( this, overlay ) ) - ++this->ovl_changed; - } - - if (overlay->argb_layer) { - if (this->argb_ovl_count >= XINE_VORAW_MAX_OVL) - return; - this->argb_ovl[this->argb_ovl_count++] = overlay; } + if ( vdpau_process_ovl( this, overlay ) ) + ++this->ovl_changed; } @@ -667,9 +564,6 @@ 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; @@ -690,6 +584,7 @@ scaler = 1; if ( this->overlays[i].expected_overlay_height ) scaler = 1; + this->has_overlay = 1; } if ( scaler ) { @@ -700,7 +595,7 @@ 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 ) { + if ( (!this->has_overlay || 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 ) { fprintf(stderr, "vdpau_overlay_end: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st) ); @@ -719,9 +614,10 @@ 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; + this->has_unscaled = 1; } - if ( (this->overlay_unscaled_width!=w || this->overlay_unscaled_height!=h) && this->overlay_unscaled != VDP_INVALID_HANDLE ) { + if ( (!this->has_unscaled || 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 ) { fprintf(stderr, "vdpau_overlay_end: vdp_output_surface_destroy failed : %s\n", vdp_get_error_string(st) ); @@ -732,13 +628,13 @@ this->overlay_unscaled_width = w; this->overlay_unscaled_height = h; - if ( this->overlay_unscaled == VDP_INVALID_HANDLE ) { + if ( this->has_unscaled && 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 ) fprintf(stderr, "vdpau_overlay_end: vdp_output_surface_create failed : %s\n", vdp_get_error_string(st) ); } - if ( this->overlay_output == VDP_INVALID_HANDLE ) { + if ( this->has_overlay && 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 ) fprintf(stderr, "vdpau_overlay_end: vdp_output_surface_create failed : %s\n", vdp_get_error_string(st) ); @@ -750,21 +646,25 @@ 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 }; + if (this->has_overlay) { st = vdp_output_surface_put_bits( this->overlay_output, &buf, &pitch, &clear ); if ( st != VDP_STATUS_OK ) { fprintf(stderr, "vdpau_overlay_end: vdp_output_surface_put_bits (clear) failed : %s\n", vdp_get_error_string(st) ); } + } + if (this->has_unscaled) { 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 ) { fprintf(stderr, "vdpau_overlay_end: vdp_output_surface_put_bits (clear) failed : %s\n", vdp_get_error_string(st) ); } + } free(buf); VdpOutputSurface *surface; for ( i=0; iovl_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 ) { + if ( !this->overlays[i].unscaled && 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; @@ -777,7 +677,6 @@ fprintf(stderr, "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; } @@ -860,74 +759,55 @@ -static void vdpau_provide_standard_frame_data (vo_frame_t *this_gen, xine_current_frame_data_t *data) +static void vdpau_provide_standard_frame_data (vo_frame_t *this, xine_current_frame_data_t *data) { - vdpau_frame_t *this = (vdpau_frame_t *)this_gen; VdpStatus st; VdpYCbCrFormat format; + uint32_t pitches[3]; + void *base[3]; - 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); + if (this->format != XINE_IMGFMT_VDPAU) { + fprintf(stderr, "vdpau_provide_standard_frame_data: unexpected frame format 0x%08x!\n", this->format); return; } - if (!(this->flags & VO_CHROMA_422)) { + vdpau_accel_t *accel = (vdpau_accel_t *) this->accel_data; + + if (accel->vdp_runtime_nr != *(accel->current_vdp_runtime_nr)) + return; + + this = accel->vo_frame; + + if (accel->chroma == VDP_CHROMA_TYPE_420) { 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); + data->img_size = this->width * this->height + + ((this->width + 1) / 2) * ((this->height + 1) / 2) + + ((this->width + 1) / 2) * ((this->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)); + pitches[0] = this->width; + pitches[1] = this->width / 2; + pitches[2] = this->width / 2; + base[0] = data->img; + base[1] = data->img + this->width * this->height; + base[2] = data->img + this->width * this->height + this->width * this->height / 4; 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; + data->img_size = this->width * this->height + + ((this->width + 1) / 2) * this->height + + ((this->width + 1) / 2) * this->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); + pitches[0] = this->width * 2; + base[0] = data->img; 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); + st = vdp_video_surface_getbits_ycbcr(accel->surface, format, base, pitches); if (st != VDP_STATUS_OK) fprintf(stderr, "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]); } } @@ -1332,7 +1212,7 @@ return; float value = this_gen->noise/100.0; - if ( value==0 ) { + if ( value==0 || ((this_gen->sd_only_properties & 1) && this_gen->video_mixer_width >= 800)) { 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 ); @@ -1361,7 +1241,7 @@ return; float value = this_gen->sharpness/100.0; - if ( value==0 ) { + if ( value==0 || (this_gen->sd_only_properties >= 2 && this_gen->video_mixer_width >= 800)) { 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 ); @@ -1384,6 +1264,18 @@ +static void vdpau_update_sd_only_properties( void *this_gen, xine_cfg_entry_t *entry ) +{ + vdpau_driver_t *this = (vdpau_driver_t *) this_gen; + + this->sd_only_properties = entry->num_value; + printf( "vo_vdpau: enable sd only noise=%d, sd only sharpness %d\n", ((this->sd_only_properties & 1) != 0), (this->sd_only_properties >= 2) ); + vdpau_update_noise(this); + vdpau_update_sharpness(this); +} + + + static void vdpau_update_csc( vdpau_driver_t *this_gen ) { float hue = this_gen->hue/100.0; @@ -1518,11 +1410,14 @@ { vdpau_driver_t *this = (vdpau_driver_t *) this_gen; - if ( this->init_queue<2 ) + pthread_mutex_lock(&this->queue_lock); + if ( this->init_queue < this->queue_length ) ++this->init_queue; ++this->current_output_surface; - if ( this->current_output_surface > (NOUTPUTSURFACE-1) ) + if ( this->current_output_surface >= this->queue_length ) this->current_output_surface = 0; + pthread_mutex_unlock(&this->queue_lock); + pthread_cond_broadcast(&this->queue_changed); } @@ -1688,41 +1583,34 @@ stream_speed = frame->vo_frame.stream ? xine_get_param(frame->vo_frame.stream, XINE_PARAM_FINE_SPEED) : 0; - 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; + uint32_t layer_count = 0; + VdpLayer layer[2]; + VdpRect ovl_source, unscaled_source; 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; + ovl_source.x0 = 0; ovl_source.y0 = 0; ovl_source.x1 = this->overlay_output_width; ovl_source.y1 = this->overlay_output_height; + layer[0].struct_version = VDP_LAYER_VERSION; layer[0].source_surface = this->overlay_output; layer[0].source_rect = &ovl_source; layer[0].destination_rect = &vid_dest; + /* recalculate video destination window to match osd's specified video window */ + if (!this->has_unscaled && 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 - ovl_source.x0) * (vid_dest.x1 - vid_dest.x0) + vid_dest.x0 * (ovl_source.x1 - ovl_source.x0)) / (ovl_source.x1 - ovl_source.x0); + vid_dest.y0 = ((win_rect.y0 - ovl_source.y0) * (vid_dest.y1 - vid_dest.y0) + vid_dest.y0 * (ovl_source.y1 - ovl_source.y0)) / (ovl_source.y1 - ovl_source.y0); + vid_dest.x1 = ((win_rect.x1 - ovl_source.x0) * (vid_dest.x1 - vid_dest.x0) + vid_dest.x0 * (ovl_source.x1 - ovl_source.x0)) / (ovl_source.x1 - ovl_source.x0); + vid_dest.y1 = ((win_rect.y1 - ovl_source.y0) * (vid_dest.y1 - vid_dest.y0) + vid_dest.y0 * (ovl_source.y1 - ovl_source.y0)) / (ovl_source.y1 - ovl_source.y0); } - else { - layer_count = 0; + ++layer_count; } - 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; + if ( this->has_unscaled ) { + unscaled_source.x0 = 0; unscaled_source.y0 = 0; unscaled_source.x1 = this->overlay_unscaled_width; unscaled_source.y1 = this->overlay_unscaled_height; + layer[layer_count].struct_version = VDP_LAYER_VERSION; layer[layer_count].source_surface = this->overlay_unscaled; layer[layer_count].source_rect = &unscaled_source; layer[layer_count].destination_rect = &unscaled_source; /* 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); + vid_dest.x0 = this->video_window_x; + vid_dest.y0 = this->video_window_y; + vid_dest.x1 = this->video_window_x + this->video_window_width; + vid_dest.y1 = this->video_window_y + this->video_window_height; } + ++layer_count; } /* try to get frame duration from previous img->pts when frame->duration is 0 */ @@ -1734,10 +1622,20 @@ } int non_progressive = (this->honor_progressive && !frame->vo_frame.progressive_frame) || !this->honor_progressive; + VdpTime last_time; + + if ( this->init_queue>=this->queue_length ) + vdp_queue_block( vdp_queue, this->output_surface[this->current_output_surface], &last_time ); + #ifdef LOCKDISPLAY XLockDisplay( this->display ); #endif + pthread_mutex_lock(&this->output_surface_lock[this->current_output_surface]); + this->output_surface_vpts[this->current_output_surface] = frame->vo_frame.vpts; + + vdpau_check_output_size( this_gen ); + if ( frame->format==XINE_IMGFMT_VDPAU && this->deinterlace && non_progressive && !(frame->vo_frame.flags & VO_STILL_IMAGE) && frame_duration>2500 ) { VdpTime current_time = 0; VdpVideoSurface past[2]; @@ -1753,13 +1651,15 @@ if ( st != VDP_STATUS_OK ) fprintf(stderr, "vo_vdpau: vdp_video_mixer_render error : %s\n", vdp_get_error_string( st ) ); + pthread_mutex_unlock(&this->output_surface_lock[this->current_output_surface]); + 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 ) { + if ( this->init_queue>=this->queue_length ) { #ifdef LOCKDISPLAY XUnlockDisplay(this->display); #endif @@ -1769,6 +1669,11 @@ #endif } + pthread_mutex_lock(&this->output_surface_lock[this->current_output_surface]); + this->output_surface_vpts[this->current_output_surface] = frame->vo_frame.vpts; + if (stream_speed > 0) + this->output_surface_vpts[this->current_output_surface] += (uint64_t)frame->vo_frame.duration * XINE_FINE_SPEED_NORMAL / (2 * stream_speed); + 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; @@ -1783,6 +1688,8 @@ if ( st != VDP_STATUS_OK ) fprintf(stderr, "vo_vdpau: vdp_video_mixer_render error : %s\n", vdp_get_error_string( st ) ); + pthread_mutex_unlock(&this->output_surface_lock[this->current_output_surface]); + if ( stream_speed > 0 ) current_time += frame->vo_frame.duration * 1000000ull * XINE_FINE_SPEED_NORMAL / (180 * stream_speed); @@ -1798,6 +1705,8 @@ if ( st != VDP_STATUS_OK ) fprintf(stderr, "vo_vdpau: vdp_video_mixer_render error : %s\n", vdp_get_error_string( st ) ); + pthread_mutex_unlock(&this->output_surface_lock[this->current_output_surface]); + vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, 0 ); vdpau_shift_queue( this_gen ); } @@ -1925,6 +1834,166 @@ } +typedef struct { + xine_grab_frame_t grab_frame; + + VdpOutputSurface render_surface; + int vdp_runtime_nr; + int width, height; + uint32_t *rgba; +} vdpau_grab_frame_t; + + +static int vdpau_alloc_grab_frame(vdpau_driver_t *this, void *data) +{ + vdpau_grab_frame_t *frame = calloc(1, sizeof(vdpau_grab_frame_t)); + if (!frame) + return -1; + + frame->render_surface = VDP_INVALID_HANDLE; + frame->grab_frame.vpts = -1; + *((vdpau_grab_frame_t **) data) = frame; + + return 0; +} + + +static int vdpau_free_grab_frame(vdpau_driver_t *this, void *data) +{ + vdpau_grab_frame_t *frame = (vdpau_grab_frame_t *) data; + + free(frame->grab_frame.img); + free(frame->rgba); + if (frame->render_surface != VDP_INVALID_HANDLE && frame->vdp_runtime_nr == this->vdp_runtime_nr) { + if (vdp_output_surface_destroy(frame->render_surface) != VDP_STATUS_OK) + printf("vo_vdpau: Can't destroy output surface!\n"); + } + free(frame); + return 0; +} + + +static int vdpau_grab_last_displayed_frame (vdpau_driver_t *this, void *data) { + vdpau_grab_frame_t *frame = (vdpau_grab_frame_t *) data; + int previous = -1; + + pthread_mutex_lock(&this->queue_lock); + if (this->init_queue) { + previous = this->current_output_surface ? this->current_output_surface - 1: this->queue_length - 1; + + /* Ensure that we do not grab the same frame again */ + if (frame->grab_frame.vpts == this->output_surface_vpts[previous]) + previous = -1; + } + if (previous == -1 && frame->grab_frame.timeout > 0) { + /* wait for next displayed frame */ + struct timeval tvnow, tvdiff, tvtimeout; + struct timespec ts; + tvdiff.tv_sec = frame->grab_frame.timeout / 1000; + tvdiff.tv_usec = frame->grab_frame.timeout % 1000; + tvdiff.tv_usec *= 1000; + gettimeofday(&tvnow, NULL); + timeradd(&tvnow, &tvdiff, &tvtimeout); + ts.tv_sec = tvtimeout.tv_sec; + ts.tv_nsec = tvtimeout.tv_usec; + ts.tv_nsec *= 1000; + if (!pthread_cond_timedwait(&this->queue_changed, &this->queue_lock, &ts)) + previous = this->current_output_surface ? this->current_output_surface - 1: this->queue_length - 1; + } + pthread_mutex_unlock(&this->queue_lock); + + if (previous == -1) + return 1; /* no frame available */ + + pthread_mutex_lock(&this->output_surface_lock[previous]); + + int width = this->output_surface_width[previous] - frame->grab_frame.crop_left - frame->grab_frame.crop_right; + int height = this->output_surface_height[previous] - frame->grab_frame.crop_top - frame->grab_frame.crop_bottom; + if (width < 1) + width = 1; + if (height < 1) + height = 1; + + if (frame->grab_frame.width <= 0) + frame->grab_frame.width = width; + if (frame->grab_frame.height <= 0) + frame->grab_frame.height = height; + + if (frame->vdp_runtime_nr != this->vdp_runtime_nr) + frame->render_surface = VDP_INVALID_HANDLE; + + if (frame->grab_frame.width != frame->width || frame->grab_frame.height != frame->height) { + free(frame->rgba); + free(frame->grab_frame.img); + frame->rgba = NULL; + frame->grab_frame.img = NULL; + + if (frame->render_surface != VDP_INVALID_HANDLE) { + if (vdp_output_surface_destroy(frame->render_surface) != VDP_STATUS_OK) + printf("vo_vdpau: Can't destroy output surface!\n"); + frame->render_surface = VDP_INVALID_HANDLE; + } + + frame->width = frame->grab_frame.width; + frame->height = frame->grab_frame.height; + } + + if (frame->rgba == NULL) { + frame->rgba = (uint32_t *) calloc(frame->width * frame->height, sizeof(uint32_t)); + if (frame->rgba == NULL) + return -1; + frame->grab_frame.img = (uint8_t *) calloc(frame->width * frame->height, 3); + if (frame->grab_frame.img == NULL) + return -1; + } + + VdpStatus st; + uint32_t pitches = frame->width * sizeof(uint32_t); + VdpRect src_rect = { frame->grab_frame.crop_left, frame->grab_frame.crop_top, width+frame->grab_frame.crop_left, height+frame->grab_frame.crop_top }; + frame->grab_frame.vpts = this->output_surface_vpts[previous]; + + if (frame->width != width || frame->height != height) { + st = VDP_STATUS_OK; + if (frame->render_surface == VDP_INVALID_HANDLE) { + frame->vdp_runtime_nr = this->vdp_runtime_nr; + st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, frame->width, frame->height, &frame->render_surface); + } + if (st == VDP_STATUS_OK) { + st = vdp_output_surface_render_output_surface(frame->render_surface, NULL, this->output_surface[previous], &src_rect, NULL, NULL, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); + pthread_mutex_unlock(&this->output_surface_lock[previous]); + if (st == VDP_STATUS_OK) { + st = vdp_output_surface_get_bits(frame->render_surface, NULL, &frame->rgba, &pitches); + if (st != VDP_STATUS_OK) + printf("vo_vdpau: Can't get output surface bits for raw frame grabbing!\n"); + } + else + printf("vo_vdpau: Can't render output surface for raw frame grabbing!\n"); + } else { + pthread_mutex_unlock(&this->output_surface_lock[previous]); + printf("vo_vdpau: Can't create output surface for raw frame grabbing!\n"); + } + } else { + st = vdp_output_surface_get_bits(this->output_surface[previous], &src_rect, &frame->rgba, &pitches); + pthread_mutex_unlock(&this->output_surface_lock[previous]); + if (st != VDP_STATUS_OK) + printf("vo_vdpau: Can't get output surface bits for raw frame grabbing!\n"); + } + if (st == VDP_STATUS_OK) { + uint32_t *src = frame->rgba; + uint8_t *dst = frame->grab_frame.img; + int n = frame->width * frame->height; + while (n--) { + *dst++ = (uint8_t)(*src >> 16); /*R*/ + *dst++ = (uint8_t)(*src >> 8); /*G*/ + *dst++ = (uint8_t)(*src++); /*B*/ + } + return 0; + } + + frame->grab_frame.vpts = -1; + return -1; +} + static int vdpau_gui_data_exchange (vo_driver_t *this_gen, int data_type, void *data) { @@ -1941,9 +2010,7 @@ #ifdef LOCKDISPLAY XLockDisplay( this->display ); #endif - int previous = this->current_output_surface - 1; - if ( previous < 0 ) - previous = NOUTPUTSURFACE - 1; + int previous = this->current_output_surface ? this->current_output_surface - 1: this->queue_length - 1; vdp_queue_display( vdp_queue, this->output_surface[previous], 0, 0, 0 ); #ifdef LOCKDISPLAY XUnlockDisplay( this->display ); @@ -1996,6 +2063,14 @@ rect->h = y2-y1; break; } + case XINE_GUI_SEND_ALLOC_GRAB_FRAME: + return vdpau_alloc_grab_frame (this, data); + + case XINE_GUI_SEND_FREE_GRAB_FRAME: + return vdpau_free_grab_frame (this, data); + + case XINE_GUI_SEND_GRAB_FRAME: + return vdpau_grab_last_displayed_frame (this, data); default: return -1; @@ -2034,13 +2109,11 @@ 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; iqueue_length; ++i ) { if ( this->output_surface[i]!=VDP_INVALID_HANDLE ) vdp_output_surface_destroy( this->output_surface[i] ); } @@ -2058,6 +2131,11 @@ if ( (vdp_device != VDP_INVALID_HANDLE) && vdp_device_destroy ) vdp_device_destroy( vdp_device ); + for (i = 0; i < this->queue_length; ++i) + pthread_mutex_destroy(&this->output_surface_lock[i]); + pthread_mutex_destroy(&this->queue_lock); + pthread_cond_destroy(&this->queue_changed); + free (this); } @@ -2112,7 +2190,7 @@ this->current_output_surface = 0; this->init_queue = 0; int i; - for ( i=0; iqueue_length; ++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; @@ -2137,10 +2215,6 @@ 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 ) { @@ -2175,7 +2249,7 @@ 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; iqueue_length; ++i ) vdp_output_surface_destroy( this->output_surface[i] ); return; } @@ -2304,10 +2378,6 @@ 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 ); @@ -2381,9 +2451,15 @@ 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_RENDER_OUTPUT_SURFACE , (void*)&vdp_output_surface_render_output_surface ); + if ( vdpau_init_error( st, "Can't get OUTPUT_SURFACE_RENDER_OUTPUT_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_OUTPUT_SURFACE_GET_BITS_NATIVE , (void*)&vdp_output_surface_get_bits ); + if ( vdpau_init_error( st, "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_GET_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; @@ -2447,6 +2523,9 @@ 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_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; @@ -2498,13 +2577,26 @@ if ( vdpau_init_error( st, "Can't create video surface !!", &this->vo_driver, 1 ) ) return NULL; - for ( i=0; iqueue_length = config->register_num (config, "video.output.vdpau_display_queue_length", 2, /* default */ + _("default length of display queue"), + _("The default number of video output surfaces to create for the display queue"), + 20, NULL, this); + if (this->queue_length < 2) + this->queue_length = 2; + if (this->queue_length > NOUTPUTSURFACE) + this->queue_length = NOUTPUTSURFACE; + + for ( i=0; iqueue_length; ++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; iqueue_lock, NULL); + pthread_cond_init(&this->queue_changed, NULL); + + for ( i=0; iqueue_length; ++i ) { + pthread_mutex_init(&this->output_surface_lock[i], NULL); 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; @@ -2578,7 +2670,7 @@ 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; iqueue_length; ++i ) vdp_output_surface_destroy( this->output_surface[i] ); return NULL; } @@ -2663,6 +2755,18 @@ 10, vdpau_set_background, this ); } + this->sd_only_properties = config->register_enum( config, "video.output.vdpau_sd_only_properties", 0, vdpau_sd_only_properties, + _("vdpau: restrict enabling video properties for SD video only"), + _("none\n" + "No restrictions\n\n" + "noise\n" + "Restrict noise reduction property.\n\n" + "sharpness\n" + "Restrict sharpness property.\n\n" + "noise+sharpness" + "Restrict noise and sharpness properties.\n\n"), + 10, vdpau_update_sd_only_properties, 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"), diff -Naur xine-lib-1.2_orig/src/xine-utils/utils.c xine-lib-1.2/src/xine-utils/utils.c --- xine-lib-1.2_orig/src/xine-utils/utils.c 2010-01-24 22:47:09.000000000 +0100 +++ xine-lib-1.2/src/xine-utils/utils.c 2010-01-24 22:52:20.158399316 +0100 @@ -482,21 +482,13 @@ /* select does not work on win32 */ Sleep(usec / 1000); #else -# if 0 -# if HAVE_NANOSLEEP - /* nanosleep is prefered on solaris, because it's mt-safe */ + # if HAVE_NANOSLEEP struct timespec ts, remaining; ts.tv_sec = usec / 1000000; ts.tv_nsec = (usec % 1000000) * 1000; while (nanosleep (&ts, &remaining) == -1 && errno == EINTR) ts = remaining; # else - usleep(usec); -# endif -# else - if (usec < 10000) { - usec = 10000; - } struct timeval tm; tm.tv_sec = usec / 1000000; tm.tv_usec = usec % 1000000;