summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Roitzsch <mroi@users.sourceforge.net>2004-04-09 15:01:29 +0000
committerMichael Roitzsch <mroi@users.sourceforge.net>2004-04-09 15:01:29 +0000
commit039fe9adb8fdc6e361d0b193ae1d7bcfec5287d9 (patch)
tree3329ad5e475689bd8746dcad3611978ffe621156
parentff3ff7253e5680592329b363b9f84cccd8231eff (diff)
downloadxine-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--ChangeLog2
-rw-r--r--src/libspudec/spu.c148
-rw-r--r--src/libspudec/spu.h21
-rw-r--r--src/libspudec/xine_decoder.c28
4 files changed, 151 insertions, 48 deletions
diff --git a/ChangeLog b/ChangeLog
index 78714a9c6..f55647d65 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;