summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_out/video_out_vdpau.c168
-rw-r--r--src/xine-engine/osd.c173
-rw-r--r--src/xine-engine/osd.h25
-rw-r--r--src/xine-engine/video_out.h24
-rw-r--r--src/xine-engine/xine.c48
-rw-r--r--src/xine-engine/xine_interface.c8
6 files changed, 349 insertions, 97 deletions
diff --git a/src/video_out/video_out_vdpau.c b/src/video_out/video_out_vdpau.c
index 857076869..e9f561579 100644
--- a/src/video_out/video_out_vdpau.c
+++ b/src/video_out/video_out_vdpau.c
@@ -216,6 +216,10 @@ typedef struct {
uint32_t argb_overlay_width;
uint32_t argb_overlay_height;
int has_argb_overlay;
+ int argb_osd_x;
+ int argb_osd_y;
+ int argb_osd_w;
+ int argb_osd_h;
VdpVideoSurface soft_surface;
uint32_t soft_surface_width;
@@ -280,33 +284,78 @@ 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 )
+static int vdpau_process_argb_ovl( vdpau_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay )
{
vdpau_driver_t *this = (vdpau_driver_t *) this_gen;
- if(overlay->argb_buffer == NULL)
+ if(overlay->argb_layer == NULL)
return 0;
- if ( (this->argb_overlay_width < overlay->width ) || (this->argb_overlay_height < overlay->height) || (this->argb_overlay == VDP_INVALID_HANDLE) ) {
- if (this->argb_overlay != VDP_INVALID_HANDLE) {
- vdp_output_surface_destroy( this->argb_overlay );
+ pthread_mutex_lock(&overlay->argb_layer->mutex);
+
+ if (overlay->argb_layer->buffer != NULL) {
+ int extent_width = overlay->extent_width;
+ int extent_height = overlay->extent_height;
+ if (extent_width <= 0 || extent_height <= 0) {
+ extent_width = frame_gen->width;
+ extent_height = frame_gen->height;
}
- VdpStatus st = vdp_output_surface_create( vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, overlay->width, overlay->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) );
+
+ if (extent_width > 0 && extent_height > 0) {
+ if ( (this->argb_overlay_width != extent_width ) || (this->argb_overlay_height != 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, extent_width, 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 = extent_width;
+ this->argb_overlay_height = extent_height;
+
+ /* set stored osd location to extent as any smaller osd requires to clear the surface first */
+ this->argb_osd_x = 0;
+ this->argb_osd_y = 0;
+ this->argb_osd_w = extent_width;
+ this->argb_osd_h = extent_height;
+ }
+
+ /* wipe surface if osd layout changed */
+ if (overlay->x != this->argb_osd_x || overlay->y != this->argb_osd_y || overlay->width != this->argb_osd_w || overlay->height != this->argb_osd_h) {
+ this->argb_osd_x = overlay->x;
+ this->argb_osd_y = overlay->y;
+ this->argb_osd_w = overlay->width;
+ this->argb_osd_h = overlay->height;
+
+ uint32_t *zeros = calloc(4 * extent_width, extent_height);
+ if (zeros) {
+ uint32_t pitch = extent_width * 4;
+ VdpRect dest = { 0, 0, extent_width, extent_height };
+ 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 */
+ uint32_t pitch = overlay->width * 4;
+ uint32_t *buffer_start = overlay->argb_layer->buffer + overlay->argb_layer->y1 * overlay->width + overlay->argb_layer->x1;
+ VdpRect dest = { overlay->x + overlay->argb_layer->x1, overlay->y + overlay->argb_layer->y1, overlay->x + overlay->argb_layer->x2, overlay->y + overlay->argb_layer->y2 };
+ overlay->argb_layer->x1 = overlay->width;
+ overlay->argb_layer->y1 = overlay->height;
+ overlay->argb_layer->x2 = 0;
+ overlay->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;
}
- this->argb_overlay_width = overlay->width;
- this->argb_overlay_height = overlay->height;
}
- uint32_t pitch = this->argb_overlay_width*4;
- VdpRect dest = { 0, overlay->y, this->argb_overlay_width, overlay->y + overlay->height };
- uint32_t *buffer_start = overlay->argb_buffer + overlay->y*this->argb_overlay_width;
- 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;
+ pthread_mutex_unlock(&overlay->argb_layer->mutex);
return 1;
}
@@ -418,8 +467,8 @@ static void vdpau_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, v
++this->ovl_changed;
}
- if(overlay->argb_buffer)
- vdpau_process_argb_ovl( this, overlay );
+ if(overlay->argb_layer)
+ vdpau_process_argb_ovl( this, frame_gen, overlay );
}
@@ -603,6 +652,81 @@ static vo_frame_t *vdpau_alloc_frame (vo_driver_t *this_gen)
+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] = xine_xmalloc_aligned(16, this->vo_frame.pitches[0] * this->vo_frame.height, (void **)&this->chunk[0]);
+ this->vo_frame.base[1] = xine_xmalloc_aligned(16, this->vo_frame.pitches[1] * ((this->vo_frame.height+1)/2), (void **)&this->chunk[1]);
+ this->vo_frame.base[2] = xine_xmalloc_aligned(16, this->vo_frame.pitches[2] * ((this->vo_frame.height+1)/2), (void **)&this->chunk[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] = xine_xmalloc_aligned(16, this->vo_frame.pitches[0] * this->vo_frame.height, (void **)&this->chunk[0]);
+ 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[1], this->vo_frame.pitches[1],
+ data->img+this->vo_frame.width*this->vo_frame.height, this->vo_frame.width/2,
+ /* V */
+ this->vo_frame.base[2], this->vo_frame.pitches[2],
+ 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);
+ }
+
+ 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_duplicate_frame_data (vo_frame_t *this_gen, vo_frame_t *original)
{
vdpau_frame_t *this = (vdpau_frame_t *)this_gen;
@@ -690,6 +814,7 @@ static void vdpau_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_
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;
}
}
@@ -701,6 +826,7 @@ static void vdpau_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_
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;
}
}
@@ -1504,7 +1630,7 @@ static vo_driver_t *vdpau_open_plugin (video_driver_class_t *class_gen, const vo
return NULL;
}
- this->capabilities = VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_CROP | VO_CAP_UNSCALED_OVERLAY;
+ 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;
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 );
diff --git a/src/xine-engine/osd.c b/src/xine-engine/osd.c
index 4b521e539..7f4e6aefb 100644
--- a/src/xine-engine/osd.c
+++ b/src/xine-engine/osd.c
@@ -143,16 +143,19 @@ static osd_object_t *XINE_MALLOC osd_new_object (osd_renderer_t *this, int width
osd->next = this->osds;
this->osds = osd;
+ osd->extent_width = 0;
+ osd->extent_height = 0;
osd->width = width;
osd->height = height;
osd->area = calloc(width, height);
+ osd->area_touched = 0;
- osd->x1 = width;
- osd->y1 = height;
- osd->x2 = 0;
- osd->y2 = 0;
+ osd->x1 = osd->argb_layer.x1 = width;
+ osd->y1 = osd->argb_layer.y1 = height;
+ osd->x2 = osd->argb_layer.x2 = 0;
+ osd->y2 = osd->argb_layer.y2 = 0;
- osd->argb_buffer = NULL;
+ pthread_mutex_init(&osd->argb_layer.mutex, NULL);
memcpy(osd->color, textpalettes_color[0], sizeof(textpalettes_color[0]));
memcpy(osd->trans, textpalettes_trans[0], sizeof(textpalettes_trans[0]));
@@ -171,6 +174,18 @@ static osd_object_t *XINE_MALLOC osd_new_object (osd_renderer_t *this, int width
return osd;
}
+/*
+ * osd extent must be set to achive video resolution independent osds
+ * both sizes must be > 0 to take effect. otherwise, video resolution
+ * will still be used. the extent defines the reference coordinate
+ * system which is matched to the video output area.
+ */
+static void osd_set_extent (osd_object_t *osd, int extent_width, int extent_height) {
+
+ osd->extent_width = extent_width;
+ osd->extent_height = extent_height;
+}
+
/*
@@ -231,7 +246,7 @@ static int _osd_show (osd_object_t *osd, int64_t vpts, int unscaled ) {
memset( this->event.object.overlay, 0, sizeof(*this->event.object.overlay) );
- this->event.object.overlay->argb_buffer = osd->argb_buffer;
+ this->event.object.overlay->argb_layer = &osd->argb_layer;
this->event.object.overlay->unscaled = unscaled;
this->event.object.overlay->x = osd->display_x + osd->x1;
@@ -239,6 +254,9 @@ static int _osd_show (osd_object_t *osd, int64_t vpts, int unscaled ) {
this->event.object.overlay->width = osd->x2 - osd->x1;
this->event.object.overlay->height = osd->y2 - osd->y1;
+ this->event.object.overlay->extent_width = osd->extent_width;
+ this->event.object.overlay->extent_height = osd->extent_height;
+
this->event.object.overlay->hili_top = 0;
this->event.object.overlay->hili_bottom = this->event.object.overlay->height;
this->event.object.overlay->hili_left = 0;
@@ -246,53 +264,59 @@ static int _osd_show (osd_object_t *osd, int64_t vpts, int unscaled ) {
/* there will be at least that many rle objects (one for each row) */
this->event.object.overlay->num_rle = 0;
- /* We will never need more rle objects than columns in any row
- Rely on lazy page allocation to avoid us actually taking up
- this much RAM */
- this->event.object.overlay->data_size = osd->width * osd->height;
- rle_p = this->event.object.overlay->rle =
- malloc(this->event.object.overlay->data_size * sizeof(rle_elem_t) );
+ if (!osd->area_touched) {
+ /* avoid rle encoding when only argb_layer is modified */
+ this->event.object.overlay->data_size = 0;
+ rle_p = this->event.object.overlay->rle = NULL;
+ } else {
+ /* We will never need more rle objects than columns in any row
+ Rely on lazy page allocation to avoid us actually taking up
+ this much RAM */
+ this->event.object.overlay->data_size = osd->width * osd->height;
+ rle_p = this->event.object.overlay->rle =
+ malloc(this->event.object.overlay->data_size * sizeof(rle_elem_t) );
- for( y = osd->y1; y < osd->y2; y++ ) {
+ for( y = osd->y1; y < osd->y2; y++ ) {
#ifdef DEBUG_RLE
- lprintf("osd_show %p y = %d: ", osd, y);
+ lprintf("osd_show %p y = %d: ", osd, y);
#endif
- c = osd->area + y * osd->width + osd->x1;
+ c = osd->area + y * osd->width + osd->x1;
- /* initialize a rle object with the first pixel's color */
- rle.len = 1;
- rle.color = *c++;
+ /* initialize a rle object with the first pixel's color */
+ rle.len = 1;
+ rle.color = *c++;
- /* loop over the remaining pixels in the row */
- for( x = osd->x1 + rle.len; x < osd->x2; x++, c++ ) {
- if( rle.color != *c ) {
+ /* loop over the remaining pixels in the row */
+ for( x = osd->x1 + rle.len; x < osd->x2; x++, c++ ) {
+ if( rle.color != *c ) {
#ifdef DEBUG_RLE
- lprintf("(%d, %d), ", rle.len, rle.color);
+ lprintf("(%d, %d), ", rle.len, rle.color);
#endif
- *rle_p++ = rle;
- this->event.object.overlay->num_rle++;
+ *rle_p++ = rle;
+ this->event.object.overlay->num_rle++;
- rle.color = *c;
- rle.len = 1;
- } else {
- rle.len++;
+ rle.color = *c;
+ rle.len = 1;
+ } else {
+ rle.len++;
+ }
}
- }
#ifdef DEBUG_RLE
- lprintf("(%d, %d)\n", rle.len, rle.color);
+ lprintf("(%d, %d)\n", rle.len, rle.color);
#endif
- *rle_p++ = rle;
- this->event.object.overlay->num_rle++;
- }
+ *rle_p++ = rle;
+ this->event.object.overlay->num_rle++;
+ }
#ifdef DEBUG_RLE
- lprintf("osd_show %p rle ends\n", osd);
+ lprintf("osd_show %p rle ends\n", osd);
#endif
- lprintf("num_rle = %d\n", this->event.object.overlay->num_rle);
-
- memcpy(this->event.object.overlay->hili_color, osd->color, sizeof(osd->color));
- memcpy(this->event.object.overlay->hili_trans, osd->trans, sizeof(osd->trans));
- memcpy(this->event.object.overlay->color, osd->color, sizeof(osd->color));
- memcpy(this->event.object.overlay->trans, osd->trans, sizeof(osd->trans));
+ lprintf("num_rle = %d\n", this->event.object.overlay->num_rle);
+
+ memcpy(this->event.object.overlay->hili_color, osd->color, sizeof(osd->color));
+ memcpy(this->event.object.overlay->hili_trans, osd->trans, sizeof(osd->trans));
+ memcpy(this->event.object.overlay->color, osd->color, sizeof(osd->color));
+ memcpy(this->event.object.overlay->trans, osd->trans, sizeof(osd->trans));
+ }
this->event.event_type = OVERLAY_EVENT_SHOW;
this->event.vpts = vpts;
@@ -376,11 +400,14 @@ static int osd_hide (osd_object_t *osd, int64_t vpts) {
static void osd_clear (osd_object_t *osd) {
lprintf("osd=%p\n",osd);
- memset(osd->area, 0, osd->width * osd->height);
- osd->x1 = osd->width;
- osd->y1 = osd->height;
- osd->x2 = 0;
- osd->y2 = 0;
+ if (osd->area_touched) {
+ osd->area_touched = 0;
+ memset(osd->area, 0, osd->width * osd->height);
+ }
+ osd->x1 = osd->argb_layer.x1 = osd->width;
+ osd->y1 = osd->argb_layer.y1 = osd->height;
+ osd->x2 = osd->argb_layer.x2 = 0;
+ osd->y2 = osd->argb_layer.y2 = 0;
}
/*
@@ -402,6 +429,7 @@ static void osd_point (osd_object_t *osd, int x, int y, int color) {
osd->x2 = MAX(osd->x2, (x + 1));
osd->y1 = MIN(osd->y1, y);
osd->y2 = MAX(osd->y2, (y + 1));
+ osd->area_touched = 1;
c = osd->area + y * osd->width + x;
*c = color;
@@ -461,6 +489,7 @@ static void osd_line (osd_object_t *osd,
osd->x2 = MAX( osd->x2, x2 );
osd->y1 = MIN( osd->y1, y1 );
osd->y2 = MAX( osd->y2, y2 );
+ osd->area_touched = 1;
dx = x2 - x1;
dy = y2 - y1;
@@ -574,6 +603,7 @@ static void osd_filled_rect (osd_object_t *osd,
osd->x2 = MAX( osd->x2, dx );
osd->y1 = MIN( osd->y1, y );
osd->y2 = MAX( osd->y2, dy );
+ osd->area_touched = 1;
dx -= x;
dy -= y;
@@ -1131,6 +1161,7 @@ static int osd_render_text (osd_object_t *osd, int x1, int y1,
if( x1 < osd->x1 ) osd->x1 = x1;
if( y1 < osd->y1 ) osd->y1 = y1;
+ osd->area_touched = 1;
inbuf = text;
inbytesleft = strlen(text);
@@ -1479,6 +1510,7 @@ static void osd_free_object (osd_object_t *osd_to_close) {
else
this->osds = osd->next;
+ pthread_mutex_destroy(&osd->argb_layer.mutex);
free( osd );
break;
}
@@ -1524,6 +1556,7 @@ static void osd_draw_bitmap(osd_object_t *osd, uint8_t *bitmap,
osd->x2 = MAX( osd->x2, x1+width );
osd->y1 = MIN( osd->y1, y1 );
osd->y2 = MAX( osd->y2, y1+height );
+ osd->area_touched = 1;
for( y=0; y<height; y++ ) {
if ( palette_map ) {
@@ -1543,33 +1576,56 @@ static void osd_draw_bitmap(osd_object_t *osd, uint8_t *bitmap,
}
static void osd_set_argb_buffer(osd_object_t *osd, uint32_t *argb_buffer,
- int x, int y, int width, int height)
+ int dirty_x, int dirty_y, int dirty_width, int dirty_height)
{
- osd->argb_buffer = argb_buffer;
- if(osd->x1 == 0 || x < osd->x1)
- osd->x1 = x;
- if(osd->x2 == 0 || (x + width) > osd->x2)
- osd->x2 = x + width;
- if(osd->y1 == 0 || y < osd->y1)
- osd->y1 = y;
- if(osd->y2 == 0 || (y + height) > osd->y2)
- osd->y2 = y + height;
+ if (osd->argb_layer.buffer != argb_buffer) {
+ dirty_x = 0;
+ dirty_y = 0;
+ dirty_width = osd->width;
+ dirty_height = osd->height;
+ }
+
+ /* keep osd_object clipping behavior */
+ osd->x1 = MIN( osd->x1, dirty_x );
+ osd->x2 = MAX( osd->x2, dirty_x + dirty_width );
+ osd->y1 = MIN( osd->y1, dirty_y );
+ osd->y2 = MAX( osd->y2, dirty_y + dirty_height );
+
+ pthread_mutex_lock(&osd->argb_layer.mutex);
+
+ /* argb layer update area accumulation */
+ osd->argb_layer.x1 = MIN( osd->argb_layer.x1, dirty_x );
+ osd->argb_layer.x2 = MAX( osd->argb_layer.x2, dirty_x + dirty_width );
+ osd->argb_layer.y1 = MIN( osd->argb_layer.y1, dirty_y );
+ osd->argb_layer.y2 = MAX( osd->argb_layer.y2, dirty_y + dirty_height );
+
+ osd->argb_layer.buffer = argb_buffer;
+
+ pthread_mutex_unlock(&osd->argb_layer.mutex);
}
static uint32_t osd_get_capabilities (osd_object_t *osd) {
osd_renderer_t *this = osd->renderer;
uint32_t capabilities = 0;
+ uint32_t vo_capabilities;
#ifdef HAVE_FT2
capabilities |= XINE_OSD_CAP_FREETYPE2;
#endif
this->stream->xine->port_ticket->acquire(this->stream->xine->port_ticket, 1);
- if( this->stream->video_out->get_capabilities(this->stream->video_out) &
- VO_CAP_UNSCALED_OVERLAY)
- capabilities |= XINE_OSD_CAP_UNSCALED;
+ vo_capabilities = this->stream->video_out->get_capabilities(this->stream->video_out);
this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 1);
+
+ if (vo_capabilities & VO_CAP_UNSCALED_OVERLAY)
+ capabilities |= XINE_OSD_CAP_UNSCALED;
+
+ if (vo_capabilities & VO_CAP_CUSTOM_EXTENT_OVERLAY)
+ capabilities |= XINE_OSD_CAP_CUSTOM_EXTENT;
+
+ if (vo_capabilities & VO_CAP_ARGB_LAYER_OVERLAY)
+ capabilities |= XINE_OSD_CAP_ARGB_LAYER;
return capabilities;
}
@@ -1634,6 +1690,7 @@ osd_renderer_t *_x_osd_renderer_init( xine_stream_t *stream ) {
this->set_argb_buffer = osd_set_argb_buffer;
this->show_unscaled = osd_show_unscaled;
this->get_capabilities = osd_get_capabilities;
+ this->set_extent = osd_set_extent;
return this;
}
diff --git a/src/xine-engine/osd.h b/src/xine-engine/osd.h
index a6acc11ab..36e6fc0ae 100644
--- a/src/xine-engine/osd.h
+++ b/src/xine-engine/osd.h
@@ -47,8 +47,12 @@ struct osd_object_s {
int width, height; /* work area dimentions */
uint8_t *area; /* work area */
+ int area_touched; /* work area was used for painting */
int display_x,display_y; /* where to display it in screen */
+ /* extent of reference coordinate system */
+ int extent_width, extent_height;
+
/* clipping box inside work area */
int x1, y1;
int x2, y2;
@@ -70,7 +74,7 @@ struct osd_object_s {
/* this holds an optional ARGB overlay, which
* is only be used by supported video_out modules.
* right now this is only vdpau */
- uint32_t *argb_buffer;
+ argb_layer_t argb_layer;
};
@@ -219,10 +223,25 @@ struct osd_renderer_s {
uint32_t (*get_capabilities) (osd_object_t *osd);
/*
- * set a buffer to an argb buffer
+ * define extent of reference coordinate system for video
+ * resolution independent osds. both sizes must be > 0 to
+ * take effect. otherwise, video resolution will be used.
+ */
+ void (*set_extent) (osd_object_t *osd, int extent_width, int extent_height);
+
+ /*
+ * set an argb buffer to be blended into video
+ * the buffer must exactly match the osd dimensions
+ * and stay valid while the osd is on screen. pass
+ * a NULL pointer to safely remove the buffer from
+ * the osd layer. only the dirty area will be
+ * updated on screen. for convinience the whole
+ * osd object will be considered dirty when setting
+ * a different buffer pointer.
+ * see also XINE_OSD_CAP_ARGB_LAYER
*/
void (*set_argb_buffer) (osd_object_t *osd, uint32_t *argb_buffer,
- int x, int y, int width, int height);
+ int dirty_x, int dirty_y, int dirty_width, int dirty_height);
/* private stuff */
diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h
index 76b347a41..0c73ddafa 100644
--- a/src/xine-engine/video_out.h
+++ b/src/xine-engine/video_out.h
@@ -68,6 +68,14 @@ struct vo_frame_s {
* member functions
*/
+ /* Provide a copy of the frame's image in an image format already known to xine. data's member */
+ /* have already been intialized to frame's content on entry, so it's usually only necessary to */
+ /* change format and img_size. In case img is set, it will point to a memory block of suitable */
+ /* size (size has been determined by a previous call with img == NULL). img content and img_size */
+ /* must adhere to the specification of _x_get_current_frame_data(). */
+ /* Currently this is needed for all image formats except XINE_IMGFMT_YV12 and XINE_IMGFMT_YUY2. */
+ void (*proc_provide_standard_frame_data) (vo_frame_t *vo_img, xine_current_frame_data_t *data);
+
/* Duplicate picture data and acceleration specific data of a frame. */
/* if the image format isn't already known by Xine. Currently this is needed */
/* For all image formats except XINE_IMGFMT_YV12 and XINE_IMGFMT_YUY2 */
@@ -286,6 +294,8 @@ struct xine_video_port_s {
#define VO_CAP_XXMC 0x00000040 /* driver can use extended XvMC */
#define VO_CAP_VDPAU_H264 0x00000080 /* driver can use VDPAU for H264 */
#define VO_CAP_VDPAU_MPEG12 0x00000100 /* driver can use VDPAU for mpeg1/2 */
+#define VO_CAP_CUSTOM_EXTENT_OVERLAY 0x01000000 /* driver can blend custom extent overlay to output extent */
+#define VO_CAP_ARGB_LAYER_OVERLAY 0x02000000 /* driver supports true color overlay */
/*
@@ -398,6 +408,14 @@ typedef struct rle_elem_s {
uint16_t color;
} rle_elem_t;
+typedef struct argb_layer_s {
+ pthread_mutex_t mutex;
+ uint32_t *buffer;
+ /* dirty area */
+ int x1, y1;
+ int x2, y2;
+} argb_layer_t;
+
struct vo_overlay_s {
rle_elem_t *rle; /* rle code buffer */
@@ -408,6 +426,10 @@ struct vo_overlay_s {
int width; /* width of subpicture area */
int height; /* height of subpicture area */
+ /* extent of reference coordinate system */
+ int extent_width;
+ int extent_height;
+
uint32_t color[OVL_PALETTE_SIZE]; /* color lookup table */
uint8_t trans[OVL_PALETTE_SIZE]; /* mixer key table */
int rgb_clut; /* true if clut was converted to rgb */
@@ -423,7 +445,7 @@ struct vo_overlay_s {
int unscaled; /* true if it should be blended unscaled */
- uint32_t *argb_buffer;
+ argb_layer_t *argb_layer;
};
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index e4e36527f..e0c98c018 100644
--- a/src/xine-engine/xine.c
+++ b/src/xine-engine/xine.c
@@ -1963,6 +1963,8 @@ static int _x_get_current_frame_data (xine_stream_t *stream,
stream->xine->port_ticket->acquire(stream->xine->port_ticket, 0);
frame = stream->video_out->get_last_frame (stream->video_out);
+ if (frame)
+ frame->lock(frame);
stream->xine->port_ticket->release(stream->xine->port_ticket, 0);
if (!frame) {
@@ -1994,6 +1996,30 @@ static int _x_get_current_frame_data (xine_stream_t *stream,
switch (frame->format) {
+ default:
+ if (frame->proc_provide_standard_frame_data) {
+ uint8_t *img = data->img;
+ size_t img_size = data->img_size;
+ data->img = 0;
+ data->img_size = 0;
+
+ /* ask frame implementation for required img buffer size */
+ frame->proc_provide_standard_frame_data(frame, data);
+ required_size = data->img_size;
+
+ data->img = img;
+ data->img_size = img_size;
+ break;
+ }
+
+ if (!data->img && !(flags & XINE_FRAME_DATA_ALLOCATE_IMG))
+ break; /* not interested in image data */
+
+ xprintf (stream->xine, XINE_VERBOSITY_DEBUG,
+ "xine: error, snapshot function not implemented for format 0x%x\n", frame->format);
+ /* fall though and provide "green" YV12 image */
+ data->format = XINE_IMGFMT_YV12;
+
case XINE_IMGFMT_YV12:
required_size = frame->width * frame->height
+ ((frame->width + 1) / 2) * ((frame->height + 1) / 2)
@@ -2006,26 +2032,21 @@ static int _x_get_current_frame_data (xine_stream_t *stream,
+ ((frame->width + 1) / 2) * frame->height;
break;
- default:
- if (data->img || (flags & XINE_FRAME_DATA_ALLOCATE_IMG)) {
- xprintf (stream->xine, XINE_VERBOSITY_DEBUG,
- "xine: error, snapshot function not implemented for format 0x%x\n", frame->format);
- _x_abort ();
- }
-
- required_size = 0;
}
if (flags & XINE_FRAME_DATA_ALLOCATE_IMG) {
/* return allocated buffer size */
data->img_size = required_size;
/* allocate img or fail */
- if (!(data->img = calloc(1, required_size)))
+ if (!(data->img = calloc(1, required_size))) {
+ frame->free(frame);
return 0;
+ }
} else {
/* fail if supplied buffer is to small */
if (data->img && !img_size_unknown && data->img_size < required_size) {
data->img_size = required_size;
+ frame->free(frame);
return 0;
}
/* return used buffer size */
@@ -2061,11 +2082,14 @@ static int _x_get_current_frame_data (xine_stream_t *stream,
break;
default:
- xprintf (stream->xine, XINE_VERBOSITY_DEBUG,
- "xine: error, snapshot function not implemented for format 0x%x\n", frame->format);
- _x_abort ();
+ if (frame->proc_provide_standard_frame_data)
+ frame->proc_provide_standard_frame_data(frame, data);
+ else if (!(flags & XINE_FRAME_DATA_ALLOCATE_IMG))
+ memset(data->img, 0, data->img_size);
}
}
+
+ frame->free(frame);
return 1;
}
diff --git a/src/xine-engine/xine_interface.c b/src/xine-engine/xine_interface.c
index 4f59785a1..08ff4dc22 100644
--- a/src/xine-engine/xine_interface.c
+++ b/src/xine-engine/xine_interface.c
@@ -856,8 +856,12 @@ void xine_osd_draw_bitmap(xine_osd_t *this, uint8_t *bitmap,
}
void xine_osd_set_argb_buffer(xine_osd_t *this, uint32_t *argb_buffer,
- int x, int y, int width, int height) {
- this->osd.renderer->set_argb_buffer(&this->osd, argb_buffer, x, y, width, height);
+ int dirty_x, int dirty_y, int dirty_width, int dirty_height) {
+ this->osd.renderer->set_argb_buffer(&this->osd, argb_buffer, dirty_x, dirty_y, dirty_width, dirty_height);
+}
+
+void xine_osd_set_extent(xine_osd_t *this, int extent_width, int extent_height) {
+ this->osd.renderer->set_extent(&this->osd, extent_width, extent_height);
}