summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libvdpau/vdpau_h264.c5
-rw-r--r--src/libvdpau/vdpau_mpeg12.c4
-rw-r--r--src/video_out/video_out_vdpau.c167
3 files changed, 158 insertions, 18 deletions
diff --git a/src/libvdpau/vdpau_h264.c b/src/libvdpau/vdpau_h264.c
index d6548b682..c7ad706e9 100644
--- a/src/libvdpau/vdpau_h264.c
+++ b/src/libvdpau/vdpau_h264.c
@@ -444,7 +444,12 @@ static void vdpau_h264_decode_data (video_decoder_t *this_gen,
}
if(status != VDP_STATUS_OK)
+ {
xprintf(this->xine, XINE_VERBOSITY_LOG, "vdpau_h264: Decoder failure: %s\n", this->vdpau_accel->vdp_get_error_string(status));
+ img->bad_frame = 1;
+ img->draw(img, this->stream);
+ this->last_img = 0;
+ }
else {
img->duration = this->video_step;
diff --git a/src/libvdpau/vdpau_mpeg12.c b/src/libvdpau/vdpau_mpeg12.c
index fc7221019..66d451c12 100644
--- a/src/libvdpau/vdpau_mpeg12.c
+++ b/src/libvdpau/vdpau_mpeg12.c
@@ -118,6 +118,7 @@ typedef struct {
int slices_size;
int slices_pos, slices_pos_top;
+ int progressive_frame;
int state;
} picture_t;
@@ -435,6 +436,7 @@ static void picture_coding_extension( sequence_t *sequence, uint8_t *buf, int le
lprintf( "alternate_scan: %d\n", get_bits( buf,29,1 ) );
lprintf( "repeat_first_field: %d\n", get_bits( buf,30,1 ) );
lprintf( "chroma_420_type: %d\n", get_bits( buf,31,1 ) );
+ sequence->picture.progressive_frame = get_bits( buf,32,1 );
lprintf( "progressive_frame: %d\n", get_bits( buf,32,1 ) );
sequence->picture.state = WANT_SLICE;
}
@@ -687,6 +689,8 @@ static void decode_picture( vdpau_mpeg12_decoder_t *vd )
img->bad_frame = 0;
img->duration = seq->video_step;
+ img->top_field_first = pic->vdp_infos.top_field_first;
+ // progressive_frame is unreliable with most mpeg2 streams //img->progressive_frame = pic->progressive_frame;
if ( pic->vdp_infos.picture_coding_type!=B_FRAME ) {
if ( pic->vdp_infos.picture_coding_type==I_FRAME && !seq->backward_ref ) {
diff --git a/src/video_out/video_out_vdpau.c b/src/video_out/video_out_vdpau.c
index 4daddb2d2..f9746a1a4 100644
--- a/src/video_out/video_out_vdpau.c
+++ b/src/video_out/video_out_vdpau.c
@@ -96,7 +96,7 @@ VdpPresentationQueueCreate *vdp_queue_create;
VdpPresentationQueueDestroy *vdp_queue_destroy;
VdpPresentationQueueDisplay *vdp_queue_display;
VdpPresentationQueueBlockUntilSurfaceIdle *vdp_queue_block;
-VdpPresentationQueueSetBackgroundColor *vdp_queue_set_backgroung_color;
+VdpPresentationQueueSetBackgroundColor *vdp_queue_set_background_color;
VdpPresentationQueueGetTime *vdp_queue_get_time;
VdpBitmapSurfacePutBitsNative *vdp_bitmap_put_bits;
@@ -110,6 +110,62 @@ VdpDecoderRender *vdp_decoder_render;
+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;
+ XLockDisplay(guarded_display);
+ r = orig_vdp_video_surface_create(device, chroma_type, width, height, surface);
+ XUnlockDisplay(guarded_display);
+ 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;
+ XLockDisplay(guarded_display);
+ r = orig_vdp_decoder_create(device, profile, width, height, max_references, decoder);
+ XUnlockDisplay(guarded_display);
+ return r;
+}
+
+static VdpStatus guarded_vdp_decoder_destroy(VdpDecoder decoder)
+{
+ VdpStatus r;
+ XLockDisplay(guarded_display);
+ r = orig_vdp_decoder_destroy(decoder);
+ XUnlockDisplay(guarded_display);
+ 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;
+ XLockDisplay(guarded_display);
+ r = orig_vdp_decoder_render(decoder, target, picture_info, bitstream_buffer_count, bitstream_buffers);
+ XUnlockDisplay(guarded_display);
+ return r;
+}
+
+
+
typedef struct {
VdpBitmapSurface ovl_bitmap;
uint32_t bitmap_width, bitmap_height;
@@ -175,6 +231,8 @@ typedef struct {
uint32_t video_mixer_width;
uint32_t video_mixer_height;
+ VdpColor back_color;
+
vdpau_frame_t *back_frame[ NUM_FRAMES_BACK ];
uint32_t capabilities;
@@ -217,6 +275,8 @@ static void vdpau_overlay_clut_yuv2rgb(vdpau_driver_t *this, vo_overlay_t *over
}
}
+
+
static int vdpau_process_argb_ovl( vdpau_driver_t *this_gen, vo_overlay_t *overlay )
{
vdpau_driver_t *this = (vdpau_driver_t *) this_gen;
@@ -247,6 +307,8 @@ static int vdpau_process_argb_ovl( vdpau_driver_t *this_gen, vo_overlay_t *overl
return 1;
}
+
+
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];
@@ -514,6 +576,7 @@ static vo_frame_t *vdpau_alloc_frame (vo_driver_t *this_gen)
/*
* 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;
@@ -533,6 +596,51 @@ static vo_frame_t *vdpau_alloc_frame (vo_driver_t *this_gen)
+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->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] = xine_xmalloc_aligned(16, this->vo_frame.pitches[0] * orig->vo_frame.height, (void **)&this->chunk[0]);
+ this->vo_frame.base[1] = xine_xmalloc_aligned(16, this->vo_frame.pitches[1] * ((orig->vo_frame.height+1)/2), (void **)&this->chunk[1]);
+ this->vo_frame.base[2] = xine_xmalloc_aligned(16, this->vo_frame.pitches[2] * ((orig->vo_frame.height+1)/2), (void **)&this->chunk[2]);
+ format = VDP_YCBCR_FORMAT_YV12;
+ } else {
+ this->vo_frame.pitches[0] = 8*((orig->vo_frame.width + 3) / 4);
+ this->vo_frame.base[0] = xine_xmalloc_aligned(16, this->vo_frame.pitches[0] * orig->vo_frame.height, (void **)&this->chunk[0]);
+ 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));
+
+ if (this->chunk[0])
+ free(this->chunk[0]);
+ if (this->chunk[1])
+ free(this->chunk[1]);
+ if (this->chunk[2])
+ free(this->chunk[2]);
+ this->chunk[0] = this->chunk[1] = this->chunk[2] = NULL;
+}
+
+
+
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)
{
@@ -574,6 +682,7 @@ static void vdpau_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_
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;
}
}
@@ -584,6 +693,7 @@ static void vdpau_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_
else {
frame->vdpau_accel_data.chroma = chroma;
++this->allocated_surfaces;
+ frame->vo_frame.proc_duplicate_frame_data = vdpau_duplicate_frame_data;
}
}
@@ -639,6 +749,7 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
VdpChromaType chroma = this->video_mixer_chroma;
uint32_t mix_w = this->video_mixer_width;
uint32_t mix_h = this->video_mixer_height;
+ VdpTime stream_speed;
if ( (frame->width != this->sc.delivered_width) || (frame->height != this->sc.delivered_height) || (frame->ratio != this->sc.delivered_ratio) ) {
@@ -729,13 +840,23 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
//printf( "out_dest = %d %d %d %d - vid_dest = %d %d %d %d\n", out_dest.x0, out_dest.y0, out_dest.x1, out_dest.y1, vid_dest.x0, vid_dest.y0, vid_dest.x1, vid_dest.y1 );
- XLockDisplay( this->display );
+ /* 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 );
+ XLockDisplay( this->display );
+
uint32_t layer_count;
VdpLayer layer[3];
VdpRect layersrc, unscaledsrc;
@@ -767,7 +888,7 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
VdpVideoSurface future[1];
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;
- st = vdp_video_mixer_render( this->video_mixer, VDP_INVALID_HANDLE, 0, VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD,
+ st = vdp_video_mixer_render( this->video_mixer, VDP_INVALID_HANDLE, 0, frame->vo_frame.progressive_frame || frame->vo_frame.top_field_first ? VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD : VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD,
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 ) );
@@ -776,8 +897,11 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, current_time );
if ( this->init_queue<2 ) ++this->init_queue;
this->current_output_surface ^= 1;
- if ( this->init_queue>1 )
+ if ( this->init_queue>1 ) {
+ XUnlockDisplay(this->display);
vdp_queue_block( vdp_queue, this->output_surface[this->current_output_surface], &last_time );
+ XLockDisplay(this->display);
+ }
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 */
@@ -791,12 +915,17 @@ static void vdpau_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
past[0] = surface;
future[0] = VDP_INVALID_HANDLE;
- st = vdp_video_mixer_render( this->video_mixer, VDP_INVALID_HANDLE, 0, VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD,
+ st = vdp_video_mixer_render( this->video_mixer, VDP_INVALID_HANDLE, 0, frame->vo_frame.progressive_frame || frame->vo_frame.top_field_first ? VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD : VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD,
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 ) );
- current_time += frame->vo_frame.duration*100000/18;
+ /* 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 * 100000ull * XINE_FINE_SPEED_NORMAL / (18 * stream_speed);
+ else
+ current_time = 0; /* immediately i. e. no delay */
+
vdp_queue_display( vdp_queue, this->output_surface[this->current_output_surface], 0, 0, current_time );
if ( this->init_queue<2 ) ++this->init_queue;
this->current_output_surface ^= 1;
@@ -979,10 +1108,7 @@ static int vdpau_gui_data_exchange (vo_driver_t *this_gen, int data_type, void *
XUnlockDisplay( this->display );
break;
}
- VdpColor backColor;
- backColor.red = backColor.green = backColor.blue = 0;
- backColor.alpha = 1;
- vdp_queue_set_backgroung_color( vdp_queue, &backColor );
+ vdp_queue_set_background_color( vdp_queue, &this->back_color );
XUnlockDisplay( this->display );
this->sc.force_redraw = 1;
break;
@@ -1081,6 +1207,7 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo
if (!this)
return NULL;
+ guarded_display = visual->display;
this->display = visual->display;
this->screen = visual->screen;
this->drawable = visual->d;
@@ -1174,10 +1301,10 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo
vdpau_dispose( &this->vo_driver );
return NULL;
}
- st = vdp_get_proc_address( vdp_device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE , (void*)&vdp_video_surface_create );
+ 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*)&vdp_video_surface_destroy );
+ 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 );
@@ -1231,7 +1358,7 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo
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_backgroung_color );
+ 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 );
@@ -1240,13 +1367,13 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo
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*)&vdp_decoder_create );
+ 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*)&vdp_decoder_destroy );
+ 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*)&vdp_decoder_render );
+ 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 );
@@ -1266,8 +1393,12 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo
if ( vdpau_init_error( st, "Can't create presentation queue !!", &this->vo_driver, 1 ) )
return NULL;
- VdpColor backColor = { 0, 0, 0, 1 };
- vdp_queue_set_backgroung_color( vdp_queue, &backColor );
+ /* choose almost magenta as backcolor for color keying */
+ this->back_color.red = 0.98;
+ this->back_color.green = 0.01;
+ this->back_color.blue = 0.99;
+ this->back_color.alpha = 1;
+ vdp_queue_set_background_color( vdp_queue, &this->back_color );
this->soft_surface_width = 1280;
this->soft_surface_height = 720;