diff options
author | Reinhard Nißl <rnissl@gmx.de> | 2009-01-02 23:15:50 +0100 |
---|---|---|
committer | Reinhard Nißl <rnissl@gmx.de> | 2009-01-02 23:15:50 +0100 |
commit | 852aff94b4586982ff33bf21471cda90124a65bf (patch) | |
tree | 795274cd501d5d442e7a816a5852d587e562328d | |
parent | 6f5ac0bdb26d6574af48c44de78ef0378ce55756 (diff) | |
download | xine-lib-852aff94b4586982ff33bf21471cda90124a65bf.tar.gz xine-lib-852aff94b4586982ff33bf21471cda90124a65bf.tar.bz2 |
Extend OSD framework by ARGB layer and custom extent specification.
The ARGB layer is based on the idea and scratch implementation of Julian
Scheel. Each OSD object may be associated with a client ARGB buffer which
holds the content of the OSD, hence there is no need to copy the buffer
content.
So far an OSD's reference coordinate system was defined by coded video
resolution. By specifing an OSD's extent, capable hardware or software
implementations my scale an arbitrarily sized OSD to the video output
area while blending.
Additional constants have been defined to allow vo_drivers to report
their capabilities and to allow clients to check whether an OSD
implementation supports these new features.
-rw-r--r-- | include/xine.h | 28 | ||||
-rw-r--r-- | include/xine/osd.h | 34 | ||||
-rw-r--r-- | include/xine/video_out.h | 17 | ||||
-rw-r--r-- | src/xine-engine/osd.c | 173 | ||||
-rw-r--r-- | src/xine-engine/xine_interface.c | 10 |
5 files changed, 211 insertions, 51 deletions
diff --git a/include/xine.h b/include/xine.h index 613850b09..b4573bf73 100644 --- a/include/xine.h +++ b/include/xine.h @@ -2077,8 +2077,10 @@ void xine_event_send (xine_stream_t *stream, const xine_event_t *event) XINE_PRO /* yellow text, black border, transparent background */ #define XINE_TEXTPALETTE_YELLOW_BLACK_TRANSPARENT 3 -#define XINE_OSD_CAP_FREETYPE2 0x0001 /* freetype2 support compiled in */ -#define XINE_OSD_CAP_UNSCALED 0x0002 /* unscaled overlays supp. by vo drv */ +#define XINE_OSD_CAP_FREETYPE2 0x0001 /* freetype2 support compiled in */ +#define XINE_OSD_CAP_UNSCALED 0x0002 /* unscaled overlays supp. by vo drv */ +#define XINE_OSD_CAP_CUSTOM_EXTENT 0x0004 /* hardware scaled to match video output window */ +#define XINE_OSD_CAP_ARGB_LAYER 0x0008 /* supports separate true color layer */ typedef struct xine_osd_s xine_osd_t; @@ -2143,6 +2145,28 @@ void xine_osd_get_palette (xine_osd_t *self, uint32_t *color, void xine_osd_set_palette (xine_osd_t *self, const uint32_t *const color, const uint8_t *const trans ) XINE_PROTECTED; + +/* + * 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 xine_osd_set_argb_buffer(xine_osd_t *self, uint32_t *argb_buffer, + int dirty_x, int dirty_y, int dirty_width, int dirty_height) XINE_PROTECTED; + +/* + * define extent of reference coordinate system + * for video resolution independent osds. + * see also XINE_OSD_CAP_CUSTOM_EXTENT + */ +void xine_osd_set_extent(xine_osd_t *self, int extent_width, int extent_height) XINE_PROTECTED; + /* * close osd rendering engine * loaded fonts are unloaded diff --git a/include/xine/osd.h b/include/xine/osd.h index de924a1ae..b22c02996 100644 --- a/include/xine/osd.h +++ b/include/xine/osd.h @@ -40,7 +40,11 @@ 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; @@ -57,6 +61,12 @@ struct osd_object_s { osd_font_t *font; osd_ft2context_t *ft2; + + /* this holds an optional ARGB overlay, which + * is only be used by supported video_out modules. + * right now this is only vdpau */ + argb_layer_t argb_layer; + int32_t handle; }; @@ -205,7 +215,29 @@ struct osd_renderer_s { * see xine.h for defined XINE_OSD_CAP_ values. */ uint32_t (*get_capabilities) (osd_object_t *osd); - + + /* + * 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 dirty_x, int dirty_y, int dirty_width, int dirty_height); + + /* private stuff */ pthread_mutex_t osd_mutex; diff --git a/include/xine/video_out.h b/include/xine/video_out.h index 7b3c26497..cd32fd22f 100644 --- a/include/xine/video_out.h +++ b/include/xine/video_out.h @@ -298,6 +298,8 @@ struct xine_video_port_s { #define VO_CAP_AUTOPAINT_COLORKEY 0x00200000 #define VO_CAP_ZOOM_X 0x00400000 #define VO_CAP_ZOOM_Y 0x00800000 +#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 */ /* * vo_driver_s contains the functions every display driver @@ -426,6 +428,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 */ @@ -435,6 +445,10 @@ struct vo_overlay_s { int y; /* y start of subpicture area */ 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 */ @@ -450,6 +464,9 @@ struct vo_overlay_s { int hili_rgb_clut; /* true if clut was converted to rgb */ int unscaled; /* true if it should be blended unscaled */ + + + argb_layer_t *argb_layer; }; diff --git a/src/xine-engine/osd.c b/src/xine-engine/osd.c index a789b50d4..1d3754d42 100644 --- a/src/xine-engine/osd.c +++ b/src/xine-engine/osd.c @@ -236,15 +236,20 @@ static osd_object_t *XINE_MALLOC osd_new_object (osd_renderer_t *this, int width osd->renderer = this; 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; + + 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])); @@ -263,6 +268,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; +} + /* @@ -322,11 +339,17 @@ static int _osd_show (osd_object_t *osd, int64_t vpts, int unscaled ) { this->event.object.handle = osd->handle; memset( this->event.object.overlay, 0, sizeof(*this->event.object.overlay) ); + + 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; this->event.object.overlay->y = osd->display_y + osd->y1; 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; @@ -335,53 +358,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); + 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)); + 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; @@ -465,11 +494,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; } /* @@ -491,6 +523,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; @@ -550,7 +583,8 @@ 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; @@ -663,6 +697,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; @@ -1258,6 +1293,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); @@ -1606,6 +1642,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; } @@ -1651,6 +1688,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 ) { @@ -1669,21 +1707,58 @@ 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 dirty_x, int dirty_y, int dirty_width, int dirty_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; } @@ -1753,8 +1828,10 @@ osd_renderer_t *_x_osd_renderer_init( xine_stream_t *stream ) { this->get_text_size = osd_get_text_size; this->close = osd_renderer_close; this->draw_bitmap = osd_draw_bitmap; + 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/xine_interface.c b/src/xine-engine/xine_interface.c index 217272a97..43a40f51c 100644 --- a/src/xine-engine/xine_interface.c +++ b/src/xine-engine/xine_interface.c @@ -846,6 +846,16 @@ void xine_osd_draw_bitmap(xine_osd_t *this, uint8_t *bitmap, this->osd.renderer->draw_bitmap(&this->osd, bitmap, x1, y1, width, height, palette_map); } +void xine_osd_set_argb_buffer(xine_osd_t *this, uint32_t *argb_buffer, + 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); +} + + const char *const *xine_post_list_inputs(xine_post_t *this_gen) { post_plugin_t *this = (post_plugin_t *)this_gen; return this->input_ids; |