]> git.sesse.net Git - vlc/blobdiff - src/spu_decoder/spu_decoder.c
. les sous-titres sont centr�s
[vlc] / src / spu_decoder / spu_decoder.c
index add2858db48cd5f41798c452e78814ae3a3a6323..9c9d130e350a5be32b603ea952ecf9cfac44aa6f 100644 (file)
@@ -1,35 +1,55 @@
 /*****************************************************************************
  * 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"
 
 /*
@@ -40,6 +60,11 @@ static void     RunThread           ( spudec_thread_t *p_spudec );
 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
  *****************************************************************************/
@@ -77,6 +102,9 @@ spudec_thread_t * spudec_CreateThread( input_thread_t * p_input )
     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) )
@@ -141,7 +169,8 @@ static int InitThread( spudec_thread_t *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 */
@@ -171,19 +200,152 @@ static void RunThread( spudec_thread_t *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
@@ -233,7 +395,7 @@ static void ErrorThread( spudec_thread_t *p_spudec )
 /*****************************************************************************
  * 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 )