From 9f169bfef3229a9c2b2396993e2fcea1b3a7c8ac Mon Sep 17 00:00:00 2001 From: Michael Roitzsch Date: Mon, 24 Jun 2002 15:49:32 +0000 Subject: Add a correction for spus during menus that contain a display duration entry. This confuses the card because the spu should be hidden when the menu is left, not by timeout. Therefore we kill such an entry in menu spus. CVS patchset: 2154 CVS date: 2002/06/24 15:49:32 --- src/dxr3/dxr3_decode_spu.c | 123 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 27 deletions(-) diff --git a/src/dxr3/dxr3_decode_spu.c b/src/dxr3/dxr3_decode_spu.c index 6b3a37d47..4dfccaade 100644 --- a/src/dxr3/dxr3_decode_spu.c +++ b/src/dxr3/dxr3_decode_spu.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: dxr3_decode_spu.c,v 1.5 2002/06/12 15:09:07 mroi Exp $ + * $Id: dxr3_decode_spu.c,v 1.6 2002/06/24 15:49:32 mroi Exp $ */ /* dxr3 spu decoder plugin. @@ -63,15 +63,15 @@ static void dxr3_spudec_reset(spu_decoder_t *this_gen); static void dxr3_spudec_close(spu_decoder_t *this_gen); static void dxr3_spudec_dispose(spu_decoder_t *this_gen); -/* helper functions */ -static int dxr3_present(xine_t *xine); -static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen); -static int dxr3_spudec_copy_nav_to_btn(pci_t *nav_pci, int32_t button, int32_t mode, em8300_button_t *btn); -static void dxr3_swab_clut(int* clut); - /* plugin structures */ typedef struct dxr3_spu_stream_state_s { uint32_t stream_filter; + + int spu_length; + int spu_ctrl; + int spu_end; + int end_found; + int bytes_passed; /* used to parse the spu */ } dxr3_spu_stream_state_t; typedef struct dxr3_spudec_s { @@ -81,14 +81,20 @@ typedef struct dxr3_spudec_s { char devname[128]; char devnum[3]; - int fd_spu; /* to access the dxr3 spu device */ + int fd_spu; /* to access the dxr3 spu device */ dxr3_spu_stream_state_t spu_stream_state[MAX_SPU_STREAMS]; - int menu; /* are we in a menu? */ + int menu; /* are we in a menu? */ pci_t pci; - uint32_t buttonN; /* currently highlighted button */ + uint32_t buttonN; /* currently highlighted button */ } dxr3_spudec_t; +/* helper functions */ +static int dxr3_present(xine_t *xine); +static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen); +static int dxr3_spudec_copy_nav_to_btn(dxr3_spudec_t *this, int32_t mode, em8300_button_t *btn); +static void dxr3_swab_clut(int* clut); + spu_decoder_t *init_spu_decoder_plugin(int iface_version, xine_t *xine) { @@ -175,8 +181,10 @@ static void dxr3_spudec_init(spu_decoder_t *this_gen, vo_instance_t *vo_out) #if LOG_SPU printf ("dxr3_decode_spu: init: SPU_FD = %i\n",this->fd_spu); #endif - for (i=0; i < MAX_SPU_STREAMS; i++) /* reset the spu filter for non-dvdnav */ + for (i=0; i < MAX_SPU_STREAMS; i++) { this->spu_stream_state[i].stream_filter = 1; + this->spu_stream_state[i].spu_length = 0; + } } static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf) @@ -184,6 +192,7 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf) dxr3_spudec_t *this = (dxr3_spudec_t *)this_gen; ssize_t written; uint32_t stream_id = buf->type & 0x1f; + dxr3_spu_stream_state_t *state = &this->spu_stream_state[stream_id]; if (buf->type == BUF_SPU_CLUT) { #if LOG_SPU @@ -223,10 +232,11 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf) /* menu ahead, remember pci for later evaluation */ xine_fast_memcpy(&this->pci, &pci, sizeof(pci_t)); - if ((dxr3_spudec_copy_nav_to_btn(&this->pci, this->buttonN, 0, &btn ) > 0)) + if ((dxr3_spudec_copy_nav_to_btn(this, 0, &btn ) > 0)) if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, &btn)) printf("dxr3_decode_spu: failed to set spu button (%s)\n", strerror(errno)); + this->menu = 1; } if ((pci.hli.hl_gi.hli_ss == 0) && (this->pci.hli.hl_gi.hli_ss == 1)) { @@ -240,52 +250,97 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf) 0x00, 0x01, 0x00, 0x20, 0x02, 0xFF }; /* leaving menu */ this->pci.hli.hl_gi.hli_ss = 0; + this->menu = 0; ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, NULL); write(this->fd_spu, empty_spu, sizeof(empty_spu)); } } return; } + + /* Look for the display duration entry in the spu packets. + * If the spu is a menu button highlight pane, this entry must not exist, + * because the spu is hidden, when the menu is left, not by timeout. + * Some broken dvds do not respect this and therefore confuse the spu + * decoding pipeline of the card. We fix this here. + */ + if (!state->spu_length) { + state->spu_length = buf->content[0] << 8 | buf->content[1]; + state->spu_ctrl = (buf->content[2] << 8 | buf->content[3]) + 2; + state->spu_end = 0; + state->end_found = 0; + state->bytes_passed = 0; + } + if (!state->end_found) { + int offset_in_buffer = state->spu_ctrl - state->bytes_passed; + if (offset_in_buffer >= 0 && offset_in_buffer < buf->size) + state->spu_end = buf->content[offset_in_buffer] << 8; + offset_in_buffer++; + if (offset_in_buffer >= 0 && offset_in_buffer < buf->size) { + state->spu_end |= buf->content[offset_in_buffer]; + state->end_found = 1; + } + } + if (state->end_found && this->menu) { + int offset_in_buffer = state->spu_end - state->bytes_passed; + if (offset_in_buffer >= 0 && offset_in_buffer < buf->size) + buf->content[offset_in_buffer] = 0x00; + offset_in_buffer++; + if (offset_in_buffer >= 0 && offset_in_buffer < buf->size) + buf->content[offset_in_buffer] = 0x00; + offset_in_buffer += 3; + if (offset_in_buffer >= 0 && offset_in_buffer < buf->size && + buf->content[offset_in_buffer] == 0x02) + buf->content[offset_in_buffer] = 0x00; + } + state->spu_length -= buf->size; + if (state->spu_length < 0) state->spu_length = 0; + state->bytes_passed += buf->size; + + /* filter unwanted streams */ if (buf->decoder_flags & BUF_FLAG_PREVIEW) { #if LOG_SPU printf("dxr3_decode_spu: Dropping SPU channel %d. Preview data\n", stream_id); #endif return; } - - if (this->spu_stream_state[stream_id].stream_filter == 0) { + if (state->stream_filter == 0) { #if LOG_SPU printf("dxr3_decode_spu: Dropping SPU channel %d. Stream filtered\n", stream_id); #endif return; } - if ((this->xine->spu_channel & 0x1f) != stream_id ) { + if ((this->xine->spu_channel & 0x1f) != stream_id) { #if LOG_SPU printf("dxr3_decode_spu: Dropping SPU channel %d. Not selected stream_id\n", stream_id); #endif return; } - if ((this->menu == 0) && (this->xine->spu_channel & 0x80)) { + if ((this->menu == 0) && (this->xine->spu_channel & 0x80)) { #if LOG_SPU printf("dxr3_decode_spu: Dropping SPU channel %d. Only allow forced display SPUs\n", stream_id); #endif return; } + /* write sync timestamp to the card */ if (buf->pts) { int64_t vpts; uint32_t vpts32; vpts = this->xine->metronom->got_spu_packet( this->xine->metronom, buf->pts); + /* estimate with current time, when metronom doesn't know */ + if (!vpts) vpts = this->xine->metronom->get_current_time(this->xine->metronom); #if LOG_PTS - printf ("dxr3_decode_spu: pts=%lld vpts=%lld\n", buf->pts, vpts); + printf("dxr3_decode_spu: pts = %lld vpts = %lld\n", buf->pts, vpts); #endif vpts32 = vpts; if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_SETPTS, &vpts32)) printf("dxr3_decode_spu: spu setpts failed (%s)\n", strerror(errno)); } + /* write spu data to the card */ #if LOG_SPU printf ("dxr3_decode_spu: write: SPU_FD = %i\n",this->fd_spu); #endif @@ -302,6 +357,11 @@ static void dxr3_spudec_decode_data(spu_decoder_t *this_gen, buf_element_t *buf) static void dxr3_spudec_reset(spu_decoder_t *this_gen) { + dxr3_spudec_t *this = (dxr3_spudec_t *)this_gen; + int i; + + for (i = 0; i < MAX_SPU_STREAMS; i++) + this->spu_stream_state[i].spu_length = 0; } static void dxr3_spudec_close(spu_decoder_t *this_gen) @@ -344,7 +404,7 @@ static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen) xine_spu_event_t *event = (xine_spu_event_t *)event_gen; #if LOG_SPU - printf ("dxr3_decode_spu: event caught: SPU_FD = %i\n",this->fd_spu); + printf("dxr3_decode_spu: event caught: SPU_FD = %i\n",this->fd_spu); #endif switch (event->event.type) { @@ -353,16 +413,16 @@ static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen) spu_button_t *but = event->data; em8300_button_t btn; #if LOG_BTN - printf ("dxr3_decode_spu: got SPU_BUTTON\n"); + printf("dxr3_decode_spu: got SPU_BUTTON\n"); #endif this->buttonN = but->buttonN; if ((but->show > 0) && (dxr3_spudec_copy_nav_to_btn( - &this->pci, this->buttonN, but->show - 1, &btn) > 0)) + this, but->show - 1, &btn) > 0)) if (ioctl(this->fd_spu, EM8300_IOCTL_SPU_BUTTON, &btn)) printf("dxr3_decode_spu: failed to set spu button (%s)\n", strerror(errno)); #if LOG_BTN - printf ("dxr3_decode_spu: buttonN = %u\n",but->buttonN); + printf("dxr3_decode_spu: buttonN = %u\n",but->buttonN); #endif } break; @@ -371,7 +431,7 @@ static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen) { spudec_clut_table_t *clut = event->data; #if LOG_SPU - printf ("dxr3_spu: got SPU_CLUT\n"); + printf("dxr3_decode_spu: got SPU_CLUT\n"); #endif #ifdef WORDS_BIGENDIAN dxr3_swab_clut(clut->clut); @@ -381,16 +441,25 @@ static void dxr3_spudec_event_listener(void *this_gen, xine_event_t *event_gen) strerror(errno)); } break; +#if 0 + /* FIXME: I think this event is not necessary any more + * We know from nav packet decoding, if we are in a menu. */ case XINE_EVENT_SPU_FORCEDISPLAY: { this->menu = (int)event->data; +#if LOG_SPU + printf("dxr3_decode_spu: got SPU_FORCEDISPLAY, force display is %s\n", + this->menu ? "on" : "off"); +#endif } break; +#endif } } -static int dxr3_spudec_copy_nav_to_btn(pci_t *nav_pci, int32_t button, int32_t mode, em8300_button_t *btn) +static int dxr3_spudec_copy_nav_to_btn(dxr3_spudec_t *this, int32_t mode, em8300_button_t *btn) { + int32_t button = this->buttonN; btni_t *button_ptr; /* FIXME: Need to communicate with dvdnav vm to get/set @@ -402,19 +471,19 @@ static int dxr3_spudec_copy_nav_to_btn(pci_t *nav_pci, int32_t button, int32_t m * } */ - if ((button <= 0) || (button > nav_pci->hli.hl_gi.btn_ns)) { + if ((button <= 0) || (button > this->pci.hli.hl_gi.btn_ns)) { printf("dxr3_decode_spu: Unable to select button number %i as it doesn't exist. Forcing button 1\n", button); button = 1; } - button_ptr = &nav_pci->hli.btnit[button-1]; + button_ptr = &this->pci.hli.btnit[button-1]; if(button_ptr->btn_coln != 0) { #if LOG_BTN fprintf(stderr, "dxr3_decode_spu: normal button clut, mode %d\n", mode); #endif - btn->color = (nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode] >> 16); - btn->contrast = (nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode]); + btn->color = (this->pci.hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode] >> 16); + btn->contrast = (this->pci.hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode]); /* FIXME: Only the first grouping of buttons are used at the moment */ btn->left = button_ptr->x_start; btn->top = button_ptr->y_start; -- cgit v1.2.3