diff options
author | phintuka <phintuka> | 2013-01-15 20:33:29 +0000 |
---|---|---|
committer | phintuka <phintuka> | 2013-01-15 20:33:29 +0000 |
commit | 6eb935429d9b03858fc7058e1a183bf82f844bcf (patch) | |
tree | d91d9f1c6af90b261fe211cca2d1f7dd2ec572bb | |
parent | b347d3265c249d9a0bffe1f393ae0e6c291c81e6 (diff) | |
download | xineliboutput-6eb935429d9b03858fc7058e1a183bf82f844bcf.tar.gz xineliboutput-6eb935429d9b03858fc7058e1a183bf82f844bcf.tar.bz2 |
Support ARGB OSD with vdpau / opengl2 video drivers.
Untested with vdpau. Opengl2 driver needs some fixing.
May require setting video size in OSD settings to match output window size.
Also playing with hardware / software / scaling options may help ...
-rw-r--r-- | xine/osd_manager.c | 206 | ||||
-rw-r--r-- | xine/osd_manager.h | 4 | ||||
-rw-r--r-- | xine_input_vdr.c | 9 |
3 files changed, 214 insertions, 5 deletions
diff --git a/xine/osd_manager.c b/xine/osd_manager.c index d4e2d615..3de7088c 100644 --- a/xine/osd_manager.c +++ b/xine/osd_manager.c @@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: osd_manager.c,v 1.23 2011-03-07 12:36:39 phintuka Exp $ + * $Id: osd_manager.c,v 1.24 2013-01-15 20:33:29 phintuka Exp $ * */ @@ -46,6 +46,11 @@ typedef struct { uint16_t video_window_h; int64_t last_changed_vpts; + +#ifdef VO_CAP_ARGB_LAYER_OVERLAY + argb_layer_t *argb_layer; + uint32_t *argb_buffer; +#endif } osd_data_t; typedef struct osd_manager_impl_s { @@ -68,6 +73,50 @@ typedef struct osd_manager_impl_s { /************************************* Tools ************************************/ /* + * argb layer (originally copied from xine - why aren't these functions exported ?) + */ + +#ifdef VO_CAP_ARGB_LAYER_OVERLAY +static argb_layer_t *argb_layer_create() { + + argb_layer_t *argb_layer = (argb_layer_t *)calloc(1, sizeof (argb_layer_t)); + + pthread_mutex_init(&argb_layer->mutex, NULL); + + return argb_layer; +} + +static void argb_layer_destroy(argb_layer_t *argb_layer) { + + pthread_mutex_destroy(&argb_layer->mutex); + free(argb_layer); +} + +static void set_argb_layer(argb_layer_t **dst, argb_layer_t *src) { + + if (src) { + pthread_mutex_lock(&src->mutex); + ++src->ref_count; + pthread_mutex_unlock(&src->mutex); + } + + if (*dst) { + int free_argb_layer; + + pthread_mutex_lock(&(*dst)->mutex); + free_argb_layer = (0 == --(*dst)->ref_count); + pthread_mutex_unlock(&(*dst)->mutex); + + if (free_argb_layer) + argb_layer_destroy(*dst); + } + + *dst = src; +} +#endif /* VO_CAP_ARGB_LAYER_OVERLAY */ + + +/* * acquire_ticket() */ static void acquire_ticket(osd_manager_impl_t *this) @@ -258,6 +307,12 @@ static int exec_osd_size(osd_manager_impl_t *this, osd_command_t *cmd) acquire_ticket(this); +#ifdef VO_CAP_ARGB_LAYER_OVERLAY + set_argb_layer(&osd->argb_layer, NULL); + free(osd->argb_buffer); + osd->argb_buffer = NULL; +#endif + xine_video_port_t *video_out = this->stream->video_out; this->vo_scaling = !!(video_out->get_capabilities(video_out) & VO_XCAP_OSDSCALING); @@ -348,6 +403,12 @@ static int exec_osd_close(osd_manager_impl_t *this, osd_command_t *cmd) osd->extent_height = 576; osd->last_changed_vpts = 0; +#ifdef VO_CAP_ARGB_LAYER_OVERLAY + set_argb_layer(&osd->argb_layer, NULL); + free(osd->argb_buffer); + osd->argb_buffer = NULL; +#endif + return CONTROL_OK; } @@ -537,8 +598,138 @@ static int exec_osd_set_lut8(osd_manager_impl_t *this, osd_command_t *cmd) static int exec_osd_set_argb(osd_manager_impl_t *this, osd_command_t *cmd) { - LOGMSG("OSD_Set_ARGB not implemented"); +#ifdef VO_CAP_ARGB_LAYER_OVERLAY + video_overlay_manager_t *ovl_manager = get_ovl_manager(this); + video_overlay_event_t ov_event = {0}; + vo_overlay_t ov_overlay = {0}; + osd_data_t *osd = &this->osd[cmd->wnd]; + int handle = osd->handle; + + if (!ovl_manager) + return CONTROL_PARAM_ERROR; + + if (!this->mgr.argb_supported(this->stream)) { + LOGMSG("ARGB overlay not supported by video driver"); + return CONTROL_PARAM_ERROR; + } + + if (osd->extent_width < 32 || osd->extent_height < 32) { + LOGMSG("ARGB overlay: incorrect extent"); + return CONTROL_PARAM_ERROR; + } + + this->stream->video_out->enable_ovl(this->stream->video_out, 1); + + /* get / allocate OSD handle */ + if (handle < 0) { + handle = ovl_manager->get_handle(ovl_manager,0); + osd->handle = handle; + osd->extent_width = osd->extent_width ?: 720; + osd->extent_height = osd->extent_height ?: 576; + osd->last_changed_vpts = 0; + } + + /* fill SHOW event */ + ov_event.event_type = OVERLAY_EVENT_SHOW; + ov_event.vpts = osd_exec_vpts(this, cmd); + ov_event.object.handle = handle; + ov_event.object.overlay = &ov_overlay; + ov_event.object.object_type = 1; /* menu */ + + /* ARGB overlays are not cached for re-scaling */ + clear_osdcmd(&osd->cmd); + + /* fill ov_overlay */ + ov_overlay.x = 0; + ov_overlay.y = 0; + ov_overlay.width = osd->extent_width; + ov_overlay.height = osd->extent_height; + + /* tag this overlay */ + ov_overlay.hili_rgb_clut = VDR_OSD_MAGIC; + + /* fill extra data */ + const vdr_osd_extradata_t extra_data = { + extent_width: osd->extent_width, + extent_height: osd->extent_height, + layer: cmd->layer, + scaling: cmd->scaling + }; + memcpy(ov_overlay.hili_color, &extra_data, sizeof(extra_data)); + + /* xine-lib 1.2 extensions */ + ov_overlay.extent_width = osd->extent_width; + ov_overlay.extent_height = osd->extent_height; + ov_overlay.video_window_x = osd->video_window_x ?: -1; + ov_overlay.video_window_y = osd->video_window_y ?: -1; + ov_overlay.video_window_width = osd->video_window_w ?: -1; + ov_overlay.video_window_height = osd->video_window_h ?: -1; + + /* this should trigger blending at output resolution (after scaling video frame) ... */ + //ov_overlay.unscaled = 1; + + /* allocate buffer */ + if (!osd->argb_buffer) { + osd->argb_buffer = calloc(sizeof(uint32_t), osd->extent_width * osd->extent_height); + } + if (!osd->argb_layer) { + set_argb_layer(&osd->argb_layer, argb_layer_create()); + osd->argb_layer->buffer = osd->argb_buffer; + } + + /* copy changed data to buffer */ + /* TODO: do we need double-buffering or locking to prevent tearing ? */ + + uint32_t *src = (uint32_t*)cmd->raw_data; + uint32_t* dst = osd->argb_buffer; + int stride = cmd->w; + int lines = cmd->h; + + /* clip */ + if (cmd->x + cmd->w > osd->extent_width) { + stride = osd->extent_width - cmd->x; + if (stride < 0) stride = 0; + LOGMSG("ARGB overlay: incorrect extent, cropping right side"); + } + if (cmd->y + cmd->h > osd->extent_height) { + lines = osd->extent_height - cmd->y; + LOGMSG("ARGB overlay: incorrect extent, cropping bottom"); + } + + /* blend */ + dst += cmd->y * osd->extent_width + cmd->x; + for (; lines > 0; lines--) { + memcpy(dst, src, stride * sizeof(uint32_t)); + src += cmd->w; + dst += osd->extent_width; + } + + /* set dirty area. not used in opengl2 driver ... */ + osd->argb_layer->x1 = cmd->x; + osd->argb_layer->x2 = cmd->x + cmd->w - 1; + osd->argb_layer->y1 = cmd->y; + osd->argb_layer->y2 = cmd->y + cmd->h - 1; + + /* set buffer (ref-counted) */ + set_argb_layer(&ov_overlay.argb_layer, osd->argb_layer); + + /* send event to overlay manager */ + while (ovl_manager->add_event(ovl_manager, (void *)&ov_event) < 0) { + LOGMSG("OSD_Set_ARGB(%d): overlay manager queue full !", cmd->wnd); + ovl_manager->flush_events(ovl_manager); + } + + /* release buffer (ref-counted) */ + set_argb_layer(&ov_overlay.argb_layer, NULL); + + osd->last_changed_vpts = ov_event.vpts ?: xine_get_current_vpts(this->stream); + + return CONTROL_OK; + +#else /* VO_CAP_ARGB_LAYER_OVERLAY */ + LOGMSG("OSD_Set_ARGB: plugin was build without ARGB support"); return CONTROL_PARAM_ERROR; +#endif } /* @@ -743,6 +934,16 @@ static void video_size_changed(osd_manager_t *this_gen, xine_stream_t *stream, i pthread_mutex_unlock(&this->lock); } +static int argb_supported(xine_stream_t *stream) +{ +#ifdef VO_CAP_ARGB_LAYER_OVERLAY + xine_video_port_t *video_out = stream->video_out; + return !!(video_out->get_capabilities(video_out) & VO_CAP_ARGB_LAYER_OVERLAY); +#else + return 0; +#endif +} + /* * osd_manager_dispose() */ @@ -787,6 +988,7 @@ osd_manager_t *init_osd_manager(void) this->mgr.command = exec_osd_command; this->mgr.dispose = osd_manager_dispose; this->mgr.video_size_changed = video_size_changed; + this->mgr.argb_supported = argb_supported; pthread_mutex_init(&this->lock, NULL); diff --git a/xine/osd_manager.h b/xine/osd_manager.h index d71336ed..5a5ec1e9 100644 --- a/xine/osd_manager.h +++ b/xine/osd_manager.h @@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: osd_manager.h,v 1.1 2008-12-06 16:17:18 phintuka Exp $ + * $Id: osd_manager.h,v 1.2 2013-01-15 20:33:29 phintuka Exp $ * */ @@ -28,6 +28,8 @@ struct osd_manager_s { void (*dispose)(osd_manager_t *, xine_stream_t *); void (*video_size_changed)(osd_manager_t *, xine_stream_t *, int width, int height); + + int (*argb_supported)(xine_stream_t *); }; osd_manager_t *init_osd_manager(void); diff --git a/xine_input_vdr.c b/xine_input_vdr.c index 32078532..c53d48b0 100644 --- a/xine_input_vdr.c +++ b/xine_input_vdr.c @@ -4,7 +4,7 @@ * See the main source file 'xineliboutput.c' for copyright information and * how to reach the author. * - * $Id: xine_input_vdr.c,v 1.363 2012-07-18 11:55:33 phintuka Exp $ + * $Id: xine_input_vdr.c,v 1.364 2013-01-15 20:33:29 phintuka Exp $ * */ @@ -136,7 +136,7 @@ typedef struct { # include <linux/unistd.h> /* syscall(__NR_gettid) */ #endif -static const char module_revision[] = "$Id: xine_input_vdr.c,v 1.363 2012-07-18 11:55:33 phintuka Exp $"; +static const char module_revision[] = "$Id: xine_input_vdr.c,v 1.364 2013-01-15 20:33:29 phintuka Exp $"; static const char log_module_input_vdr[] = "[input_vdr] "; #define LOG_MODULENAME log_module_input_vdr #define SysLogLevel iSysLogLevel @@ -3602,6 +3602,11 @@ static void *vdr_control_thread(void *this_gen) counter--; } + if (this->osd_manager && this->osd_manager->argb_supported(this->stream)) { + LOGMSG("ARGB OSD supported by video driver"); + puts_vdr(this, "INFO ARGBOSD\r\n"); + } + write_control(this, "CONFIG\r\n"); while(this->control_running) { |