summaryrefslogtreecommitdiff
path: root/src/xine-engine
diff options
context:
space:
mode:
authorMiguel Freitas <miguelfreitas@users.sourceforge.net>2001-11-28 22:19:10 +0000
committerMiguel Freitas <miguelfreitas@users.sourceforge.net>2001-11-28 22:19:10 +0000
commitd48b3bf8769a8ac1741d819289ed9ea117764bc5 (patch)
treeb90a868f2118128d8b0bcff135f9b0ac3d46ae73 /src/xine-engine
parent157c020ba6d577c45678b7b59f96b3ca646fa525 (diff)
downloadxine-lib-d48b3bf8769a8ac1741d819289ed9ea117764bc5.tar.gz
xine-lib-d48b3bf8769a8ac1741d819289ed9ea117764bc5.tar.bz2
* OSD (On Screen Display) for rendering text and graphics into overlays
* reworked spu and overlay manager (multiple overlays supported) CVS patchset: 1126 CVS date: 2001/11/28 22:19:10
Diffstat (limited to 'src/xine-engine')
-rw-r--r--src/xine-engine/Makefile.am7
-rw-r--r--src/xine-engine/osd.c709
-rw-r--r--src/xine-engine/osd.h159
-rw-r--r--src/xine-engine/video_out.c39
-rw-r--r--src/xine-engine/video_out.h41
-rw-r--r--src/xine-engine/video_overlay.c550
-rw-r--r--src/xine-engine/video_overlay.h66
-rw-r--r--src/xine-engine/xine.c17
-rw-r--r--src/xine-engine/xine_internal.h4
9 files changed, 1546 insertions, 46 deletions
diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am
index ad67530f2..ccf76e5e7 100644
--- a/src/xine-engine/Makefile.am
+++ b/src/xine-engine/Makefile.am
@@ -9,8 +9,9 @@ lib_LTLIBRARIES = libxine.la
libxine_la_SOURCES = xine.c metronom.c configfile.c buffer.c \
load_plugins.c video_decoder.c buffer_types.c \
- audio_decoder.c video_out.c audio_out.c resample.c events.c lrb.c
-libxine_la_LIBADD = $(THREAD_LIBS) $(DYNAMIC_LD_LIBS) -lm
+ audio_decoder.c video_out.c audio_out.c resample.c events.c lrb.c \
+ video_overlay.c osd.c
+libxine_la_LIBADD = $(THREAD_LIBS) $(DYNAMIC_LD_LIBS) -lm -lz
libxine_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
@@ -18,7 +19,7 @@ libxine_la_LDFLAGS = \
include_HEADERS = buffer.h metronom.h configfile.h \
audio_out.h resample.h video_out.h xine_internal.h spu_decoder.h \
- events.h lrb.h
+ events.h lrb.h video_overlay.h osd.h
noinst_HEADERS = bswap.h
diff --git a/src/xine-engine/osd.c b/src/xine-engine/osd.c
new file mode 100644
index 000000000..aaad50a63
--- /dev/null
+++ b/src/xine-engine/osd.c
@@ -0,0 +1,709 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * OSD stuff (text and graphic primitives)
+ */
+
+#define __OSD_C__
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <zlib.h>
+
+#include "events.h"
+#include "video_overlay.h"
+#include "xine_internal.h"
+#include "video_out/alphablend.h"
+#include "xine-engine/bswap.h"
+#include "xineutils.h"
+#include "video_out.h"
+#include "osd.h"
+
+/*
+#define LOG_DEBUG 1
+*/
+
+#ifdef DEBUG
+
+# ifdef __GNUC__
+# define LOG(lvl, fmt...) fprintf (stderr, fmt);
+# else
+# define LOG(lvl, ...) fprintf (stderr, __VA_ARGS__);
+# endif
+
+#else /* !DEBUG */
+
+# ifdef __GNUC__
+# define LOG(lvl, fmt...)
+# else
+# define LOG(lvl, ...)
+# endif
+
+#endif /* !DEBUG */
+
+
+#define MAX(a,b) ( (a) > (b) ) ? (a) : (b)
+#define MIN(a,b) ( (a) < (b) ) ? (a) : (b)
+
+/*
+ initialize the osd rendering engine
+*/
+
+osd_renderer_t *osd_renderer_init( video_overlay_instance_t *video_overlay )
+{
+ osd_renderer_t *this;
+
+ this = xine_xmalloc(sizeof(osd_renderer_t));
+ this->video_overlay = video_overlay;
+ this->event.object.overlay = xine_xmalloc( sizeof(vo_overlay_t) );
+
+ pthread_mutex_init (&this->osd_mutex, NULL);
+
+#ifdef LOG_DEBUG
+ printf("osd_renderer_init %p\n", this);
+#endif
+
+ return this;
+}
+
+void osd_renderer_exit( osd_renderer_t *this )
+{
+
+ while( this->osds )
+ osd_close( this->osds );
+
+ while( this->fonts )
+ osd_renderer_unload_font( this, this->fonts->name );
+
+ free(this);
+}
+
+
+/*
+ open a new osd object. this will allocated an empty (all zero) drawing
+ area where graphic primitives may be used.
+ It is ok to specify big width and height values. The render will keep
+ track of the smallest changed area to not generate too big overlays.
+ A default palette is initialized (i sugest keeping color 0 as transparent
+ for the sake of simplicity)
+*/
+
+osd_object_t *osd_open(osd_renderer_t *this, int width, int height)
+{
+ osd_object_t *osd;
+
+ static clut_t default_color[] = {
+ CLUT_Y_CR_CB_INIT(0x00, 0x00, 0x00),
+ CLUT_Y_CR_CB_INIT(0x80, 0x80, 0x80),
+ CLUT_Y_CR_CB_INIT(0xff, 0x90, 0x00),
+ CLUT_Y_CR_CB_INIT(0xff, 0x80, 0x80)
+ };
+ static uint8_t default_trans[] = {0, 7, 15, 15};
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ osd = xine_xmalloc( sizeof(osd_object_t) );
+ osd->renderer = this;
+ osd->next = this->osds;
+ this->osds = osd;
+
+ osd->width = width;
+ osd->height = height;
+ osd->area = xine_xmalloc( width * height );
+
+ osd->x1 = width;
+ osd->y1 = height;
+ osd->x2 = 0;
+ osd->y2 = 0;
+
+ memcpy(osd->color, default_color, sizeof(default_color));
+ memcpy(osd->trans, default_trans, sizeof(default_trans));
+
+ osd->handle = -1;
+
+ pthread_mutex_unlock (&this->osd_mutex);
+
+#ifdef LOG_DEBUG
+ printf("osd_open %p [%dx%d]\n", osd, width, height);
+#endif
+
+ return osd;
+}
+
+
+/*
+ free osd object
+*/
+
+void osd_close(osd_object_t *osd_to_close)
+{
+ osd_renderer_t *this = osd_to_close->renderer;
+ osd_object_t *osd, *last;
+
+ if( osd_to_close->handle >= 0 )
+ osd_hide(osd_to_close,0);
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ last = NULL;
+ osd = this->osds;
+ while( osd ) {
+ if ( osd == osd_to_close ) {
+ free( osd->area );
+
+ if( last )
+ last->next = osd->next;
+ else
+ this->osds = osd->next;
+ free( osd );
+ break;
+ }
+ last = osd;
+ osd = osd->next;
+ }
+ pthread_mutex_unlock (&this->osd_mutex);
+}
+
+
+/*
+ send the osd to be displayed at given pts (0=now)
+ the object is not changed. there may be subsequent drawing on it.
+*/
+int osd_show(osd_object_t *osd, uint32_t vpts )
+{
+ osd_renderer_t *this = osd->renderer;
+ rle_elem_t rle, *rle_p=0;
+ int x, y, spare;
+ uint8_t *c;
+
+#ifdef LOG_DEBUG
+ printf("osd_show %p vpts=%d\n", osd, vpts);
+#endif
+
+ if( osd->handle >= 0 )
+ return 0; /* must hide first */
+
+ if( (osd->handle = this->video_overlay->get_handle(this->video_overlay,0)) == -1 )
+ return 0;
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ /* check if osd is valid (something draw on it) */
+ if( osd->x2 >= osd->x1 ) {
+
+ this->event.object.handle = osd->handle;
+ /* not really needed this, but good pratice to clean it up */
+ memset( this->event.object.overlay, 0, sizeof(this->event.object.overlay) );
+ 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 + 1;
+ this->event.object.overlay->height = osd->y2 - osd->y1 + 1;
+
+ this->event.object.overlay->clip_top = 0;
+ this->event.object.overlay->clip_bottom = this->event.object.overlay->height - 1;
+ this->event.object.overlay->clip_left = 0;
+ this->event.object.overlay->clip_right = this->event.object.overlay->width - 1;
+
+ spare = osd->y2 - osd->y1;
+
+ this->event.object.overlay->data_size = 1024;
+ 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++ ) {
+ rle.len = 0;
+ c = osd->area + y * osd->width + osd->x1;
+ for( x = osd->x1; x <= osd->x2; x++, c++ ) {
+ if( rle.color != *c ) {
+ if( rle.len ) {
+ if( (this->event.object.overlay->num_rle + spare) * sizeof(rle_elem_t) >
+ this->event.object.overlay->data_size ) {
+ this->event.object.overlay->data_size += 1024;
+ rle_p = this->event.object.overlay->rle =
+ realloc( this->event.object.overlay->rle,
+ this->event.object.overlay->data_size * sizeof(rle_elem_t) );
+ rle_p += 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_p++ = rle;
+ this->event.object.overlay->num_rle++;
+ }
+
+#ifdef LOG_DEBUG
+ printf("osd_show num_rle = %d\n", this->event.object.overlay->num_rle);
+#endif
+
+ 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 = EVENT_SHOW_SPU;
+ this->event.vpts = vpts;
+ this->video_overlay->add_event(this->video_overlay,(void *)&this->event);
+ }
+ pthread_mutex_unlock (&this->osd_mutex);
+
+ return 1;
+}
+
+/*
+ send event to hide osd at given pts (0=now)
+ the object is not changed. there may be subsequent drawing on it.
+*/
+int osd_hide(osd_object_t *osd, uint32_t vpts )
+{
+ osd_renderer_t *this = osd->renderer;
+
+#ifdef LOG_DEBUG
+ printf("osd_hide %p vpts=%d\n",osd, vpts);
+#endif
+
+ if( osd->handle < 0 )
+ return 0;
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ this->event.object.handle = osd->handle;
+ osd->handle = -1; /* handle will be freed after hide */
+
+ /* not really needed this, but good pratice to clean it up */
+ memset( this->event.object.overlay, 0, sizeof(this->event.object.overlay) );
+
+ this->event.event_type = EVENT_HIDE_SPU;
+ this->event.vpts = vpts;
+ this->video_overlay->add_event(this->video_overlay,(void *)&this->event);
+
+ pthread_mutex_unlock (&this->osd_mutex);
+
+ return 1;
+}
+
+/*
+ Bresenham line implementation on osd object
+*/
+
+void osd_line(osd_object_t *osd,
+ int x1, int y1, int x2, int y2, int color )
+{
+ uint8_t *c;
+ int dx, dy, t, inc, d, inc1, inc2;
+
+#ifdef LOG_DEBUG
+ printf("osd_line %p (%d,%d)-(%d,%d)\n",osd, x1,y1, x2,y2 );
+#endif
+
+ /* update clipping area */
+ t = MIN( x1, x2 );
+ osd->x1 = MIN( osd->x1, t );
+ t = MAX( x1, x2 );
+ osd->x2 = MAX( osd->x2, t );
+ t = MIN( y1, y2 );
+ osd->y1 = MIN( osd->y1, t );
+ t = MAX( y1, y2 );
+ osd->y2 = MAX( osd->y2, t );
+
+ dx = abs(x1-x2);
+ dy = abs(y1-y2);
+
+ if( dx>=dy ) {
+ if( x1>x2 )
+ {
+ t = x2; x2 = x1; x1 = t;
+ t = y2; y2 = y1; y1 = t;
+ }
+
+ if( y2 > y1 ) inc = 1; else inc = -1;
+
+ inc1 = 2*dy;
+ d = inc1 - dx;
+ inc2 = 2*(dy-dx);
+
+ c = osd->area + y1 * osd->width + x1;
+
+ while(x1<x2)
+ {
+ *c++ = color;
+ x1++;
+ if( d<0 ) {
+ d+=inc1;
+ } else {
+ y1+=inc;
+ d+=inc2;
+ c = osd->area + y1 * osd->width + x1;
+ }
+ }
+ } else {
+ if( y1>y2 ) {
+ t = x2; x2 = x1; x1 = t;
+ t = y2; y2 = y1; y1 = t;
+ }
+
+ if( x2 > x1 ) inc = 1; else inc = -1;
+
+ inc1 = 2*dx;
+ d = inc1-dy;
+ inc2 = 2*(dx-dy);
+
+ c = osd->area + y1 * osd->width + x1;
+
+ while(y1<y2) {
+ *c = color;
+ c += osd->width;
+ y1++;
+ if( d<0 ) {
+ d+=inc1;
+ } else {
+ x1+=inc;
+ d+=inc2;
+ c = osd->area + y1 * osd->width + x1;
+ }
+ }
+ }
+}
+
+
+/*
+ filled retangle
+*/
+
+void osd_filled_rect(osd_object_t *osd,
+ int x1, int y1, int x2, int y2, int color )
+{
+ int x, y, dx, dy;
+
+#ifdef LOG_DEBUG
+ printf("osd_filled_rect %p (%d,%d)-(%d,%d)\n",osd, x1,y1, x2,y2 );
+#endif
+
+ /* update clipping area */
+ x = MIN( x1, x2 );
+ osd->x1 = MIN( osd->x1, x );
+ dx = MAX( x1, x2 );
+ osd->x2 = MAX( osd->x2, dx );
+ y = MIN( y1, y2 );
+ osd->y1 = MIN( osd->y1, y );
+ dy = MAX( y1, y2 );
+ osd->y2 = MAX( osd->y2, dy );
+
+ dx -= x;
+ dy -= y;
+
+ for( ; dy--; y++ ) {
+ memset(osd->area + y * osd->width + x,color,dx);
+ }
+}
+
+/*
+ set palette (color and transparency)
+*/
+
+void osd_set_palette(osd_object_t *osd, uint32_t *color, uint8_t *trans )
+{
+ memcpy(osd->color, color, sizeof(osd->color));
+ memcpy(osd->trans, trans, sizeof(osd->trans));
+}
+
+/*
+ get palette (color and transparency)
+*/
+
+void osd_get_palette(osd_object_t *osd, uint32_t *color, uint8_t *trans )
+{
+ memcpy(color, osd->color, sizeof(osd->color));
+ memcpy(trans, osd->trans, sizeof(osd->trans));
+}
+
+/*
+ set position were overlay will be blended
+*/
+
+void osd_set_position(osd_object_t *osd, int x, int y )
+{
+ osd->display_x = x;
+ osd->display_y = y;
+}
+
+static uint16_t gzread_i16(gzFile *fp) {
+ uint16_t ret;
+ ret = gzgetc(fp);
+ ret |= (gzgetc(fp)<<8);
+ return ret;
+}
+
+/*
+ load bitmap font into osd engine
+ returns the internal font name to be used with other functions
+ FIXME: check if font is already loaded!
+*/
+
+char * osd_renderer_load_font(osd_renderer_t *this, char *name)
+{
+ gzFile *fp;
+ osd_font_t *font = NULL;
+ char *filename;
+ int i, ret = 0;
+
+#ifdef LOG_DEBUG
+ printf("osd_renderer_load_font %p name=%s\n", this, name );
+#endif
+
+ filename = malloc(strlen(name)+200);
+ sprintf(filename,"%s/%s.xinefont.gz",XINE_SKINDIR, name);
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ /* load quick & dirt font format */
+ /* fixme: check read errors... */
+ if( (fp = gzopen(filename,"rb")) != NULL ) {
+
+ font = xine_xmalloc( sizeof(osd_font_t) );
+
+ gzread(fp, font->name, sizeof(font->name) );
+ font->version = gzread_i16(fp);
+ font->num_fontchars = gzread_i16(fp);
+
+ font->fontchar = malloc( sizeof(osd_fontchar_t) * font->num_fontchars );
+
+#ifdef LOG_DEBUG
+ printf("font %s %d\n",font->name, font->num_fontchars);
+#endif
+ for( i = 0; i < font->num_fontchars; i++ ) {
+ font->fontchar[i].code = gzread_i16(fp);
+ font->fontchar[i].width = gzread_i16(fp);
+ font->fontchar[i].height = gzread_i16(fp);
+ font->fontchar[i].bmp = malloc(font->fontchar[i].width*font->fontchar[i].height);
+ if( gzread(fp,font->fontchar[i].bmp,
+ font->fontchar[i].width*font->fontchar[i].height) <= 0 )
+ break;
+#ifdef LOG_DEBUG
+ printf("char[%d] %dx%d\n",font->fontchar[i].code,font->fontchar[i].width,font->fontchar[i].height);
+#endif
+ }
+
+ if( i == font->num_fontchars ) {
+ ret = 1;
+
+ font->next = this->fonts;
+ this->fonts = font;
+ } else {
+ while( --i >= 0 ) {
+ free(font->fontchar[i].bmp);
+ }
+ free(font->fontchar);
+ free(font);
+ }
+
+ gzclose(fp);
+ }
+
+ pthread_mutex_unlock (&this->osd_mutex);
+ free(filename);
+
+ if( ret )
+ return font->name;
+ else
+ return NULL;
+}
+
+/*
+ unload font
+*/
+int osd_renderer_unload_font(osd_renderer_t *this, char *fontname )
+{
+ osd_font_t *font, *last;
+ osd_object_t *osd;
+ int i, ret = 0;
+
+#ifdef LOG_DEBUG
+ printf("osd_renderer_unload_font %p name=%s\n", this, fontname);
+#endif
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ osd = this->osds;
+ while( osd ) {
+ if( !strcmp(osd->font->name, fontname) )
+ osd->font = NULL;
+ osd = osd->next;
+ }
+
+ last = NULL;
+ font = this->fonts;
+ while( font ) {
+ if ( !strcmp(font->name,fontname) ) {
+
+ for( i = 0; i < font->num_fontchars; i++ ) {
+ free( font->fontchar[i].bmp );
+ }
+ free( font->fontchar );
+
+ if( last )
+ last->next = font->next;
+ else
+ this->fonts = font->next;
+ free( font );
+ break;
+ }
+ last = font;
+ font = font->next;
+ }
+
+ pthread_mutex_unlock (&this->osd_mutex);
+ return ret;
+}
+
+
+/*
+ set the font of osd object
+*/
+
+int osd_set_font( osd_object_t *osd, char *fontname )
+{
+ osd_renderer_t *this = osd->renderer;
+ osd_font_t *font;
+ int ret = 0;
+
+#ifdef LOG_DEBUG
+ printf("osd_set_font %p name=%s\n", osd, fontname);
+#endif
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ osd->font = NULL;
+
+ font = this->fonts;
+ while( font ) {
+ if( !strcmp(font->name, fontname) ) {
+ ret = 1;
+ osd->font = font;
+ }
+ font = font->next;
+ }
+
+ pthread_mutex_unlock (&this->osd_mutex);
+ return ret;
+}
+
+
+/*
+ render text on x,y position (8 bits version)
+ no \n yet
+*/
+int osd_render_text( osd_object_t *osd, int x1, int y1, char *text )
+{
+ osd_renderer_t *this = osd->renderer;
+ osd_font_t *font;
+ int i, y;
+ uint8_t *dst, *src;
+
+#ifdef LOG_DEBUG
+ printf("osd_render_text %p (%d,%d) \"%s\"\n", osd, x1, y1, text);
+#endif
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ font = osd->font;
+
+ if( x1 < osd->x1 ) osd->x1 = x1;
+ if( y1 < osd->y1 ) osd->y1 = y1;
+
+ while( font && *text ) {
+
+ for( i = 0; i < font->num_fontchars; i++ ) {
+ if( font->fontchar[i].code == (*text & 0xff) )
+ break;
+ }
+
+#ifdef LOG_DEBUG
+ printf("font %s [%d] %dx%d -> %d,%d\n",font->name, *text,
+ font->fontchar[i].width, font->fontchar[i].height,
+ x1,y1);
+#endif
+
+ if ( i != font->num_fontchars ) {
+ dst = osd->area + y1 * osd->width + x1;
+ src = font->fontchar[i].bmp;
+
+ for( y = 0; y < font->fontchar[i].height; y++ ) {
+ memcpy( dst, src, font->fontchar[i].width );
+ src += font->fontchar[i].width;
+ dst += osd->width;
+ }
+ x1 += font->fontchar[i].width;
+
+ if( x1 > osd->x2 ) osd->x2 = x1;
+ if( y1 + font->fontchar[i].height > osd->y2 )
+ osd->y2 = y1 + font->fontchar[i].height;
+ }
+ text++;
+ }
+
+ pthread_mutex_unlock (&this->osd_mutex);
+
+ return 1;
+}
+
+/*
+ get width and height of how text will be renderized
+*/
+int osd_get_text_size( osd_object_t *osd, char *text, int *width, int *height )
+{
+ osd_renderer_t *this = osd->renderer;
+ osd_font_t *font;
+ int i;
+
+#ifdef LOG_DEBUG
+ printf("osd_get_text_size %p \"%s\"\n", osd, text);
+#endif
+
+ pthread_mutex_lock (&this->osd_mutex);
+
+ font = osd->font;
+
+ *width = 0;
+ *height = 0;
+
+ while( *text ) {
+
+ for( i = 0; i < font->num_fontchars; i++ ) {
+ if( font->fontchar[i].code == *text )
+ break;
+ }
+
+ if ( i != font->num_fontchars ) {
+ if( font->fontchar[i].height > *height )
+ *height = font->fontchar[i].height;
+ *width += font->fontchar[i].width;
+ }
+ text++;
+ }
+
+ pthread_mutex_unlock (&this->osd_mutex);
+
+ return 1;
+}
+
diff --git a/src/xine-engine/osd.h b/src/xine-engine/osd.h
new file mode 100644
index 000000000..2e27faf93
--- /dev/null
+++ b/src/xine-engine/osd.h
@@ -0,0 +1,159 @@
+#ifndef __OSD_H__
+#define __OSD_H__
+
+#ifdef __OSD_C__
+
+typedef struct osd_object_s osd_object_t;
+typedef struct osd_renderer_s osd_renderer_t;
+typedef struct osd_fontchar_s osd_fontchar_t;
+typedef struct osd_font_s osd_font_t;
+
+struct osd_object_s {
+ osd_object_t *next;
+ osd_renderer_t *renderer;
+
+ int width, height; /* work area dimentions */
+ uint8_t *area; /* work area */
+ int display_x,display_y; /* where to display it in screen */
+
+ /* clipping box inside work area */
+ int x1, y1;
+ int x2, y2;
+
+ uint32_t color[16]; /* color lookup table */
+ uint8_t trans[16]; /* mixer key table */
+
+ int32_t handle;
+
+ osd_font_t *font;
+};
+
+
+struct osd_renderer_s {
+ pthread_mutex_t osd_mutex;
+ video_overlay_instance_t *video_overlay;
+ video_overlay_event_t event;
+ osd_object_t *osds;
+ osd_font_t *fonts;
+};
+
+struct osd_fontchar_s {
+ uint16_t code;
+ uint16_t width;
+ uint16_t height;
+ uint8_t *bmp;
+};
+
+struct osd_font_s {
+ char name[40];
+ uint16_t version;
+ uint16_t num_fontchars;
+ osd_fontchar_t *fontchar;
+ osd_font_t *next;
+};
+
+#else
+
+typedef void osd_object_t;
+typedef void osd_renderer_t;
+
+#endif
+
+/*
+ initialize the osd rendering engine
+*/
+osd_renderer_t *osd_renderer_init( video_overlay_instance_t *video_overlay );
+
+/* close osd rendering engine
+ loaded fonts are unloaded
+ osd objects are closed
+*/
+void osd_renderer_exit( osd_renderer_t *this );
+
+/*
+ open a new osd object. this will allocated an empty (all zero) drawing
+ area where graphic primitives may be used.
+ It is ok to specify big width and height values. The render will keep
+ track of the smallest changed area to not generate too big overlays.
+ A default palette is initialized (i sugest keeping color 0 as transparent
+ for the sake of simplicity)
+*/
+osd_object_t *osd_open(osd_renderer_t *this, int width, int height);
+
+
+/*
+ free osd object
+*/
+void osd_close(osd_object_t *osd_to_close);
+
+
+/*
+ send the osd to be displayed at given pts (0=now)
+ the object is not changed. there may be subsequent drawing on it.
+*/
+int osd_show(osd_object_t *osd, uint32_t vpts );
+
+/*
+ send event to hide osd at given pts (0=now)
+ the object is not changed. there may be subsequent drawing on it.
+*/
+int osd_hide(osd_object_t *osd, uint32_t vpts );
+
+/*
+ Bresenham line implementation on osd object
+*/
+void osd_line(osd_object_t *osd,
+ int x1, int y1, int x2, int y2, int color );
+
+/*
+ filled retangle
+*/
+void osd_filled_rect(osd_object_t *osd,
+ int x1, int y1, int x2, int y2, int color );
+
+/*
+ set palette (color and transparency)
+*/
+void osd_set_palette(osd_object_t *osd, uint32_t *color, uint8_t *trans );
+
+/*
+ get palette (color and transparency)
+*/
+void osd_get_palette(osd_object_t *osd, uint32_t *color, uint8_t *trans );
+
+/*
+ set position were overlay will be blended
+*/
+void osd_set_position(osd_object_t *osd, int x, int y );
+
+/*
+ load bitmap font into osd engine
+*/
+char * osd_renderer_load_font(osd_renderer_t *this, char *name);
+
+/*
+ unload font
+*/
+int osd_renderer_unload_font(osd_renderer_t *this, char *name );
+
+/*
+ set the font of osd object
+*/
+
+int osd_set_font( osd_object_t *osd, char *fontname );
+
+
+/*
+ render text on x,y position (8 bits version)
+ no \n yet
+*/
+int osd_render_text( osd_object_t *osd, int x1, int y1, char *text );
+
+/*
+ get width and height of how text will be renderized
+*/
+int osd_get_text_size( osd_object_t *osd, char *text, int *width, int *height );
+
+
+#endif
+
diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c
index 920b69577..b4acb22ad 100644
--- a/src/xine-engine/video_out.c
+++ b/src/xine-engine/video_out.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: video_out.c,v 1.57 2001/11/20 12:41:58 miguelfreitas Exp $
+ * $Id: video_out.c,v 1.58 2001/11/28 22:19:12 miguelfreitas Exp $
*
*/
@@ -297,16 +297,13 @@ static void *video_out_loop (void *this_gen) {
#endif
if (this->overlay_source) {
- /* This is the only way for the spu decoder to get pts values
+ /* This is the only way for the overlay manager to get pts values
* for flushing it's buffers. So don't remove it! */
- vo_overlay_t *ovl;
-
xine_profiler_start_count (prof_spu_blend);
- ovl = this->overlay_source->get_overlay (this->overlay_source, img->PTS);
- if (this->video_loop_running && ovl && this->driver->overlay_blend && this->overlay_enabled)
- this->driver->overlay_blend (this->driver, img, ovl);
-
+ this->overlay_source->multiple_overlay_blend (this->overlay_source, img->PTS,
+ this->driver, img,
+ this->video_loop_running && this->overlay_enabled);
xine_profiler_stop_count (prof_spu_blend);
}
@@ -408,7 +405,11 @@ static vo_frame_t *vo_get_frame (vo_instance_t *this,
}
static void vo_close (vo_instance_t *this) {
-
+
+ /* this will make sure all hide events were processed */
+ if (this->overlay_source)
+ this->overlay_source->flush_events (this->overlay_source);
+
if (this->video_loop_running) {
void *p;
@@ -570,19 +571,6 @@ static int vo_frame_draw (vo_frame_t *img) {
return frames_to_skip;
}
-static void vo_register_ovl_src (vo_instance_t *this, ovl_src_t *ovl_src)
-{
- this->overlay_source = ovl_src;
- ovl_src->metronom = this->metronom;
-}
-
-static void vo_unregister_ovl_src (vo_instance_t *this, ovl_src_t *ovl_src)
-{
- /* only remove the source if it is the same as registered */
- if (this->overlay_source == ovl_src)
- this->overlay_source = NULL;
-}
-
static void vo_enable_overlay (vo_instance_t *this, int overlay_enabled) {
this->overlay_enabled = overlay_enabled;
}
@@ -602,8 +590,6 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom) {
this->close = vo_close;
this->exit = vo_exit;
this->get_capabilities = vo_get_capabilities;
- this->register_ovl_src = vo_register_ovl_src;
- this->unregister_ovl_src = vo_unregister_ovl_src;
this->enable_ovl = vo_enable_overlay;
this->num_frames_delivered = 0;
@@ -612,9 +598,12 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, metronom_t *metronom) {
this->free_img_buf_queue = vo_new_img_buf_queue ();
this->display_img_buf_queue = vo_new_img_buf_queue ();
this->video_loop_running = 0;
- this->video_paused = 0;
+ this->video_paused = 0;
this->pts_per_frame = 0;
this->pts_per_half_frame = 0;
+
+ this->overlay_source = video_overlay_new_instance();
+ this->overlay_source->init (this->overlay_source);
this->overlay_enabled = 1;
for (i=0; i<NUM_FRAME_BUFFERS; i++) {
diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h
index 8e4ac0828..4f0acf681 100644
--- a/src/xine-engine/video_out.h
+++ b/src/xine-engine/video_out.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: video_out.h,v 1.30 2001/11/20 12:41:58 miguelfreitas Exp $
+ * $Id: video_out.h,v 1.31 2001/11/28 22:19:12 miguelfreitas Exp $
*
*
* xine version of video_out.h
@@ -53,6 +53,7 @@ typedef struct vo_driver_s vo_driver_t ;
typedef struct vo_instance_s vo_instance_t;
typedef struct img_buf_fifo_s img_buf_fifo_t;
typedef struct vo_overlay_s vo_overlay_t;
+typedef struct video_overlay_instance_s video_overlay_instance_t;
/* public part, video drivers may add private fields */
@@ -99,14 +100,6 @@ struct vo_frame_s {
void (*dispose) (vo_frame_t *vo_img);
};
-typedef struct ovl_src_s ovl_src_t;
-
-struct ovl_src_s {
- void *src_gen;
- vo_overlay_t* (*get_overlay) (ovl_src_t* self, int pts);
- metronom_t* metronom;
-};
-
struct vo_instance_s {
uint32_t (*get_capabilities) (vo_instance_t *this); /* for constants see below */
@@ -132,11 +125,9 @@ struct vo_instance_s {
vo_frame_t* (*get_last_frame) (vo_instance_t *this);
/* overlay stuff */
- void (*register_ovl_src) (vo_instance_t *this, ovl_src_t *ovl_src);
- void (*unregister_ovl_src) (vo_instance_t *this, ovl_src_t *ovl_src);
void (*enable_ovl) (vo_instance_t *this, int ovl_enable);
- ovl_src_t *overlay_source;
- int overlay_enabled;
+ video_overlay_instance_t *overlay_source;
+ int overlay_enabled;
/* video driver is no longer used by decoder => close */
void (*close) (vo_instance_t *this);
@@ -308,8 +299,8 @@ struct vo_overlay_s {
int width; /* width of subpicture area */
int height; /* height of subpicture area */
- uint32_t color[4]; /* color lookup table */
- uint8_t trans[4]; /* mixer key table */
+ uint32_t color[16]; /* color lookup table */
+ uint8_t trans[16]; /* mixer key table */
int rgb_clut; /* true if clut was converted to rgb*/
int clip_top;
@@ -319,6 +310,26 @@ struct vo_overlay_s {
};
+
+/* API to video_overlay */
+struct video_overlay_instance_s {
+ void (*init) (video_overlay_instance_t *this_gen);
+
+ int32_t (*get_handle) (video_overlay_instance_t *this_gen, int object_type );
+
+ void (*free_handle) (video_overlay_instance_t *this_gen, int32_t handle);
+
+ int32_t (*add_event) (video_overlay_instance_t *this_gen, void *event);
+
+ void (*flush_events) (video_overlay_instance_t *this_gen );
+
+ void (*multiple_overlay_blend) (video_overlay_instance_t *this_gen, int vpts,
+ vo_driver_t *output, vo_frame_t *vo_img, int enabled);
+};
+
+video_overlay_instance_t *video_overlay_new_instance ();
+
+
/*
* build a video_out_instance from
* a given video driver
diff --git a/src/xine-engine/video_overlay.c b/src/xine-engine/video_overlay.c
new file mode 100644
index 000000000..099f0416b
--- /dev/null
+++ b/src/xine-engine/video_overlay.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: video_overlay.c,v 1.1 2001/11/28 22:19:11 miguelfreitas Exp $
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "buffer.h"
+#include "events.h"
+#include "xine_internal.h"
+#include "video_out/alphablend.h"
+#include "xine-engine/bswap.h"
+#include "xineutils.h"
+#include "video_overlay.h"
+
+/*
+#define LOG_DEBUG 1
+*/
+
+
+typedef struct video_overlay_events_s {
+ video_overlay_event_t *event;
+ uint32_t next_event;
+} video_overlay_events_t;
+
+typedef struct video_overlay_showing_s {
+ int32_t handle; /* -1 means not allocated */
+} video_overlay_showing_t;
+
+
+typedef struct video_overlay_s {
+ video_overlay_instance_t video_overlay;
+
+ pthread_mutex_t video_overlay_events_mutex;
+ video_overlay_events_t video_overlay_events[MAX_EVENTS];
+ pthread_mutex_t video_overlay_objects_mutex;
+ video_overlay_object_t video_overlay_objects[MAX_OBJECTS];
+ pthread_mutex_t video_overlay_showing_mutex;
+ video_overlay_showing_t video_overlay_showing[MAX_SHOWING];
+
+} video_overlay_t;
+
+
+static void add_showing_handle( video_overlay_t *this, int32_t handle )
+{
+ int i;
+
+ pthread_mutex_lock( &this->video_overlay_showing_mutex );
+
+ for( i = 0; i < MAX_SHOWING; i++ )
+ if( this->video_overlay_showing[i].handle == handle )
+ break; /* already showing */
+
+ if( i == MAX_SHOWING ) {
+ for( i = 0; i < MAX_SHOWING && this->video_overlay_showing[i].handle >= 0; i++ )
+ ;
+
+ if( i != MAX_SHOWING )
+ this->video_overlay_showing[i].handle = handle;
+ else
+ fprintf(stderr,"video_overlay: error: no showing slots available\n");
+ }
+
+ pthread_mutex_unlock( &this->video_overlay_showing_mutex );
+}
+
+static void remove_showing_handle( video_overlay_t *this, int32_t handle )
+{
+ int i;
+
+ pthread_mutex_lock( &this->video_overlay_showing_mutex );
+
+ for( i = 0; i < MAX_SHOWING; i++ ) {
+ if( this->video_overlay_showing[i].handle == handle ) {
+ this->video_overlay_showing[i].handle = -1;
+ }
+ }
+
+ pthread_mutex_unlock( &this->video_overlay_showing_mutex );
+}
+
+static void remove_events_handle( video_overlay_t *this, int32_t handle )
+{
+ uint32_t last_event,this_event;
+
+ pthread_mutex_lock( &this->video_overlay_events_mutex );
+
+ this_event=0;
+ do {
+ last_event=this_event;
+ this_event=this->video_overlay_events[last_event].next_event;
+
+ while( this_event &&
+ this->video_overlay_events[this_event].event->object.handle == handle ) {
+ /* remove event from pts list */
+ this->video_overlay_events[last_event].next_event=
+ this->video_overlay_events[this_event].next_event;
+
+ /* free its overlay */
+ if( this->video_overlay_events[this_event].event->object.overlay ) {
+ if( this->video_overlay_events[this_event].event->object.overlay->rle )
+ free( this->video_overlay_events[this_event].event->object.overlay->rle );
+ free(this->video_overlay_events[this_event].event->object.overlay);
+ this->video_overlay_events[this_event].event->object.overlay = NULL;
+ }
+
+ /* mark as free */
+ this->video_overlay_events[this_event].next_event = 0;
+ this->video_overlay_events[this_event].event->event_type = EVENT_NULL;
+
+ this_event=this->video_overlay_events[last_event].next_event;
+ }
+ } while ( this_event );
+
+ pthread_mutex_unlock( &this->video_overlay_events_mutex );
+}
+
+
+/*
+ allocate a handle from the object pool (exported function)
+ */
+static int32_t video_overlay_get_handle(video_overlay_instance_t *this_gen, int object_type ) {
+ video_overlay_t *this = (video_overlay_t *) this_gen;
+ int n;
+
+ pthread_mutex_lock( &this->video_overlay_objects_mutex );
+
+ for( n=0; n < MAX_OBJECTS && this->video_overlay_objects[n].handle > -1; n++ )
+ ;
+
+ if (n == MAX_OBJECTS) {
+ n = -1;
+ } else {
+ this->video_overlay_objects[n].handle = n;
+ this->video_overlay_objects[n].object_type = object_type;
+ }
+
+ pthread_mutex_unlock( &this->video_overlay_objects_mutex );
+ return n;
+}
+
+/*
+ free a handle from the object pool (internal function)
+ */
+static void internal_video_overlay_free_handle(video_overlay_t *this, int32_t handle) {
+
+ pthread_mutex_lock( &this->video_overlay_objects_mutex );
+
+ if( this->video_overlay_objects[handle].overlay ) {
+ if( this->video_overlay_objects[handle].overlay->rle )
+ free( this->video_overlay_objects[handle].overlay->rle );
+ free( this->video_overlay_objects[handle].overlay );
+ this->video_overlay_objects[handle].overlay = NULL;
+ }
+ this->video_overlay_objects[handle].handle = -1;
+
+ pthread_mutex_unlock( &this->video_overlay_objects_mutex );
+}
+
+/*
+ exported free handle function. must take care of removing the object
+ from showing and events lists.
+*/
+static void video_overlay_free_handle(video_overlay_instance_t *this_gen, int32_t handle) {
+ video_overlay_t *this = (video_overlay_t *) this_gen;
+
+ remove_showing_handle(this,handle);
+ remove_events_handle(this,handle);
+ internal_video_overlay_free_handle(this,handle);
+}
+
+
+
+static void video_overlay_reset (video_overlay_t *this) {
+ int i;
+
+ pthread_mutex_lock (&this->video_overlay_events_mutex);
+ for (i=0; i < MAX_EVENTS; i++) {
+ if (this->video_overlay_events[i].event == NULL) {
+ this->video_overlay_events[i].event = xine_xmalloc (sizeof(video_overlay_event_t));
+#ifdef LOG_DEBUG
+ printf ("video_overlay: MALLOC2: this->video_overlay_events[%d].event %p, len=%d\n",
+ i,
+ this->video_overlay_events[i].event,
+ sizeof(video_overlay_event_t));
+#endif
+ }
+ this->video_overlay_events[i].event->event_type = 0; /* Empty slot */
+ this->video_overlay_events[i].next_event = 0;
+ }
+ pthread_mutex_unlock (&this->video_overlay_events_mutex);
+
+ for (i=0; i < MAX_OBJECTS; i++) {
+ internal_video_overlay_free_handle(this, i);
+ }
+
+ for( i = 0; i < MAX_SHOWING; i++ )
+ this->video_overlay_showing[i].handle = -1;
+}
+
+
+static void video_overlay_init (video_overlay_instance_t *this_gen) {
+
+ video_overlay_t *this = (video_overlay_t *) this_gen;
+
+ pthread_mutex_init (&this->video_overlay_events_mutex,NULL);
+ pthread_mutex_init (&this->video_overlay_objects_mutex,NULL);
+ pthread_mutex_init (&this->video_overlay_showing_mutex,NULL);
+
+ video_overlay_reset(this);
+}
+
+
+/* add an event to the events queue, sort the queue based on vpts.
+ * This can be the API entry point for DVD subtitles.
+ * One calls this function with an event, the event contains an overlay
+ * and a vpts when to action/process it. vpts of 0 means action the event now.
+ * One also has a handle, so one can match show and hide events.
+ *
+ * note: on success event->object.overlay is "taken" (caller will not have access
+ * to overlay data including rle).
+ * note2: handle will be freed on HIDE events
+ */
+static int32_t video_overlay_add_event(video_overlay_instance_t *this_gen, void *event_gen ) {
+ video_overlay_event_t *event = (video_overlay_event_t *) event_gen;
+ video_overlay_t *this = (video_overlay_t *) this_gen;
+ uint32_t last_event,this_event,new_event;
+
+ pthread_mutex_lock (&this->video_overlay_events_mutex);
+
+ /* We skip the 0 entry because that is used as a pointer to the first event.*/
+ /* Find a free event slot */
+ for( new_event = 1; new_event<MAX_EVENTS &&
+ this->video_overlay_events[new_event].event->event_type > 0; new_event++ )
+ ;
+
+ if (new_event < MAX_EVENTS) {
+ /* Find position in event queue to be added. */
+ this_event=0;
+ /* Find where in the current queue to insert the event. I.E. Sort it. */
+ do {
+ last_event=this_event;
+ this_event=this->video_overlay_events[last_event].next_event;
+ } while ( this_event && this->video_overlay_events[this_event].event->vpts < event->vpts );
+
+ this->video_overlay_events[last_event].next_event=new_event;
+ this->video_overlay_events[new_event].next_event=this_event;
+
+ /* memcpy everything except the actual image */
+ if ( this->video_overlay_events[new_event].event == NULL ) {
+ fprintf(stderr,"video_overlay: error: event slot is NULL!\n");
+ }
+ this->video_overlay_events[new_event].event->event_type=event->event_type;
+ this->video_overlay_events[new_event].event->vpts=event->vpts;
+ this->video_overlay_events[new_event].event->object.handle=event->object.handle;
+
+ if ( this->video_overlay_events[new_event].event->object.overlay ) {
+ fprintf(stderr,"video_overlay: error: event->object.overlay was not freed!\n");
+ }
+
+ this->video_overlay_events[new_event].event->object.overlay = xine_xmalloc (sizeof(vo_overlay_t));
+ memcpy(this->video_overlay_events[new_event].event->object.overlay,
+ event->object.overlay, sizeof(vo_overlay_t));
+
+ /* We took the callers rle and data, therefore it will be our job to free it */
+ /* clear callers overlay so it will not be freed twice */
+ memset(event->object.overlay,0,sizeof(vo_overlay_t));
+ } else {
+ fprintf(stderr, "No spare subtitle event slots\n");
+ new_event = -1;
+ }
+
+ pthread_mutex_unlock (&this->video_overlay_events_mutex);
+
+ return new_event;
+}
+
+
+/* not currently used. James might need this for debugging menu stuff */
+static void video_overlay_print_overlay( vo_overlay_t *ovl ) {
+#ifdef LOG_DEBUG
+ printf ("video_overlay: OVERLAY to show\n");
+ printf ("video_overlay: \tx = %d y = %d width = %d height = %d\n",
+ ovl->x, ovl->y, ovl->width, ovl->height );
+ printf ("video_overlay: \tclut [%x %x %x %x]\n",
+ ovl->color[0], ovl->color[1], ovl->color[2], ovl->color[3]);
+ printf ("video_overlay: \ttrans [%d %d %d %d]\n",
+ ovl->trans[0], ovl->trans[1], ovl->trans[2], ovl->trans[3]);
+ printf ("video_overlay: \tclip top=%d bottom=%d left=%d right=%d\n",
+ ovl->clip_top, ovl->clip_bottom, ovl->clip_left, ovl->clip_right);
+#endif
+ return;
+}
+
+/*
+ process overlay events
+ if vpts == 0 will process everything now (used in flush)
+*/
+static void video_overlay_event( video_overlay_t *this, int vpts ) {
+ int32_t handle;
+ uint32_t this_event;
+
+ pthread_mutex_lock (&this->video_overlay_events_mutex);
+
+ this_event=this->video_overlay_events[0].next_event;
+ while ( this_event && (vpts > this->video_overlay_events[this_event].event->vpts ||
+ vpts == 0) ) {
+ handle=this->video_overlay_events[this_event].event->object.handle;
+ switch( this->video_overlay_events[this_event].event->event_type ) {
+ case EVENT_SHOW_SPU:
+#ifdef LOG_DEBUG
+ printf ("video_overlay: SHOW SPU NOW\n");
+#endif
+ if (this->video_overlay_events[this_event].event->object.overlay != NULL) {
+ internal_video_overlay_free_handle( this, handle );
+
+ this->video_overlay_objects[handle].handle = handle;
+ if( this->video_overlay_objects[handle].overlay ) {
+ fprintf(stderr,"video_overlay: error: object->overlay was not freed!\n");
+ }
+ this->video_overlay_objects[handle].overlay =
+ this->video_overlay_events[this_event].event->object.overlay;
+ this->video_overlay_events[this_event].event->object.overlay = NULL;
+
+ add_showing_handle( this, handle );
+ }
+ break;
+
+ /* implementation for HIDE_SPU and HIDE_MENU is the same.
+ i will keep them separated in case we need something special...
+ */
+ case EVENT_HIDE_SPU:
+#ifdef LOG_DEBUG
+ printf ("video_overlay: HIDE SPU NOW\n");
+#endif
+ free(this->video_overlay_events[this_event].event->object.overlay);
+ this->video_overlay_events[this_event].event->object.overlay = NULL;
+ remove_showing_handle( this, handle );
+ internal_video_overlay_free_handle( this, handle );
+ break;
+
+ case EVENT_HIDE_MENU:
+#ifdef LOG_DEBUG
+ printf ("video_overlay: HIDE MENU NOW %d\n",handle);
+#endif
+ free(this->video_overlay_events[this_event].event->object.overlay);
+ this->video_overlay_events[this_event].event->object.overlay = NULL;
+ remove_showing_handle( this, handle );
+ internal_video_overlay_free_handle( this, handle );
+ break;
+
+ case EVENT_MENU_SPU:
+ /* mixes palette and copy rle */
+#ifdef LOG_DEBUG
+ printf ("MENU SPU NOW\n");
+#endif
+ if (this->video_overlay_events[this_event].event->object.overlay != NULL) {
+ vo_overlay_t *event_overlay = this->video_overlay_events[this_event].event->object.overlay;
+ vo_overlay_t *overlay;
+
+ /* we need to allocate overlay on first EVENT_MENU_SPU */
+ if( !this->video_overlay_objects[handle].overlay ) {
+ this->video_overlay_objects[handle].overlay
+ = xine_xmalloc( sizeof(vo_overlay_t) );
+ }
+ overlay = this->video_overlay_objects[handle].overlay;
+
+ this->video_overlay_objects[handle].handle = handle;
+
+ /* If rle is not empty, free it first */
+ if(overlay->rle) {
+ free (overlay->rle);
+ }
+ overlay->rle = event_overlay->rle;
+
+ overlay->data_size = event_overlay->data_size;
+ overlay->num_rle = event_overlay->num_rle;
+ overlay->x = event_overlay->x;
+ overlay->y = event_overlay->y;
+ overlay->width = event_overlay->width;
+ overlay->height = event_overlay->height;
+ overlay->rgb_clut = event_overlay->rgb_clut;
+ if((event_overlay->color[0] +
+ event_overlay->color[1] +
+ event_overlay->color[2] +
+ event_overlay->color[3]) > 0 ) {
+ overlay->color[0] = event_overlay->color[0];
+ overlay->color[1] = event_overlay->color[1];
+ overlay->color[2] = event_overlay->color[2];
+ overlay->color[3] = event_overlay->color[3];
+ }
+ if((event_overlay->trans[0] +
+ event_overlay->trans[1] +
+ event_overlay->trans[2] +
+ event_overlay->trans[3]) > 0 ) {
+ overlay->trans[0] = event_overlay->trans[0];
+ overlay->trans[1] = event_overlay->trans[1];
+ overlay->trans[2] = event_overlay->trans[2];
+ overlay->trans[3] = event_overlay->trans[3];
+ }
+ add_showing_handle( this, handle );
+
+ /* The null test was done at the start of this case statement */
+ free (this->video_overlay_events[this_event].event->object.overlay);
+ this->video_overlay_events[this_event].event->object.overlay = NULL;
+ }
+ break;
+
+ case EVENT_MENU_BUTTON:
+ /* mixes palette and copy clip coords */
+#ifdef LOG_DEBUG
+ printf ("MENU BUTTON NOW\n");
+#endif
+ if (this->video_overlay_events[this_event].event->object.overlay != NULL) {
+ vo_overlay_t *overlay = this->video_overlay_objects[handle].overlay;
+ vo_overlay_t *event_overlay = this->video_overlay_events[this_event].event->object.overlay;
+
+ if( !this->video_overlay_objects[handle].overlay ) {
+ fprintf(stderr,"video_overlay: error: button event received and no overlay allocated.\n");
+ }
+
+ this->video_overlay_objects[handle].handle = handle;
+ overlay->clip_top = event_overlay->clip_top;
+ overlay->clip_bottom = event_overlay->clip_bottom;
+ overlay->clip_left = event_overlay->clip_left;
+ overlay->clip_right = event_overlay->clip_right;
+
+ if((event_overlay->color[0] +
+ event_overlay->color[1] +
+ event_overlay->color[2] +
+ event_overlay->color[3]) > 0 ) {
+ overlay->color[0] = event_overlay->color[0];
+ overlay->color[1] = event_overlay->color[1];
+ overlay->color[2] = event_overlay->color[2];
+ overlay->color[3] = event_overlay->color[3];
+ }
+ if((event_overlay->trans[0] +
+ event_overlay->trans[1] +
+ event_overlay->trans[2] +
+ event_overlay->trans[3]) > 0 ) {
+ overlay->trans[0] = event_overlay->trans[0];
+ overlay->trans[1] = event_overlay->trans[1];
+ overlay->trans[2] = event_overlay->trans[2];
+ overlay->trans[3] = event_overlay->trans[3];
+ }
+ add_showing_handle( this, handle );
+
+ if( this->video_overlay_events[this_event].event->object.overlay->rle ) {
+ printf ("video_overlay: warning EVENT_MENU_BUTTON with rle data\n");
+ free( this->video_overlay_events[this_event].event->object.overlay->rle );
+ }
+
+ /* The null test was done at the start of this case statement */
+ free (this->video_overlay_events[this_event].event->object.overlay);
+ this->video_overlay_events[this_event].event->object.overlay = NULL;
+ }
+ break;
+
+ default:
+ printf ("video_overlay: unhandled event type\n");
+ break;
+ }
+
+ this->video_overlay_events[0].next_event = this->video_overlay_events[this_event].next_event;
+ this->video_overlay_events[this_event].next_event = 0;
+ this->video_overlay_events[this_event].event->event_type = 0;
+
+ this_event=this->video_overlay_events[0].next_event;
+ }
+
+ pthread_mutex_unlock (&this->video_overlay_events_mutex);
+}
+
+/* This is called from video_out.c
+ * must call output->overlay_blend for each active overlay.
+ */
+static void video_overlay_multiple_overlay_blend(video_overlay_instance_t *this_gen, int vpts,
+ vo_driver_t *output, vo_frame_t *vo_img, int enabled) {
+ video_overlay_t *this = (video_overlay_t *) this_gen;
+ int i;
+ int32_t handle;
+
+ /* Look at next events, if current video vpts > first event on queue, process the event
+ * else just continue
+ */
+ video_overlay_event( this, vpts );
+
+ /* Scan through 5 entries and display any present.
+ */
+ pthread_mutex_lock( &this->video_overlay_showing_mutex );
+ for( i = 0; enabled && output->overlay_blend && i < MAX_SHOWING; i++ ) {
+ handle=this->video_overlay_showing[i].handle;
+ if (handle >= 0 ) {
+ output->overlay_blend(output, vo_img, this->video_overlay_objects[handle].overlay);
+ }
+ }
+ pthread_mutex_unlock( &this->video_overlay_showing_mutex );
+}
+
+
+/* this should be called on stream end or stop to make sure every
+ hide event is processed.
+*/
+static void video_overlay_flush_events(video_overlay_instance_t *this_gen )
+{
+ video_overlay_t *this = (video_overlay_t *) this_gen;
+
+ video_overlay_event( this, 0 );
+}
+
+
+video_overlay_instance_t *video_overlay_new_instance () {
+
+ video_overlay_t *this;
+
+ this = (video_overlay_t *) xine_xmalloc (sizeof (video_overlay_t));
+
+ this->video_overlay.init = video_overlay_init;
+ this->video_overlay.get_handle = video_overlay_get_handle;
+ this->video_overlay.free_handle = video_overlay_free_handle;
+ this->video_overlay.add_event = video_overlay_add_event;
+ this->video_overlay.flush_events = video_overlay_flush_events;
+ this->video_overlay.multiple_overlay_blend = video_overlay_multiple_overlay_blend;
+
+ return (video_overlay_instance_t *) &this->video_overlay;
+}
+
diff --git a/src/xine-engine/video_overlay.h b/src/xine-engine/video_overlay.h
new file mode 100644
index 000000000..6cd3c4670
--- /dev/null
+++ b/src/xine-engine/video_overlay.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2000-2001 the xine project
+ *
+ * This file is part of xine, a unix video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * xine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: video_overlay.h,v 1.1 2001/11/28 22:19:11 miguelfreitas Exp $
+ *
+ */
+
+#include "xine_internal.h"
+#include "video_out/alphablend.h"
+#include "xine-engine/bswap.h"
+
+#ifdef __GNUC__
+#define CLUT_Y_CR_CB_INIT(_y,_cr,_cb) {y: (_y), cr: (_cr), cb: (_cb)}
+#else
+#define CLUT_Y_CR_CB_INIT(_y,_cr,_cb) { (_cb), (_cr), (_y) }
+#endif
+
+#define MAX_OBJECTS 50
+#define MAX_EVENTS 50
+#define MAX_SHOWING 5
+
+#define EVENT_NULL 0
+#define EVENT_SHOW_SPU 1
+#define EVENT_HIDE_SPU 2
+#define EVENT_HIDE_MENU 3
+#define EVENT_MENU_SPU 4
+#define EVENT_MENU_BUTTON 5
+#define EVENT_DELETE_RESOURCE 6 /* Maybe release handle will do this */
+#define EVENT_SHOW_OSD 7 /* Not yet implemented */
+
+typedef struct video_overlay_object_s {
+ int32_t handle; /* Used to match Show and Hide events. */
+ uint32_t object_type; /* 0=Subtitle, 1=Menu */
+ uint32_t pts; /* Needed for Menu button compares */
+ vo_overlay_t *overlay; /* The image data. */
+ uint32_t palette_type; /* 1 Y'CrCB, 2 R'G'B' */
+ uint32_t *palette; /* If NULL, no palette contained in this event. */
+} video_overlay_object_t;
+
+/* This will hold all details of an event item, needed for event queue to function */
+typedef struct video_overlay_event_s {
+ uint32_t event_type; /* Show SPU, Show OSD, Hide etc. */
+ uint32_t vpts; /* Time when event will action. 0 means action now */
+/* Once video_out blend_yuv etc. can take rle_elem_t with Colour, blend and length information.
+ * we can remove clut and blend from this structure.
+ * This will allow for many more colours for OSD.
+ */
+ video_overlay_object_t object; /* The image data. */
+} video_overlay_event_t;
+
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index 5c182f7f2..f15eed2eb 100644
--- a/src/xine-engine/xine.c
+++ b/src/xine-engine/xine.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: xine.c,v 1.80 2001/11/24 23:52:40 miguelfreitas Exp $
+ * $Id: xine.c,v 1.81 2001/11/28 22:19:12 miguelfreitas Exp $
*
* top-level xine functions
*
@@ -50,6 +50,7 @@
#include "input/input_plugin.h"
#include "metronom.h"
#include "configfile.h"
+#include "osd.h"
#include "xineutils.h"
@@ -434,7 +435,19 @@ xine_t *xine_init (vo_driver_t *vo,
this->video_out = vo_new_instance (vo, this->metronom);
video_decoder_init (this);
-
+ this->osd_renderer = osd_renderer_init( this->video_out->overlay_source );
+ osd_renderer_load_font( this->osd_renderer, "vga" );
+
+ /* just kidding. this will be removed before 0.9.7 */
+ {
+ osd_object_t *osd;
+ osd = osd_open(this->osd_renderer, 120, 120);
+ osd_set_font(osd,"vga");
+ osd_render_text(osd,0,0,"\x0ff");
+ osd_set_position(osd,10,10);
+ osd_show(osd,0);
+ }
+
if(ao)
this->audio_out = ao_new_instance (ao, this->metronom, config);
diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h
index 118ee0950..5fdc58f3b 100644
--- a/src/xine-engine/xine_internal.h
+++ b/src/xine-engine/xine_internal.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: xine_internal.h,v 1.57 2001/11/20 14:03:15 miguelfreitas Exp $
+ * $Id: xine_internal.h,v 1.58 2001/11/28 22:19:12 miguelfreitas Exp $
*
*/
@@ -181,6 +181,8 @@ struct xine_s {
video_decoder_t *video_decoder_plugins[DECODER_PLUGIN_MAX];
video_decoder_t *cur_video_decoder_plugin;
int video_finished;
+
+ void *osd_renderer;
ao_instance_t *audio_out;
fifo_buffer_t *audio_fifo;