diff options
author | Michael Roitzsch <mroi@users.sourceforge.net> | 2004-04-09 15:01:29 +0000 |
---|---|---|
committer | Michael Roitzsch <mroi@users.sourceforge.net> | 2004-04-09 15:01:29 +0000 |
commit | 039fe9adb8fdc6e361d0b193ae1d7bcfec5287d9 (patch) | |
tree | 3329ad5e475689bd8746dcad3611978ffe621156 | |
parent | ff3ff7253e5680592329b363b9f84cccd8231eff (diff) | |
download | xine-lib-039fe9adb8fdc6e361d0b193ae1d7bcfec5287d9.tar.gz xine-lib-039fe9adb8fdc6e361d0b193ae1d7bcfec5287d9.tar.bz2 |
porting the rudimentary NAV timestamp handling from DXR3 SPU decoder makes
the menu of "24" season 1 work correctly with software decoding;
thanks to Bob "GnomeKing" for doing all the testing
CVS patchset: 6362
CVS date: 2004/04/09 15:01:29
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | src/libspudec/spu.c | 148 | ||||
-rw-r--r-- | src/libspudec/spu.h | 21 | ||||
-rw-r--r-- | src/libspudec/xine_decoder.c | 28 |
4 files changed, 151 insertions, 48 deletions
@@ -1,5 +1,7 @@ xine-lib (1-rc4) * experimental DTS software decoder using libdts + * SPU decoder: timestamp handling for NAV packets fixes the menu on the first + DVD of "24" season 1 xine-lib (1-rc3c) * fix the deadlock with non-seekable input plugins diff --git a/src/libspudec/spu.c b/src/libspudec/spu.c index d363cfabd..4e8b76eef 100644 --- a/src/libspudec/spu.c +++ b/src/libspudec/spu.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2002-2004 the xine project * * Copyright (C) James Courtier-Dutton James@superbug.demon.co.uk - July 2001 * @@ -35,7 +36,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.73 2003/12/05 15:55:00 f1rmb Exp $ + * $Id: spu.c,v 1.74 2004/04/09 15:01:29 mroi Exp $ * */ @@ -150,11 +151,23 @@ void spudec_decode_nav(spudec_decoder_t *this, buf_element_t *buf) { // self->vobu_length = self->dsi.dsi_gi.vobu_ea; } } + + /* NAV packets contain start and end presentation timestamps, which tell the + * application, when the highlight information in the NAV is supposed to be valid. + * We handle these timestamps only in a very stripped-down way: We keep a list + * of NAV packets (or better: the PCI part of them), tagged with a VPTS timestamp + * telling, when the NAV should be processed. However, we only enqueue a new node + * into this list, when we receive new highlight information during an already + * showing menu. This happens very rarerly on common DVDs, so it is of low impact. + * And we only check for processing of queued entries at some prominent + * locations in this SPU decoder. Since presentation timestamps rarely solve a real + * purpose on most DVDs, this is ok compared to the full-blown solution, which would + * require a separate thread managing the queue all the time. */ pthread_mutex_lock(&this->nav_pci_lock); switch (pci.hli.hl_gi.hli_ss) { case 0: /* No Highlight information for this VOBU */ - if ( this->pci.hli.hl_gi.hli_ss == 1) { + if ( this->pci_cur.pci.hli.hl_gi.hli_ss == 1) { /* Hide menu spu between menus */ #ifdef LOG_BUTTON printf("libspudec:nav:SHOULD HIDE SPU here\n"); @@ -172,7 +185,8 @@ void spudec_decode_nav(spudec_decoder_t *this, buf_element_t *buf) { xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "libspudec: No video_overlay handles left for menu\n"); } } - xine_fast_memcpy(&this->pci, &pci, sizeof(pci_t)); + spudec_clear_nav_list(this); + xine_fast_memcpy(&this->pci_cur.pci, &pci, sizeof(pci_t)); /* incoming SPUs will be plain subtitles */ this->event.object.object_type = 0; if (this->button_filter) { @@ -192,42 +206,56 @@ void spudec_decode_nav(spudec_decoder_t *this, buf_element_t *buf) { break; case 1: /* All New Highlight information for this VOBU */ - xine_fast_memcpy(&this->pci, &pci, sizeof(pci_t)); - /* incoming SPUs will be menus */ - this->event.object.object_type = 1; - if (!this->button_filter) { - /* we possibly entered a menu, so we update the UI button info */ - xine_event_t event; - xine_ui_data_t data; - - event.type = XINE_EVENT_UI_NUM_BUTTONS; - event.data = &data; - event.data_length = sizeof(data); - data.num_buttons = pci.hli.hl_gi.btn_ns; - - xine_event_send(this->stream, &event); + if (this->pci_cur.pci.hli.hl_gi.hli_ss != 0 && + pci.hli.hl_gi.hli_s_ptm > this->pci_cur.pci.hli.hl_gi.hli_s_ptm) { + pci_node_t *node = &this->pci_cur; + printf("libspudec: DEBUG: allocating new PCI node for hli_s_ptm %d\n", pci.hli.hl_gi.hli_s_ptm); + /* append PCI at the end of the list */ + while (node->next) node = node->next; + node->next = (pci_node_t *)xine_xmalloc(sizeof(pci_node_t)); + node->next->vpts = this->stream->metronom->got_spu_packet(this->stream->metronom, pci.hli.hl_gi.hli_s_ptm); + node->next->next = NULL; + xine_fast_memcpy(&node->next->pci, &pci, sizeof(pci_t)); + } else { + spudec_clear_nav_list(this); + /* menu ahead, remember PCI for later use */ + xine_fast_memcpy(&this->pci_cur.pci, &pci, sizeof(pci_t)); + spudec_process_nav(this); } - this->button_filter=1; - /******************************* - * We should do something about fosl_btnn, but - * until we can send the info to dvdnav, ignore it. - * if( pci.hli.hl_gi.fosl_btnn) { - * this->buttonN = pci.hli.hl_gi.fosl_btnn; - * } - *******************************/ break; case 2: /* Use Highlight information from previous VOBU */ - this->pci.pci_gi.vobu_s_ptm = pci.pci_gi.vobu_s_ptm; - this->pci.pci_gi.vobu_e_ptm = pci.pci_gi.vobu_e_ptm; - this->pci.pci_gi.vobu_se_e_ptm = pci.pci_gi.vobu_se_e_ptm; + if (this->pci_cur.next) { + /* apply changes to last enqueued NAV */ + pci_node_t *node = this->pci_cur.next; + while (node->next) node = node->next; + node->pci.pci_gi.vobu_s_ptm = pci.pci_gi.vobu_s_ptm; + node->pci.pci_gi.vobu_e_ptm = pci.pci_gi.vobu_e_ptm; + node->pci.pci_gi.vobu_se_e_ptm = pci.pci_gi.vobu_se_e_ptm; + spudec_update_nav(this); + } else { + this->pci_cur.pci.pci_gi.vobu_s_ptm = pci.pci_gi.vobu_s_ptm; + this->pci_cur.pci.pci_gi.vobu_e_ptm = pci.pci_gi.vobu_e_ptm; + this->pci_cur.pci.pci_gi.vobu_se_e_ptm = pci.pci_gi.vobu_se_e_ptm; + } break; case 3: /* Use Highlight information from previous VOBU except commands, which come from this VOBU */ - this->pci.pci_gi.vobu_s_ptm = pci.pci_gi.vobu_s_ptm; - this->pci.pci_gi.vobu_e_ptm = pci.pci_gi.vobu_e_ptm; - this->pci.pci_gi.vobu_se_e_ptm = pci.pci_gi.vobu_se_e_ptm; - /* FIXME: Add command copying here */ + if (this->pci_cur.next) { + /* apply changes to last enqueued NAV */ + pci_node_t *node = this->pci_cur.next; + while (node->next) node = node->next; + node->pci.pci_gi.vobu_s_ptm = pci.pci_gi.vobu_s_ptm; + node->pci.pci_gi.vobu_e_ptm = pci.pci_gi.vobu_e_ptm; + node->pci.pci_gi.vobu_se_e_ptm = pci.pci_gi.vobu_se_e_ptm; + /* FIXME: Add command copying here */ + spudec_update_nav(this); + } else { + this->pci_cur.pci.pci_gi.vobu_s_ptm = pci.pci_gi.vobu_s_ptm; + this->pci_cur.pci.pci_gi.vobu_e_ptm = pci.pci_gi.vobu_e_ptm; + this->pci_cur.pci.pci_gi.vobu_se_e_ptm = pci.pci_gi.vobu_se_e_ptm; + /* FIXME: Add command copying here */ + } break; default: xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, @@ -238,6 +266,48 @@ void spudec_decode_nav(spudec_decoder_t *this, buf_element_t *buf) { return; } +void spudec_clear_nav_list(spudec_decoder_t *this) +{ + while (this->pci_cur.next) { + pci_node_t *node = this->pci_cur.next->next; + free(this->pci_cur.next); + this->pci_cur.next = node; + } + /* invalidate current timestamp */ + this->pci_cur.pci.hli.hl_gi.hli_s_ptm = (uint32_t)-1; +} + +void spudec_update_nav(spudec_decoder_t *this) +{ + metronom_clock_t *clock = this->stream->xine->clock; + + if (this->pci_cur.next && this->pci_cur.next->vpts <= clock->get_current_time(clock)) { + pci_node_t *node = this->pci_cur.next; + xine_fast_memcpy(&this->pci_cur, this->pci_cur.next, sizeof(pci_node_t)); + spudec_process_nav(this); + free(node); + } +} + +void spudec_process_nav(spudec_decoder_t *this) +{ + /* incoming SPUs will be menus */ + this->event.object.object_type = 1; + if (!this->button_filter) { + /* we possibly entered a menu, so we update the UI button info */ + xine_event_t event; + xine_ui_data_t data; + + event.type = XINE_EVENT_UI_NUM_BUTTONS; + event.data = &data; + event.data_length = sizeof(data); + data.num_buttons = this->pci_cur.pci.hli.hl_gi.btn_ns; + + xine_event_send(this->stream, &event); + } + this->button_filter=1; +} + void spudec_reassembly (xine_t *xine, spudec_seq_t *seq, uint8_t *pkt_data, u_int pkt_len) { #ifdef LOG_DEBUG @@ -357,7 +427,7 @@ void spudec_process (spudec_decoder_t *this, int stream_id) { printf ("spu: forced display:%s\n", this->state.forced_display ? "Yes" : "No" ); #endif pthread_mutex_lock(&this->nav_pci_lock); - if (this->pci.hli.hl_gi.hli_s_ptm == this->spudec_stream_state[stream_id].pts) { + if (this->pci_cur.pci.hli.hl_gi.hli_s_ptm == this->spudec_stream_state[stream_id].pts) { if (this->state.visible == OVERLAY_EVENT_HIDE) { /* menus are hidden via nav packet decoding, not here */ /* FIXME: James is not sure about this solution and may want to look this over. @@ -366,10 +436,10 @@ void spudec_process (spudec_decoder_t *this, int stream_id) { pthread_mutex_unlock(&this->nav_pci_lock); continue; } - if ( this->pci.hli.hl_gi.fosl_btnn > 0) { + if ( this->pci_cur.pci.hli.hl_gi.fosl_btnn > 0) { xine_event_t event; - this->buttonN = this->pci.hli.hl_gi.fosl_btnn ; + this->buttonN = this->pci_cur.pci.hli.hl_gi.fosl_btnn ; event.type = XINE_EVENT_INPUT_BUTTON_FORCE; event.stream = this->stream; event.data = &this->buttonN; @@ -380,13 +450,13 @@ void spudec_process (spudec_decoder_t *this, int stream_id) { fprintf(stderr, "libspudec:Full Overlay\n"); #endif if (!spudec_copy_nav_to_overlay(this->stream->xine, - &this->pci, this->state.clut, + &this->pci_cur.pci, this->state.clut, this->buttonN, 0, &this->overlay, &this->overlay)) { /* current button does not exist -> use another one */ xine_event_t event; - if (this->buttonN > this->pci.hli.hl_gi.btn_ns) - this->buttonN = this->pci.hli.hl_gi.btn_ns; + if (this->buttonN > this->pci_cur.pci.hli.hl_gi.btn_ns) + this->buttonN = this->pci_cur.pci.hli.hl_gi.btn_ns; else this->buttonN = 1; event.type = XINE_EVENT_INPUT_BUTTON_FORCE; @@ -395,7 +465,7 @@ void spudec_process (spudec_decoder_t *this, int stream_id) { event.data_length = sizeof(this->buttonN); xine_event_send(this->stream, &event); spudec_copy_nav_to_overlay(this->stream->xine, - &this->pci, this->state.clut, + &this->pci_cur.pci, this->state.clut, this->buttonN, 0, &this->overlay, &this->overlay); } } else { diff --git a/src/libspudec/spu.h b/src/libspudec/spu.h index 3aa55ba0a..2edda689b 100644 --- a/src/libspudec/spu.h +++ b/src/libspudec/spu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2001 the xine project + * Copyright (C) 2000-2004 the xine project * * Copyright (C) James Courtier-Dutton James@superbug.demon.co.uk - July 2001 * @@ -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.24 2003/12/05 15:55:00 f1rmb Exp $ + * $Id: spu.h,v 1.25 2004/04/09 15:01:47 mroi Exp $ * * This file was originally part of the OMS program. * @@ -102,6 +102,13 @@ typedef struct { spu_decoder_class_t decoder_class; } spudec_class_t; +typedef struct pci_node_s pci_node_t; +struct pci_node_s { + pci_t pci; + uint64_t vpts; + pci_node_t *next; +}; + typedef struct spudec_decoder_s { spu_decoder_t spu_decoder; @@ -118,16 +125,20 @@ typedef struct spudec_decoder_s { vo_overlay_t overlay; int ovl_caps; int output_open; - pci_t pci; + pthread_mutex_t nav_pci_lock; + pci_node_t pci_cur; uint32_t buttonN; /* Current button number for highlights */ - int32_t button_filter; /* Allow highlight changes or not */ - pthread_mutex_t nav_pci_lock; + int32_t button_filter; /* Allow highlight changes or not */ int64_t last_event_vpts; } spudec_decoder_t; void spudec_reassembly (xine_t *xine, spudec_seq_t *seq, uint8_t *pkt_data, u_int pkt_len); void spudec_process( spudec_decoder_t *this, int stream_id); +/* the nav functions must be called with the nav_pci_lock held */ void spudec_decode_nav( spudec_decoder_t *this, buf_element_t *buf); +void spudec_clear_nav_list(spudec_decoder_t *this); +void spudec_update_nav(spudec_decoder_t *this); +void spudec_process_nav(spudec_decoder_t *this); int spudec_copy_nav_to_overlay(xine_t *xine, pci_t* nav_pci, uint32_t* clut, int32_t button, int32_t mode, vo_overlay_t * overlay, vo_overlay_t * base ); diff --git a/src/libspudec/xine_decoder.c b/src/libspudec/xine_decoder.c index 0da9a701c..713271d44 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.105 2004/03/03 20:09:14 mroi Exp $ + * $Id: xine_decoder.c,v 1.106 2004/04/09 15:01:47 mroi Exp $ * * stuff needed to turn libspu into a xine decoder plugin */ @@ -118,6 +118,11 @@ static void spudec_decode_data (spu_decoder_t *this_gen, buf_element_t *buf) { return; } + /* check, if we need to process the next PCI from the list */ + pthread_mutex_lock(&this->nav_pci_lock); + spudec_update_nav(this); + pthread_mutex_unlock(&this->nav_pci_lock); + #ifdef LOG_DEBUG printf("libspudec:got buffer type = %x\n", buf->type); #endif @@ -164,9 +169,18 @@ static void spudec_reset (spu_decoder_t *this_gen) { this->spudec_stream_state[i].ra_seq.complete = 1; this->spudec_stream_state[i].ra_seq.broken = 0; } + + pthread_mutex_lock(&this->nav_pci_lock); + spudec_clear_nav_list(this); + pthread_mutex_unlock(&this->nav_pci_lock); } static void spudec_discontinuity (spu_decoder_t *this_gen) { + spudec_decoder_t *this = (spudec_decoder_t *) this_gen; + + pthread_mutex_lock(&this->nav_pci_lock); + spudec_clear_nav_list(this); + pthread_mutex_unlock(&this->nav_pci_lock); } @@ -188,6 +202,8 @@ static void spudec_dispose (spu_decoder_t *this_gen) { this->spudec_stream_state[i].overlay_handle = -1; free (this->spudec_stream_state[i].ra_seq.buf); } + + spudec_clear_nav_list(this); pthread_mutex_destroy(&this->nav_pci_lock); free (this->event.object.overlay); @@ -206,7 +222,8 @@ static int spudec_get_interact_info (spu_decoder_t *this_gen, void *data) { /*printf("get_interact_info() coping nav_pci\n");*/ pthread_mutex_lock(&this->nav_pci_lock); - memcpy(data, &this->pci, sizeof(pci_t) ); + spudec_update_nav(this); + memcpy(data, &this->pci_cur.pci, sizeof(pci_t) ); pthread_mutex_unlock(&this->nav_pci_lock); return 1; @@ -260,14 +277,15 @@ static void spudec_set_button (spu_decoder_t *this_gen, int32_t button, int32_t this->button_filter = 2; } pthread_mutex_lock(&this->nav_pci_lock); + spudec_update_nav(this); overlay_event->object.handle = this->menu_handle; - overlay_event->object.pts = this->pci.hli.hl_gi.hli_s_ptm; + overlay_event->object.pts = this->pci_cur.pci.hli.hl_gi.hli_s_ptm; overlay_event->object.overlay=overlay; overlay_event->event_type = OVERLAY_EVENT_MENU_BUTTON; #ifdef LOG_BUTTON fprintf(stderr, "libspudec:Button Overlay\n"); #endif - spudec_copy_nav_to_overlay(this->stream->xine, &this->pci, this->state.clut, + spudec_copy_nav_to_overlay(this->stream->xine, &this->pci_cur.pci, this->state.clut, this->buttonN, show-1, overlay, &this->overlay ); pthread_mutex_unlock(&this->nav_pci_lock); } else { @@ -318,6 +336,8 @@ static spu_decoder_t *open_plugin (spu_decoder_class_t *class_gen, xine_stream_t this->event.object.overlay = xine_xmalloc(sizeof(vo_overlay_t)); pthread_mutex_init(&this->nav_pci_lock, NULL); + this->pci_cur.pci.hli.hl_gi.hli_ss = 0; + this->pci_cur.next = NULL; this->ovl_caps = stream->video_out->get_capabilities(stream->video_out); this->output_open = 0; |