diff options
author | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2001-11-28 22:19:10 +0000 |
---|---|---|
committer | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2001-11-28 22:19:10 +0000 |
commit | d48b3bf8769a8ac1741d819289ed9ea117764bc5 (patch) | |
tree | b90a868f2118128d8b0bcff135f9b0ac3d46ae73 | |
parent | 157c020ba6d577c45678b7b59f96b3ca646fa525 (diff) | |
download | xine-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
-rw-r--r-- | misc/Makefile.am | 3 | ||||
-rw-r--r-- | misc/vga.xinefont.gz | bin | 0 -> 2997 bytes | |||
-rw-r--r-- | src/libspudec/spu.c | 5 | ||||
-rw-r--r-- | src/libspudec/spu.h | 47 | ||||
-rw-r--r-- | src/libspudec/xine_decoder.c | 664 | ||||
-rw-r--r-- | src/video_out/video_out_xshm.c | 4 | ||||
-rw-r--r-- | src/video_out/video_out_xv.c | 3 | ||||
-rw-r--r-- | src/xine-engine/Makefile.am | 7 | ||||
-rw-r--r-- | src/xine-engine/osd.c | 709 | ||||
-rw-r--r-- | src/xine-engine/osd.h | 159 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 39 | ||||
-rw-r--r-- | src/xine-engine/video_out.h | 41 | ||||
-rw-r--r-- | src/xine-engine/video_overlay.c | 550 | ||||
-rw-r--r-- | src/xine-engine/video_overlay.h | 66 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 17 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 4 |
16 files changed, 1658 insertions, 660 deletions
diff --git a/misc/Makefile.am b/misc/Makefile.am index 018766043..606ba1fb3 100644 --- a/misc/Makefile.am +++ b/misc/Makefile.am @@ -5,7 +5,8 @@ EXTRA_DIST = autogen.sh upload.pl SlackBuild.in SlackBuild build_rpms.sh \ bin_SCRIPTS = xine-config datadir = $(XINE_SKINDIR) -data_DATA = xine_logo.png +#this is just a hack. osd fonts should be installed in another dir +data_DATA = xine_logo.png vga.xinefont.gz debug: diff --git a/misc/vga.xinefont.gz b/misc/vga.xinefont.gz Binary files differnew file mode 100644 index 000000000..271de4445 --- /dev/null +++ b/misc/vga.xinefont.gz diff --git a/src/libspudec/spu.c b/src/libspudec/spu.c index af342d146..b096417e5 100644 --- a/src/libspudec/spu.c +++ b/src/libspudec/spu.c @@ -35,7 +35,7 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: spu.c,v 1.25 2001/11/26 20:02:33 guenter Exp $ + * $Id: spu.c,v 1.26 2001/11/28 22:19:12 miguelfreitas Exp $ * */ @@ -49,9 +49,10 @@ #include <sys/stat.h> #include <fcntl.h> -#include "spu.h" #include "video_out/alphablend.h" #include "xineutils.h" +#include "xine_internal.h" +#include "spu.h" /* #define LOG_DEBUG 1 diff --git a/src/libspudec/spu.h b/src/libspudec/spu.h index e86adfde8..8571060e8 100644 --- a/src/libspudec/spu.h +++ b/src/libspudec/spu.h @@ -19,7 +19,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: spu.h,v 1.6 2001/10/20 17:51:59 jcdutton Exp $ + * $Id: spu.h,v 1.7 2001/11/28 22:19:12 miguelfreitas Exp $ * * This file was originally part of the OMS program. * @@ -34,12 +34,10 @@ #include <inttypes.h> #include "video_out.h" +#include "video_overlay.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 NUM_SEQ_BUFFERS 50 +#define MAX_STREAMS 32 typedef struct spu_clut_struct { #ifdef WORDS_BIGENDIAN @@ -95,4 +93,41 @@ void spu_draw_picture (spu_state_t *state, spu_seq_t* seq, vo_overlay_t *ovl); void spu_discover_clut (spu_state_t *state, vo_overlay_t *ovl); void spu_update_menu (spu_state_t *state, vo_overlay_t *ovl); + +typedef struct spudec_stream_state_s { + spu_seq_t ra_seq; + uint32_t ra_complete; + uint32_t stream_filter; + spu_state_t state; + uint32_t vpts; + uint32_t pts; + int32_t overlay_handle; +} spudec_stream_state_t; + +typedef struct spudec_decoder_s { + spu_decoder_t spu_decoder; + + xine_t *xine; +/* spu_seq_t seq_list[NUM_SEQ_BUFFERS]; */ + spu_seq_t *cur_seq; + spudec_stream_state_t spu_stream_state[MAX_STREAMS]; + + video_overlay_event_t event; + video_overlay_object_t object; + int32_t menu_handle; + + spu_seq_t *ra_seq; + int ra_complete; + + uint32_t ovl_pts; + uint32_t buf_pts; + spu_state_t state; + + vo_instance_t *vo_out; + vo_overlay_t overlay; + int ovl_caps; + int output_open; +} spudec_decoder_t; + + #endif diff --git a/src/libspudec/xine_decoder.c b/src/libspudec/xine_decoder.c index 1f05e3ede..0c5811310 100644 --- a/src/libspudec/xine_decoder.c +++ b/src/libspudec/xine_decoder.c @@ -19,7 +19,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_decoder.c,v 1.35 2001/11/18 03:53:24 guenter Exp $ + * $Id: xine_decoder.c,v 1.36 2001/11/28 22:19:12 miguelfreitas Exp $ * * stuff needed to turn libspu into a xine decoder plugin */ @@ -31,15 +31,13 @@ #include <sys/stat.h> #include <fcntl.h> -#include "spu.h" #include "buffer.h" #include "events.h" #include "xine_internal.h" #include "video_out/alphablend.h" #include "xine-engine/bswap.h" #include "xineutils.h" - -static void spudec_print_overlay( vo_overlay_t *ovl ); +#include "spu.h" /* #define LOG_DEBUG 1 @@ -83,90 +81,6 @@ static clut_t __default_clut[] = { CLUT_Y_CR_CB_INIT(0x28, 0x6d, 0xef) }; -#define NUM_SEQ_BUFFERS 50 -#define MAX_OBJECTS 50 -#define MAX_STREAMS 32 -#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 spu_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. */ -} spu_object_t; - -/* This will hold all details of an event item, needed for event queue to function */ -typedef struct spu_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. - */ - spu_object_t object; /* The image data. */ -} spu_overlay_event_t; - -typedef struct spu_overlay_events_s { - spu_overlay_event_t *event; - uint32_t next_event; -} spu_overlay_events_t; - -typedef struct spu_showing_s { - int32_t handle; /* -1 means not allocated */ -} spu_showing_t; - - -typedef struct spudec_stream_state_s { - spu_seq_t ra_seq; - uint32_t ra_complete; - uint32_t stream_filter; - spu_state_t state; - uint32_t vpts; - uint32_t pts; -} spudec_stream_state_t; - -typedef struct spudec_decoder_s { - spu_decoder_t spu_decoder; - ovl_src_t ovl_src; - - xine_t *xine; -/* spu_seq_t seq_list[NUM_SEQ_BUFFERS]; */ - spu_seq_t *cur_seq; - spudec_stream_state_t spu_stream_state[MAX_STREAMS]; - pthread_mutex_t spu_events_mutex; - spu_overlay_events_t spu_events[MAX_EVENTS]; - spu_overlay_event_t event; - spu_object_t object; - pthread_mutex_t spu_objects_mutex; - spu_object_t spu_objects[MAX_OBJECTS]; - pthread_mutex_t spu_showing_mutex; /* Probably not needed */ - spu_showing_t spu_showing[MAX_SHOWING]; - spu_seq_t *ra_seq; - int ra_complete; - - uint32_t ovl_pts; - uint32_t buf_pts; - spu_state_t state; - - vo_instance_t *vo_out; - vo_overlay_t overlay; - int ovl_caps; - int output_open; - -} spudec_decoder_t; - static int spudec_can_handle (spu_decoder_t *this_gen, int buf_type) { int type = buf_type & 0xFFFF0000; return (type == BUF_SPU_PACKAGE || type == BUF_SPU_CLUT || type == BUF_SPU_SUBP_CONTROL) ; @@ -175,6 +89,7 @@ static int spudec_can_handle (spu_decoder_t *this_gen, int buf_type) { /* FIXME: This function needs checking */ static void spudec_reset (spudec_decoder_t *this) { int i; + this->ovl_pts = 0; this->buf_pts = 0; @@ -187,50 +102,9 @@ static void spudec_reset (spudec_decoder_t *this) { for (i=0; i < MAX_STREAMS; i++) { this->spu_stream_state[i].stream_filter = 1; /* So it works with non-navdvd plugins */ this->spu_stream_state[i].ra_complete = 1; + this->spu_stream_state[i].overlay_handle = -1; } - for (i=0; i < MAX_EVENTS; i++) { - if (this->spu_events[i].event == NULL) { -#ifdef LOG_DEBUG - printf ("spu: MALLOC1: this->spu_events[%d].event %p, len=%d\n", - i, - this->spu_events[i].event, - sizeof(spu_overlay_event_t)); -#endif - this->spu_events[i].event = xine_xmalloc (sizeof(spu_overlay_event_t)); -#ifdef LOG_DEBUG - printf ("spu: MALLOC2: this->spu_events[%d].event %p, len=%d\n", - i, - this->spu_events[i].event, - sizeof(spu_overlay_event_t)); -#endif - this->spu_events[i].event->event_type = 0; /* Empty slot */ - } - } - for (i=0; i < MAX_OBJECTS; i++) { - this->spu_objects[i].handle = -1; - } - /* Initialise the menu object */ - this->spu_objects[1].handle=1; - this->spu_objects[1].object_type=1; - this->spu_objects[1].pts=0; -#ifdef LOG_DEBUG - printf ("spu: MALLOC1: this->spu_objects[1].overlay %p, len=%d\n", - this->spu_objects[1].overlay, sizeof(vo_overlay_t)); -#endif - this->spu_objects[1].overlay = xine_xmalloc (sizeof(vo_overlay_t)); -#ifdef LOG_DEBUG - printf ("spu: MALLOC2: this->spu_objects[1].overlay %p, len=%d\n", - this->spu_objects[1].overlay, sizeof(vo_overlay_t)); -#endif -/* xine_xmalloc does memset */ -/* memset(this->spu_objects[1].overlay,0,sizeof(vo_overlay_t)); - */ - - pthread_mutex_init (&this->spu_events_mutex,NULL); - pthread_mutex_init (&this->spu_objects_mutex,NULL); - pthread_mutex_init (&this->spu_showing_mutex,NULL); - /* I don't think I need this. this->cur_seq = this->ra_seq = this->seq_list; */ @@ -249,131 +123,13 @@ static void spudec_init (spu_decoder_t *this_gen, vo_instance_t *vo_out) { /* FIXME:Do we really need a default clut? */ memcpy(this->state.clut, __default_clut, sizeof(this->state.clut)); this->state.need_clut = 1; - vo_out->register_ovl_src(vo_out, &this->ovl_src); -} - -/* allocate a handle from the object pool - */ -static int32_t spu_get_handle(spudec_decoder_t *this) { - int n; - n=0; - do { - n++; - } while ( ( n<MAX_OBJECTS ) && ( this->spu_objects[n].handle > -1 ) ); - if (n >= MAX_OBJECTS) return -1; - this->spu_objects[n].handle=n; - return n; -} - -/* allocate a menu handle from the object pool - */ -static int32_t spu_get_menu_handle(spudec_decoder_t *this) { - return 1; /* This might be dynamic later */ -} - -/* free a handle from the object pool - */ -static void spu_free_handle(spudec_decoder_t *this, int32_t handle) { - this->spu_objects[handle].handle = -1; -} - -/* add an event to the events queue, sort the queue based on vpts. - * This can be the API entry point for DVD subtitles. - * In future this could also be the entry point for OSD as well as other Subtitle formats. - * 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. - * FIXME: Implement Event queue locking. A different thread calls spu_get_overlay, which removes events from the queue. - */ -static int32_t spu_add_event(spudec_decoder_t *this, spu_overlay_event_t *event) { - int found; - uint32_t last_event,this_event,new_event; - new_event=0; - /* We skip the 0 entry because that is used as a pointer to the first event.*/ - /* Find a free event slot */ -#ifdef LOG_DEBUG - printf ("spu: 284MUTEX1:spu_events lock"); -#endif - pthread_mutex_lock (&this->spu_events_mutex); -#ifdef LOG_DEBUG - printf ("spu:->ok\n"); -#endif - do { - new_event++; - } while ((new_event<MAX_EVENTS) && (this->spu_events[new_event].event->event_type > 0)); - if (new_event >= MAX_EVENTS) { - pthread_mutex_unlock (&this->spu_events_mutex); - return -1; - } - /* Find position in event queue to be added. */ - this_event=0; - found=0; - /* Find where in the current queue to insert the event. I.E. Sort it. */ - do { - last_event=this_event; - this_event=this->spu_events[last_event].next_event; - if (this_event == 0) { - found=1; - break; - } -#ifdef LOG_DEBUG - printf ("spu:this_event=%d vpts %d\n",this_event, this->spu_events[this_event].event->vpts); -#endif - if (this->spu_events[this_event].event->vpts > event->vpts ) { - found=2; - break; - } - } while ((this_event != 0) && (found == 0)); - if (last_event >= MAX_EVENTS) { - pthread_mutex_unlock (&this->spu_events_mutex); - fprintf(stderr, "No spare subtitle event slots\n"); - return -1; - } - /* memcpy everything except the actual image */ - this->spu_events[last_event].next_event=new_event; - this->spu_events[new_event].next_event=this_event; - if ( this->spu_events[new_event].event == NULL ) { - fprintf(stderr,"COMPLAIN BIG TIME!\n"); - } - this->spu_events[new_event].event->event_type=event->event_type; - this->spu_events[new_event].event->vpts=event->vpts; - this->spu_events[new_event].event->object.handle=event->object.handle; -#ifdef LOG_DEBUG - printf ("spu: 323MALLOC1: this->spu_events[new_event=%d].event->object.overlay %p, len=%d\n", - new_event, - this->spu_events[new_event].event->object.overlay, - sizeof(vo_overlay_t)); -#endif - this->spu_events[new_event].event->object.overlay = xine_xmalloc (sizeof(vo_overlay_t)); -#ifdef LOG_DEBUG - printf ("spu: 328MALLOC2: this->spu_events[new_event=%d].event->object.overlay %p, len=%d\n", - new_event, - this->spu_events[new_event].event->object.overlay, - sizeof(vo_overlay_t)); -#endif - memcpy(this->spu_events[new_event].event->object.overlay, - event->object.overlay, sizeof(vo_overlay_t)); - memset(event->object.overlay,0,sizeof(vo_overlay_t)); -// spudec_print_overlay( event->object.overlay ); -// spudec_print_overlay( this->spu_events[new_event].event->object.overlay ); - pthread_mutex_unlock (&this->spu_events_mutex); - - return new_event; } -/* empty the object queue - * release all handles currently allocated. - * IMPLEMENT ME. - */ -static void spu_free_all_handles(spudec_decoder_t *this) { -return; -} static void spu_process (spudec_decoder_t *this, uint32_t stream_id) { // spu_overlay_event_t *event; // spu_object_t *object; // vo_overlay_t *overlay; - int handle; int pending = 1; this->cur_seq = &this->spu_stream_state[stream_id].ra_seq; @@ -392,12 +148,7 @@ static void spu_process (spudec_decoder_t *this, uint32_t stream_id) { this->state.menu = 0; /* 0 - No value, 1 - Forced Display. */ this->state.delay = 0; this->cur_seq->finished=0; - handle=spu_get_handle(this); - if (handle < 0) { - printf("No SPU Handles left\n"); - return; - } - + do { if (!this->spu_stream_state[stream_id].ra_seq.finished) { @@ -414,7 +165,6 @@ static void spu_process (spudec_decoder_t *this, uint32_t stream_id) { #ifdef LOG_DEBUG printf ("spu: Dropping SPU channel %d\n", stream_id); #endif - spu_free_handle(this, handle); return; } if ((this->state.modified) ) { @@ -426,45 +176,56 @@ static void spu_process (spudec_decoder_t *this, uint32_t stream_id) { if (this->state.menu == 0) { /* Subtitle */ - this->event.object.handle = handle; - /* FIXME: memcpy maybe. */ -#ifdef LOG_DEBUG - printf ("spu: 403MALLOC: this->event.object.overlay=%p\n", - this->event.object.overlay); -#endif - this->event.object.overlay = malloc(sizeof(vo_overlay_t)); + if( this->spu_stream_state[stream_id].overlay_handle < 0 ) { + this->spu_stream_state[stream_id].overlay_handle = + this->vo_out->overlay_source->get_handle(this->vo_out->overlay_source, 0); + } + + if( this->spu_stream_state[stream_id].overlay_handle < 0 ) { + printf("libspudec: No video_overlay handles left for SPU\n"); + return; + } + + this->event.object.handle = this->spu_stream_state[stream_id].overlay_handle; + memcpy(this->event.object.overlay, &this->overlay, sizeof(vo_overlay_t)); this->overlay.rle=NULL; -#ifdef LOG_DEBUG - printf ("spu: 409MALLOC: this->event.object.overlay=%p\n", - this->event.object.overlay); -#endif + this->event.event_type = this->state.visible; + + /* event hide event must free the handle after use */ + if( this->event.event_type == EVENT_HIDE_SPU ) { + this->spu_stream_state[stream_id].overlay_handle = -1; + } + this->event.vpts = this->spu_stream_state[stream_id].vpts+(this->state.delay*1000); + + /* + printf("spu event %d handle: %d vpts: %d\n", this->event.event_type, + this->event.object.handle, this->event.vpts ); + */ } else { /* Menu */ - spu_free_handle(this, handle); - this->event.object.handle = spu_get_menu_handle(this); - /* FIXME: memcpy maybe. */ -#ifdef LOG_DEBUG - printf ("spu:418MALLOC: this->event.object.overlay=%p\n", - this->event.object.overlay); -#endif - this->event.object.overlay = malloc(sizeof(vo_overlay_t)); + if( this->menu_handle < 0 ) + this->menu_handle = this->vo_out->overlay_source->get_handle(this->vo_out->overlay_source,1); + + if( this->menu_handle < 0 ) { + printf("libspudec: No video_overlay handles left for menu\n"); + return; + } + this->event.object.handle = this->menu_handle; + memcpy(this->event.object.overlay, &this->overlay, sizeof(vo_overlay_t)); this->overlay.rle=NULL; -#ifdef LOG_DEBUG - printf ("spu: 424MALLOC: this->event.object.overlay=%p\n", - this->event.object.overlay); -#endif + this->event.event_type = EVENT_MENU_SPU; this->event.vpts = this->spu_stream_state[stream_id].vpts+(this->state.delay*1000); } - spu_add_event(this, &this->event); + this->vo_out->overlay_source->add_event(this->vo_out->overlay_source, (void *)&this->event); } else { pending = 0; } @@ -509,7 +270,7 @@ static void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) { return; if (buf->PTS) { - metronom_t *metronom = this->ovl_src.metronom; + metronom_t *metronom = this->xine->metronom; uint32_t vpts = metronom->got_spu_packet(metronom, buf->PTS, 0, buf->SCR); if (vpts < this->buf_pts) { /* FIXME: Don't do this yet, @@ -546,9 +307,22 @@ static void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) { static void spudec_close (spu_decoder_t *this_gen) { spudec_decoder_t *this = (spudec_decoder_t *) this_gen; + int i; - this->vo_out->unregister_ovl_src(this->vo_out, &this->ovl_src); + if( this->menu_handle >= 0 ) + this->vo_out->overlay_source->free_handle(this->vo_out->overlay_source, + this->menu_handle); + this->menu_handle = -1; + + + for (i=0; i < MAX_STREAMS; i++) { + if( this->spu_stream_state[i].overlay_handle >= 0 ) + this->vo_out->overlay_source->free_handle(this->vo_out->overlay_source, + this->spu_stream_state[i].overlay_handle); + this->spu_stream_state[i].overlay_handle = -1; + } } + /* This function is probably not needed now */ static void spudec_nextseq(spudec_decoder_t* this) { spu_seq_t *tmp_seq = this->cur_seq + 1; @@ -582,303 +356,6 @@ static void spudec_print_overlay( vo_overlay_t *ovl ) { return; } -/* FIXME:Some optimization needs to happen here. */ -static void spu_process_event( spudec_decoder_t *this, int vpts ) { - int32_t handle; - uint32_t this_event; -// uint32_t vpts; -// uint32_t pts; -// int i; -// vo_overlay_t overlay; -#ifdef LOG_DEBUG - printf ("spu: 557MUTEX1:spu_events lock"); -#endif - pthread_mutex_lock (&this->spu_events_mutex); -#ifdef LOG_DEBUG - printf ("spu: -> ok.\n"); -#endif - this_event=this->spu_events[0].next_event; - if ((!this_event) || (vpts < this->spu_events[this_event].event->vpts) ) { - pthread_mutex_unlock (&this->spu_events_mutex); - return; - } - - handle=this->spu_events[this_event].event->object.handle; - switch( this->spu_events[this_event].event->event_type ) { - case EVENT_SHOW_SPU: -#ifdef LOG_DEBUG - printf ("spu: SHOW SPU NOW\n"); -#endif - if (this->spu_events[this_event].event->object.overlay != NULL) { - this->spu_objects[handle].handle = handle; -#ifdef LOG_DEBUG - printf ("spu: POINTER1: this->spu_objects[handle=%d].overlay=%p\n", - handle, - this->spu_objects[handle].overlay); -#endif - this->spu_objects[handle].overlay = this->spu_events[this_event].event->object.overlay; -#ifdef LOG_DEBUG - printf ("spu: POINTER2: this->spu_objects[handle=%d].overlay=%p\n", - handle, - this->spu_objects[handle].overlay); -#endif - this->spu_events[this_event].event->object.overlay = NULL; - } - this->spu_showing[1].handle = handle; - break; - - case EVENT_HIDE_SPU: -#ifdef LOG_DEBUG - printf ("spu: HIDE SPU NOW\n"); -#endif - this->spu_showing[1].handle = -1; - if(this->spu_objects[handle].overlay->rle) { -#ifdef LOG_DEBUG - printf ("spu: FREE1: this->spu_objects[%d].overlay->rle %p\n", - handle, - this->spu_objects[handle].overlay->rle); -#endif - free(this->spu_objects[handle].overlay->rle); - this->spu_objects[handle].overlay->rle = NULL; -#ifdef LOG_DEBUG - printf ("spu: FREE2: this->spu_objects[%d].overlay->rle %p\n", - handle, - this->spu_objects[handle].overlay->rle); -#endif - } -#ifdef LOG_DEBUG - printf ("spu: RLE clear=%08X\n",(uint32_t)this->spu_objects[handle].overlay->rle); -#endif - if (this->spu_objects[handle].overlay) { -#ifdef LOG_DEBUG - printf ("spu: FREE1: this->spu_objects[%d].overlay %p\n", - handle, - this->spu_objects[handle].overlay); -#endif - free(this->spu_objects[handle].overlay); - this->spu_objects[handle].overlay = NULL; -#ifdef LOG_DEBUG - printf ("spu: FREE2: this->spu_objects[%d].overlay %p\n", - handle, - this->spu_objects[handle].overlay); -#endif - } - spu_free_handle( this, handle ); - break; - - case EVENT_HIDE_MENU: -#ifdef LOG_DEBUG - printf ("spu: HIDE MENU NOW %d\n",handle); -#endif - this->spu_showing[1].handle = -1; - if(this->spu_objects[handle].overlay->rle) { -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "FREE1: this->spu_objects[%d].overlay->rle %p\n", - handle, - this->spu_objects[handle].overlay->rle); -#endif - free(this->spu_objects[handle].overlay->rle); - this->spu_objects[handle].overlay->rle = NULL; -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "FREE2: this->spu_objects[%d].overlay->rle %p\n", - handle, - this->spu_objects[handle].overlay->rle); -#endif - } - - /* FIXME: maybe free something here */ - /* spu_free_handle( this, handle ); */ - break; - - case EVENT_MENU_SPU: -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "MENU SPU NOW\n"); -#endif - if (this->spu_events[this_event].event->object.overlay != NULL) { - vo_overlay_t *overlay = this->spu_objects[handle].overlay; - vo_overlay_t *event_overlay = this->spu_events[this_event].event->object.overlay; -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "event_overlay\n"); -#endif - spudec_print_overlay(event_overlay); -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "overlay\n"); -#endif - spudec_print_overlay(overlay); - - this->spu_objects[handle].handle = handle; /* This should not change for menus */ - /* If rle is not empty, free it first */ - if(overlay && overlay->rle) { -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "FREE1: overlay->rle %p\n", - overlay->rle); -#endif - free (overlay->rle); - overlay->rle = NULL; -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "FREE2: overlay->rle %p\n", - overlay->rle); -#endif - } - 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 ) { -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "mixing clut\n"); -#endif - 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 ) { -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "mixing trans\n"); -#endif - 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]; - } - this->spu_showing[1].handle = handle; -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "overlay after\n"); -#endif - spudec_print_overlay(overlay); -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "FREE1: event_overlay %p\n", - this->spu_events[this_event].event->object.overlay = NULL); -#endif - /* The null test was done at the start of this case statement */ - free (this->spu_events[this_event].event->object.overlay); - this->spu_events[this_event].event->object.overlay = NULL; -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "FREE2: event_ovlerlay %p\n", - this->spu_events[this_event].event->object.overlay); -#endif - } - break; - - case EVENT_MENU_BUTTON: -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "MENU BUTTON NOW\n"); -#endif - if (this->spu_events[this_event].event->object.overlay != NULL) { - vo_overlay_t *overlay = this->spu_objects[handle].overlay; - vo_overlay_t *event_overlay = this->spu_events[this_event].event->object.overlay; -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "event_overlay\n"); -#endif - spudec_print_overlay(event_overlay); -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "overlay\n"); -#endif - spudec_print_overlay(overlay); - this->spu_objects[handle].handle = handle; /* This should not change for menus */ - 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; - //overlay->rgb_clut = event_overlay->rgb_clut; /* May needed later for OSD */ - if((event_overlay->color[0] + - event_overlay->color[1] + - event_overlay->color[2] + - event_overlay->color[3]) > 0 ) { -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "mixing clut\n"); -#endif - 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 ) { -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "mixing trans\n"); -#endif - 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]; - } - this->spu_showing[1].handle = handle; -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "overlay after\n"); -#endif - spudec_print_overlay(overlay); -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "FREE1: event_overlay %p\n", - this->spu_events[this_event].event->object.overlay = NULL); -#endif - /* The null test was done at the start of this case statement */ - free (this->spu_events[this_event].event->object.overlay); - this->spu_events[this_event].event->object.overlay = NULL; -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "FREE2: event_ovlerlay %p\n", - this->spu_events[this_event].event->object.overlay); -#endif - } - break; - - default: -#ifdef LOG_DEBUG - xprintf (VERBOSE|SPU, "Unhandled event type\n"); -#endif - break; - - } - this->spu_events[0].next_event = this->spu_events[this_event].next_event; - this->spu_events[this_event].next_event = 0; - this->spu_events[this_event].event->event_type = 0; - pthread_mutex_unlock (&this->spu_events_mutex); -} - -/* This is called from video_out and should return one image. - * Repeated calls will display the next image. - * until the last image is reached, when a NULL is returned - * and the pointer starts from the beginning again. - * For now, a max of 5 diffent images can be displayed at once. - * Maybe we should add a callback instead of calling the function all the time. - * We could rename this then to "Render overlay" - * This function needs an API change, to add a callback function to do the actual overlay. - * In this way we can get multiple objects displayed at the same time. - * i.e. Subtitles and OSD. - * Currently, only one object can be displayed at the same time. - * The first checkin of this code should add no more functionality than the current code. - * It was just be checked in so others can test it. - */ - -static vo_overlay_t* spudec_get_overlay(ovl_src_t *ovl_src, int vpts) { - int32_t handle; - spudec_decoder_t *this = (spudec_decoder_t*) ovl_src->src_gen; - - /* Look at next event, if current video vpts > first event on queue, process the event - * else just continue - */ - spu_process_event( this, vpts ); - /* Scan through 5 entries and display any present. - * Currently, only 1 entry is scanned, until API can change. - */ - handle=this->spu_showing[1].handle; /* handle is only valid if the object is currently visable. */ - if (handle < 0) return NULL; - return this->spu_objects[handle].overlay; -} - static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { spudec_decoder_t *this = (spudec_decoder_t *) this_gen; xine_spu_event_t *event = (xine_spu_event_t *) event_gen; @@ -890,7 +367,7 @@ static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { switch (event->event.type) { case XINE_EVENT_SPU_BUTTON: { - spu_overlay_event_t *overlay_event = NULL; + video_overlay_event_t *overlay_event = NULL; vo_overlay_t *overlay = NULL; spu_button_t *but = event->data; #ifdef LOG_DEBUG @@ -898,7 +375,7 @@ static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { overlay_event, sizeof(spu_overlay_event_t)); #endif - overlay_event = xine_xmalloc (sizeof(spu_overlay_event_t)); + overlay_event = xine_xmalloc (sizeof(video_overlay_event_t)); #ifdef LOG_DEBUG xprintf (VERBOSE|SPU, "MALLOC2: overlay_event %p, len=%d\n", overlay_event, @@ -928,7 +405,7 @@ static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { if (!this->state.menu) return; if (but->show) { - overlay_event->object.handle = spu_get_menu_handle(this); + overlay_event->object.handle = this->menu_handle; overlay_event->object.overlay=overlay; overlay_event->event_type = EVENT_MENU_BUTTON; overlay_event->vpts = 0; /* Activate it NOW */ @@ -944,13 +421,12 @@ static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { overlay->trans[1] = but->trans[1]; overlay->trans[2] = but->trans[2]; overlay->trans[3] = but->trans[3]; - spu_add_event(this, overlay_event); } else { - overlay_event->object.handle = spu_get_menu_handle(this); + overlay_event->object.handle = this->menu_handle; overlay_event->event_type = EVENT_HIDE_MENU; overlay_event->vpts = 0; /* Activate it NOW */ - spu_add_event(this, overlay_event); } + this->vo_out->overlay_source->add_event(this->vo_out->overlay_source, (void *)overlay_event); } break; case XINE_EVENT_SPU_CLUT: @@ -963,21 +439,6 @@ static void spudec_event_listener(void *this_gen, xine_event_t *event_gen) { } } break; - /* What is this for? - * This event is for GUI -> NAVDVD plugin - * SPUDEC will have to use a different EVENT - * if it needs this for CLUT auto detect. - * ->that was a patch to redetect clut on spu channel change. - * not very important, i will take a look when i have time. [MF] - */ - /* FIXME - case XINE_UI_GET_SPU_LANG: - { - this->state.need_clut = 1; - } - break; - */ - } } @@ -1008,9 +469,10 @@ spu_decoder_t *init_spu_decoder_plugin (int iface_version, xine_t *xine) { this->spu_decoder.get_identifier = spudec_get_id; this->spu_decoder.priority = 1; - this->ovl_src.src_gen = this; - this->ovl_src.get_overlay = spudec_get_overlay; this->xine = xine; + + this->menu_handle = -1; + this->event.object.overlay = malloc(sizeof(vo_overlay_t)); xine_register_event_listener(xine, spudec_event_listener, this); diff --git a/src/video_out/video_out_xshm.c b/src/video_out/video_out_xshm.c index 4a919fd7f..d6a744f80 100644 --- a/src/video_out/video_out_xshm.c +++ b/src/video_out/video_out_xshm.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_xshm.c,v 1.51 2001/11/18 03:53:24 guenter Exp $ + * $Id: video_out_xshm.c,v 1.52 2001/11/28 22:19:12 miguelfreitas Exp $ * * video_out_xshm.c, X11 shared memory extension interface for xine * @@ -720,7 +720,7 @@ static void xshm_overlay_clut_yuv2rgb(xshm_driver_t *this, vo_overlay_t *overla int i; clut_t* clut = (clut_t*) overlay->color; - for (i = 0; i < 4; i++) { + for (i = 0; i < sizeof(overlay->color)/sizeof(overlay->color[0]); i++) { *((uint32_t *)&clut[i]) = this->yuv2rgb->yuv2rgb_single_pixel_fun(this->yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr); diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c index be6bf45a0..938d6349f 100644 --- a/src/video_out/video_out_xv.c +++ b/src/video_out/video_out_xv.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_xv.c,v 1.80 2001/11/23 22:29:45 f1rmb Exp $ + * $Id: video_out_xv.c,v 1.81 2001/11/28 22:19:12 miguelfreitas Exp $ * * video_out_xv.c, X11 video extension interface for xine * @@ -1364,7 +1364,6 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) { } else if(!strcmp(attr[k].name, "XV_FILTER")) { int xv_filter; /* This setting is specific to Permedia 2/3 cards. */ - printf("XV_FILTER (%d->%d)/n",attr[k].min_value, attr[k].max_value); xv_filter = config->register_range (config, "video.XV_FILTER", 0, attr[k].min_value, attr[k].max_value, "bilinear scaling mode (permedia 2/3)", 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; |