/*****************************************************************************
* Preamble
*****************************************************************************/
+#include "defs.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 "config.h"
#include "common.h"
-#include "mtime.h"
#include "threads.h"
+#include "mtime.h"
+#include "plugins.h"
#include "intf_msg.h"
#include "debug.h" /* ASSERT */
#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) )
* 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 )