/*****************************************************************************
* spu_decoder.c : spu decoder thread
- * (c)2000 VideoLAN
+ *****************************************************************************
+ * Copyright (C) 2000 VideoLAN
+ *
+ * Authors:
+ *
+ * This program 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.
+ *
+ * This program 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.
*****************************************************************************/
/* repompé sur video_decoder.c
- * ?? passer en terminate/destroy avec les signaux supplémentaires */
+ * FIXME: passer en terminate/destroy avec les signaux supplémentaires ?? */
/*****************************************************************************
* Preamble
*****************************************************************************/
-//#include "vlc.h"
+#include "defs.h"
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/uio.h>
+#include <stdlib.h> /* malloc(), free() */
+#include <sys/types.h> /* on BSD, uio.h needs types.h */
+#include <sys/uio.h> /* for input.h */
+#include <unistd.h> /* getpid() */
#include "config.h"
#include "common.h"
+#include "threads.h"
#include "mtime.h"
-#include "vlc_thread.h"
+#include "plugins.h"
#include "intf_msg.h"
-#include "debug.h" /* ?? temporaire, requis par netlist.h */
+#include "debug.h" /* ASSERT */
#include "input.h"
#include "input_netlist.h"
#include "decoder_fifo.h"
+#include "video.h"
+#include "video_output.h"
+
#include "spu_decoder.h"
/*
static void ErrorThread ( spudec_thread_t *p_spudec );
static void EndThread ( spudec_thread_t *p_spudec );
+#define GetWord( i ) \
+ i = GetByte( &p_spudec->bit_stream ) << 8; \
+ i += GetByte( &p_spudec->bit_stream ); \
+ i_index += 2;
+
/*****************************************************************************
* spudec_CreateThread: create a spu decoder thread
*****************************************************************************/
p_spudec->bit_stream.fifo.buffer = 0;
p_spudec->bit_stream.fifo.i_available = 0;
+ /* Get the video output informations */
+ p_spudec->p_vout = p_input->p_vout;
+
/* Spawn the spu decoder thread */
if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder",
(vlc_thread_func_t)RunThread, (void *)p_spudec) )
}
p_spudec->bit_stream.p_ts = DECODER_FIFO_START( p_spudec->fifo )->p_first_ts;
- p_spudec->bit_stream.i_byte = p_spudec->bit_stream.p_ts->i_payload_start;
+ p_spudec->bit_stream.p_byte = p_spudec->bit_stream.p_ts->buffer + p_spudec->bit_stream.p_ts->i_payload_start;
+ p_spudec->bit_stream.p_end = p_spudec->bit_stream.p_ts->buffer + p_spudec->bit_stream.p_ts->i_payload_end;
vlc_mutex_unlock( &p_spudec->fifo.data_lock );
/* Mark thread as running and return */
* Main loop - it is not executed if an error occured during
* initialization
*/
- vlc_mutex_lock( &p_spudec->fifo.data_lock );
while( (!p_spudec->b_die) && (!p_spudec->b_error) )
{
- /* Trash all received PES packets */
+ int i_packet_size;
+ int i_rle_size;
+ int i_index;
+ int i_pes_size;
+ int i_pes_count;
+ boolean_t b_finished;
+ unsigned char * p_spu_data;
+ subpicture_t * p_spu = NULL;
+
while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
{
- input_NetlistFreePES( p_spudec->bit_stream.p_input, DECODER_FIFO_START(p_spudec->fifo) );
- DECODER_FIFO_INCSTART( p_spudec->fifo );
+ /* wait for the next SPU ID.
+ * FIXME: We trash 0xff bytes since they come from
+ * an incomplete previous packet */
+ do
+ {
+ i_packet_size = GetByte( &p_spudec->bit_stream );
+ }
+ while( i_packet_size == 0xff );
+
+ /* the total size - should equal the sum of the
+ * PES packet size that form the SPU packet */
+ i_packet_size = ( i_packet_size << 8 )
+ + GetByte( &p_spudec->bit_stream );
+ i_index = 2;
+
+ /* get the useful PES size (real size - 10) */
+ i_pes_size = DECODER_FIFO_START(p_spudec->fifo)->i_pes_size - 9;
+ i_pes_count = 1;
+
+ /* the RLE stuff size */
+ GetWord( i_rle_size );
+
+ /* if the values we got aren't too strange, decode the data */
+ if( i_rle_size < i_packet_size )
+ {
+ /* destroy the previous one */
+ if( p_spu ) vout_DestroySubPicture( p_spudec->p_vout, p_spu );
+
+ /* allocate the subpicture.
+ * FIXME: we should check if the allocation failed */
+ p_spu = vout_CreateSubPicture( p_spudec->p_vout,
+ DVD_SUBPICTURE, i_rle_size );
+ p_spu_data = p_spu->p_data;
+
+ /* getting the RLE part */
+ while( i_index++ < i_rle_size )
+ {
+ /* skip the leading byte of a PES */
+ if ( !((i_index + 3) % i_pes_size) )
+ {
+ i_pes_count++;
+ }
+ *p_spu_data++ = GetByte( &p_spudec->bit_stream );
+ }
+
+ /* getting the control part */
+ b_finished = 0;
+ do
+ {
+ unsigned char i_cmd;
+ unsigned int i_word;
+
+ /* the date */
+ GetWord( i_word );
+
+ /* next offset, no next offset if == i_index-5 */
+ GetWord( i_word );
+ b_finished = ( i_index - 5 >= i_word );
+
+ do
+ {
+ i_cmd = GetByte( &p_spudec->bit_stream );
+ i_index++;
+
+ switch( i_cmd )
+ {
+ case 0x00:
+ /* 00 (display now) */
+ break;
+ case 0x01:
+ /* 01 (start displaying) */
+ break;
+ case 0x02:
+ /* 02 (stop displaying) */
+ break;
+ case 0x03:
+ /* 03xxxx (palette) */
+ GetWord( i_word );
+ break;
+ case 0x04:
+ /* 04xxxx (alpha channel) */
+ GetWord( i_word );
+ break;
+ case 0x05:
+ /* 05xxxyyyxxxyyy (coordinates) */
+ i_word = GetByte( &p_spudec->bit_stream );
+ p_spu->type.spu.i_x1 = (i_word << 4) | GetBits( &p_spudec->bit_stream, 4 );
+ i_word = GetBits( &p_spudec->bit_stream, 4 );
+ p_spu->type.spu.i_x2 = (i_word << 8) | GetByte( &p_spudec->bit_stream );
+ i_word = GetByte( &p_spudec->bit_stream );
+ p_spu->type.spu.i_y1 = (i_word << 4) | GetBits( &p_spudec->bit_stream, 4 );
+ i_word = GetBits( &p_spudec->bit_stream, 4 );
+ p_spu->type.spu.i_y2 = (i_word << 8) | GetByte( &p_spudec->bit_stream );
+ i_index += 6;
+ break;
+ case 0x06:
+ /* 06xxxxyyyy (byte offsets) */
+ GetWord( i_word );
+ p_spu->type.spu.i_offset[0] = i_word - 4;
+ GetWord( i_word );
+ p_spu->type.spu.i_offset[1] = i_word - 4;
+ break;
+ case 0xff:
+ /* ff (end) */
+ break;
+ default:
+ /* ?? (unknown command) */
+ break;
+ }
+ }
+ while( i_cmd != 0xff );
+ }
+ while( !b_finished );
+
+ /* SPU is finished - we can display it */
+ vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
+ }
+ else
+ {
+ /* Unexpected PES packet - trash it */
+ vlc_mutex_lock( &p_spudec->fifo.data_lock );
+ input_NetlistFreePES( p_spudec->bit_stream.p_input,
+ DECODER_FIFO_START(p_spudec->fifo) );
+ DECODER_FIFO_INCSTART( p_spudec->fifo );
+ vlc_mutex_unlock( &p_spudec->fifo.data_lock );
+ }
+
}
/* Waiting for the input thread to put new PES packets in the fifo */
vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
+
+ if( p_spu ) vout_DestroySubPicture( p_spudec->p_vout, p_spu );
}
- vlc_mutex_unlock( &p_spudec->fifo.data_lock );
/*
* Error loop
/*****************************************************************************
* EndThread: thread destruction
*****************************************************************************
- * This function is called when the thread ends after a sucessfull
+ * This function is called when the thread ends after a sucessful
* initialization.
*****************************************************************************/
static void EndThread( spudec_thread_t *p_spudec )