diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libspudvb/xine_spudvb_decoder.c | 139 |
1 files changed, 76 insertions, 63 deletions
diff --git a/src/libspudvb/xine_spudvb_decoder.c b/src/libspudvb/xine_spudvb_decoder.c index f2fcfe182..339d66b2e 100644 --- a/src/libspudvb/xine_spudvb_decoder.c +++ b/src/libspudvb/xine_spudvb_decoder.c @@ -28,15 +28,11 @@ */ #include "pthread.h" +#include <errno.h> #include "xine_internal.h" #include "osd.h" #define MAX_REGIONS 7 -/* check every DVBSUB_TIMER_DELAY seconds */ -#define DVBSUB_TIMER_DELAY 1 -/* hide subs after n counts of the delay */ -#define SUB_TIMEOUT 6 - typedef struct { int x, y; unsigned char is_visible; @@ -90,6 +86,9 @@ typedef struct dvb_spu_decoder_s { spu_dvb_descriptor_t *spu_descriptor; + /* dvbsub_osd_mutex should be locked around all calls to this->osd_renderer->show() + and this->osd_renderer->hide() */ + pthread_mutex_t dvbsub_osd_mutex; osd_object_t *osd; char *bitmap; @@ -101,11 +100,9 @@ typedef struct dvb_spu_decoder_s { uint64_t vpts; uint64_t end_vpts; - pthread_mutex_t dvbsub_timer_mutex; - /* This is set to non-zero if the timer thread is wanted to stop. */ - int dvbsub_timer_stop; pthread_t dvbsub_timer_thread; - unsigned int dvbsub_timer_tcount; + struct timespec dvbsub_hide_timeout; + pthread_cond_t dvbsub_restart_timeout; dvbsub_func_t *dvbsub; int show; } dvb_spu_decoder_t; @@ -544,43 +541,58 @@ void process_object_data_segment (dvb_spu_decoder_t * this) } } - -/* Sleep routine for pthread */ -static void dvbsub_pthread_sleep(int seconds) { - pthread_mutex_t dummy_mutex; - pthread_cond_t dummy_cond; - struct timespec timeout; - - /* Create a dummy mutex which doesn't unlock for sure while waiting. */ - pthread_mutex_init(&dummy_mutex, NULL); - pthread_mutex_lock(&dummy_mutex); - - /* Create a dummy condition variable. */ - pthread_cond_init(&dummy_cond, NULL); - - timeout.tv_sec = time(NULL) + seconds; - timeout.tv_nsec = 0; - - pthread_cond_timedwait(&dummy_cond, &dummy_mutex, &timeout); - - pthread_cond_destroy(&dummy_cond); - pthread_mutex_unlock(&dummy_mutex); - pthread_mutex_destroy(&dummy_mutex); +static void unlock_mutex_cancellation_func(void *mutex_gen) +{ + pthread_mutex_t *mutex = (pthread_mutex_t*) mutex_gen; + pthread_mutex_unlock(mutex); } +/* Thread routine that checks for subtitle timeout periodically. + To avoid unexpected subtitle hiding, calls to this->stream->osd_renderer->show() + should be in blocks like: -/* Thread routine that checks for subtitle timeout periodically. */ -static void* dvbsub_timer_func(void *this_gen) { - dvb_spu_decoder_t *this = (dvb_spu_decoder_t *) this_gen; + pthread_mutex_lock(&this->dvbsub_osd_mutex); + this->stream->osd_renderer->show(...); + this->dvbsub_hide_timeout.tv_sec = time(NULL) + timeout value; + pthread_cond_signal(&this->dvbsub_restart_timeout); + pthread_mutex_unlock(&this->dvbsub_osd_mutex); - while (!this->dvbsub_timer_stop) { - pthread_mutex_lock(&this->dvbsub_timer_mutex); - if(this->dvbsub_timer_tcount++ > SUB_TIMEOUT) - this->stream->osd_renderer->hide (this->osd, 0); - pthread_mutex_unlock(&this->dvbsub_timer_mutex); - dvbsub_pthread_sleep(DVBSUB_TIMER_DELAY); + This ensures that the timeout is changed with the lock held, and + that the thread is signalled to pick up the new timeout. +*/ +static void* dvbsub_timer_func(void *this_gen) +{ + dvb_spu_decoder_t *this = (dvb_spu_decoder_t *) this_gen; + pthread_mutex_lock(&this->dvbsub_osd_mutex); + + /* If we're cancelled via pthread_cancel, unlock the mutex */ + pthread_cleanup_push(unlock_mutex_cancellation_func, &this->dvbsub_osd_mutex); + + while(1) + { + /* Record the current timeout, and wait - note that pthread_cond_timedwait + will unlock the mutex on entry, and lock it on exit */ + struct timespec timeout = this->dvbsub_hide_timeout; + int result = pthread_cond_timedwait(&this->dvbsub_restart_timeout, + &this->dvbsub_osd_mutex, + &this->dvbsub_hide_timeout); + if(result == ETIMEDOUT && + timeout.tv_sec == this->dvbsub_hide_timeout.tv_sec && + timeout.tv_nsec == this->dvbsub_hide_timeout.tv_nsec) + { + /* We timed out, and no-one changed the timeout underneath us. + Hide the OSD, then wait until we're signalled. */ + if(this && this->stream && this->stream->osd_renderer && this->osd) + { + lprintf("Hiding OSD in emergency thread\n"); + this->stream->osd_renderer->hide(this->osd, 0); + } + pthread_cond_wait(&this->dvbsub_restart_timeout, &this->dvbsub_osd_mutex); } - return NULL; + } + + pthread_cleanup_pop(1); + return NULL; } void draw_subtitles (dvb_spu_decoder_t * this) @@ -614,23 +626,17 @@ void draw_subtitles (dvb_spu_decoder_t * this) if(display){ - /* start timer thread if stopped */ - if(this->dvbsub_timer_stop){ - this->dvbsub_timer_stop=0; - if (pthread_create(&this->dvbsub_timer_thread, NULL, dvbsub_timer_func, this) != 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, _("dvbsub: cannot create timer thread\n")); - } - } - /* display immediately at requested PTS*/ this->stream->osd_renderer->set_palette(this->osd,(uint32_t *)this->dvbsub->colours,this->dvbsub->trans); this->stream->osd_renderer->draw_bitmap (this->osd,this->bitmap, 1,1,720,576,NULL); - pthread_mutex_lock(&this->dvbsub_timer_mutex); + pthread_mutex_lock(&this->dvbsub_osd_mutex); this->stream->osd_renderer->show (this->osd, this->vpts); - /* reset the timer thread */ - this->dvbsub_timer_tcount=0; - pthread_mutex_unlock(&this->dvbsub_timer_mutex); + this->dvbsub_hide_timeout.tv_nsec = 0; + this->dvbsub_hide_timeout.tv_sec = time(NULL) + this->dvbsub->page.page_time_out; + lprintf("page_time_out %d\n",this->dvbsub->page.page_time_out); + pthread_cond_signal(&this->dvbsub_restart_timeout); + pthread_mutex_unlock(&this->dvbsub_osd_mutex); } } @@ -651,8 +657,10 @@ static void spudec_decode_data (spu_decoder_t * this_gen, buf_element_t * buf) if (buf->decoder_flags & BUF_FLAG_SPECIAL) { if (buf->decoder_info[1] == BUF_SPECIAL_SPU_DVB_DESCRIPTOR) { if (buf->decoder_info[2] == 0) { - this->dvbsub_timer_stop=1; - this->stream->osd_renderer->hide (this->osd, 0); + /* Hide the osd - note that if the timeout thread times out, it'll rehide, which is harmless */ + pthread_mutex_lock(&this->dvbsub_osd_mutex); + this->stream->osd_renderer->hide(this->osd, 0); + pthread_mutex_unlock(&this->dvbsub_osd_mutex); } else { xine_fast_memcpy (this->spu_descriptor, buf->decoder_info_ptr[2], buf->decoder_info[2]); @@ -746,8 +754,10 @@ static void spudec_reset (spu_decoder_t * this_gen) { dvb_spu_decoder_t *this = (dvb_spu_decoder_t *) this_gen; - if (this->osd) - this->stream->osd_renderer->hide (this->osd, 0); + /* Hide the osd - if the timeout thread times out, it'll rehide harmlessly */ + pthread_mutex_lock(&this->dvbsub_osd_mutex); + this->stream->osd_renderer->hide(this->osd, 0); + pthread_mutex_unlock(&this->dvbsub_osd_mutex); } @@ -760,9 +770,10 @@ static void spudec_dispose (spu_decoder_t * this_gen) { dvb_spu_decoder_t *this = (dvb_spu_decoder_t *) this_gen; - if(!this->dvbsub_timer_stop){ - this->dvbsub_timer_stop=1; - } + pthread_cancel(this->dvbsub_timer_thread); + pthread_join(this->dvbsub_timer_thread, NULL); + pthread_mutex_destroy(&this->dvbsub_osd_mutex); + pthread_cond_destroy(&this->dvbsub_restart_timeout); if(this->spu_descriptor){ free(this->spu_descriptor); @@ -822,9 +833,11 @@ static spu_decoder_t *dvb_spu_class_open_plugin (spu_decoder_class_t * class_gen this->stream->osd_renderer->set_encoding (this->osd, NULL); this->stream->osd_renderer->set_text_palette (this->osd, TEXTPALETTE_YELLOW_BLACK_TRANSPARENT, OSD_TEXT1); - - /* subtitle timer thread. */ - this->dvbsub_timer_stop = 1; + pthread_mutex_init(&this->dvbsub_osd_mutex, NULL); + pthread_cond_init(&this->dvbsub_restart_timeout, NULL); + this->dvbsub_hide_timeout.tv_nsec = 0; + this->dvbsub_hide_timeout.tv_sec = time(NULL); + pthread_create(&this->dvbsub_timer_thread, NULL, dvbsub_timer_func, this); return (spu_decoder_t *) this; } |