diff options
| author | Reinhard Nißl <rnissl@gmx.de> | 2009-01-02 18:00:01 +0000 |
|---|---|---|
| committer | Reinhard Nißl <rnissl@gmx.de> | 2009-01-02 18:00:01 +0000 |
| commit | db791923958fd4c72f75d4fede7aff189ff879a2 (patch) | |
| tree | 42445acb47eba45f3015d44d1b5008ec227fbcc9 /src/xine-engine | |
| parent | fd02e4d93b00d02cf784018c274c26a142324003 (diff) | |
| download | xine-lib-db791923958fd4c72f75d4fede7aff189ff879a2.tar.gz xine-lib-db791923958fd4c72f75d4fede7aff189ff879a2.tar.bz2 | |
Add framegrabbing support; extend ARGB OSD interface.
Diffstat (limited to 'src/xine-engine')
| -rw-r--r-- | src/xine-engine/osd.c | 173 | ||||
| -rw-r--r-- | src/xine-engine/osd.h | 25 | ||||
| -rw-r--r-- | src/xine-engine/video_out.h | 24 | ||||
| -rw-r--r-- | src/xine-engine/xine.c | 48 | ||||
| -rw-r--r-- | src/xine-engine/xine_interface.c | 8 |
5 files changed, 202 insertions, 76 deletions
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); } |
