]> git.sesse.net Git - vlc/commitdiff
* ./modules/access/dvdplay/access.c: activated button highlighting.
authorSam Hocevar <sam@videolan.org>
Wed, 6 Nov 2002 18:07:57 +0000 (18:07 +0000)
committerSam Hocevar <sam@videolan.org>
Wed, 6 Nov 2002 18:07:57 +0000 (18:07 +0000)
  * ./modules/codec/spudec/parse.c: implemented subtitle cropping and
    temporarily disabled subtitle cropping.
  * ./modules/codec/spudec/render.c: split RenderSPU into chroma-specific
    functions.

include/video.h
include/video_output.h
modules/access/dvdplay/access.c
modules/access/dvdplay/dvd.h
modules/access/dvdplay/intf.c
modules/codec/spudec/parse.c
modules/codec/spudec/render.c
modules/codec/spudec/spudec.c
modules/codec/spudec/spudec.h
src/video_output/vout_subpictures.c

index 2601f8e36723bb7918f394a1014c5ef0927c59c2..5d2fd3e463a4cdfd2ba85a9b89c069c9c542e2e6 100644 (file)
@@ -4,7 +4,7 @@
  * includes all common video types and constants.
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: video.h,v 1.56 2002/07/23 00:39:16 sam Exp $
+ * $Id: video.h,v 1.57 2002/11/06 18:07:57 sam Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *
@@ -166,7 +166,6 @@ struct subpicture_t
     /* Type and flags - should NOT be modified except by the vout thread */
     int             i_type;                                          /* type */
     int             i_status;                                       /* flags */
-    int             i_size;                                     /* data size */
     subpicture_t *  p_next;                 /* next subtitle to be displayed */
 
     /* Date properties */
@@ -199,13 +198,13 @@ struct subpicture_t
     } type;
 #endif
 
-    /* The subpicture rendering routine */
-    void ( *pf_render ) ( vout_thread_t *, picture_t *, const subpicture_t * );
+    /* The subpicture rendering and destruction routines */
+    void ( *pf_render )  ( vout_thread_t *, picture_t *, const subpicture_t * );
+    void ( *pf_destroy ) ( subpicture_t * );
 
     /* Private data - the subtitle plugin might want to put stuff here to
      * keep track of the subpicture */
     subpicture_sys_t *p_sys;                              /* subpicture data */
-    void             *p_sys_orig;                 /* pointer before memalign */
 };
 
 /* Subpicture type */
@@ -216,5 +215,4 @@ struct subpicture_t
 #define FREE_SUBPICTURE        0                   /* free and not allocated */
 #define RESERVED_SUBPICTURE    1                   /* allocated and reserved */
 #define READY_SUBPICTURE       2                        /* ready for display */
-#define DESTROYED_SUBPICTURE   3           /* allocated but not used anymore */
 
index c6ae12e4312c30ba3dbda31a6e2b5494a0783705..22e10e7a0707c39c669b4f58bacdec44e15ab820 100644 (file)
@@ -5,7 +5,7 @@
  * thread, and destroy a previously opened video output thread.
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: video_output.h,v 1.84 2002/10/17 16:03:18 sam Exp $
+ * $Id: video_output.h,v 1.85 2002/11/06 18:07:57 sam Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@via.ecp.fr>
@@ -158,7 +158,7 @@ VLC_EXPORT( void,            vout_PlacePicture,   ( vout_thread_t *, int, int, i
 picture_t *     vout_RenderPicture  ( vout_thread_t *, picture_t *,
                                                        subpicture_t * );
 
-VLC_EXPORT( subpicture_t *,  vout_CreateSubPicture,   ( vout_thread_t *, int, int ) );
+VLC_EXPORT( subpicture_t *,  vout_CreateSubPicture,   ( vout_thread_t *, int ) );
 VLC_EXPORT( void,            vout_DestroySubPicture,  ( vout_thread_t *, subpicture_t * ) );
 VLC_EXPORT( void,            vout_DisplaySubPicture,  ( vout_thread_t *, subpicture_t * ) );
 
index 07e6a1bbf12fb0df67ec3e0b8ef5d1dad87105d6..325cfd1760df349103614143c8e3a04f7ca02446 100644 (file)
@@ -2,7 +2,7 @@
  * access.c: access capabilities for dvdplay plugin.
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: access.c,v 1.4 2002/10/26 15:24:19 gbazin Exp $
+ * $Id: access.c,v 1.5 2002/11/06 18:07:57 sam Exp $
  *
  * Author: Stéphane Borel <stef@via.ecp.fr>
  *
@@ -87,7 +87,7 @@ int E_(OpenDVD) ( vlc_object_t *p_this )
     p_dvd = malloc( sizeof(dvd_data_t) );
     if( p_dvd == NULL )
     {
-        msg_Err( p_input, "dvdplay error: out of memory" );
+        msg_Err( p_input, "out of memory" );
         return -1;
     }
 
@@ -114,7 +114,7 @@ int E_(OpenDVD) ( vlc_object_t *p_this )
 
     if( p_dvd->vmg == NULL )
     {
-        msg_Err( p_input, "dvdplay error: can't open source" );
+        msg_Err( p_input, "cannot open %s", psz_source );
         free( p_dvd );
         return -1;
     }
@@ -184,6 +184,18 @@ int E_(OpenDVD) ( vlc_object_t *p_this )
 
     p_input->psz_demux = "dvdplay";
 
+    /* FIXME: we might lose variables here */
+    var_Create( p_input, "x-start", VLC_VAR_INTEGER );
+    var_Create( p_input, "y-start", VLC_VAR_INTEGER );
+    var_Create( p_input, "x-end", VLC_VAR_INTEGER );
+    var_Create( p_input, "y-end", VLC_VAR_INTEGER );
+
+    var_Create( p_input, "color", VLC_VAR_ADDRESS );
+    var_Create( p_input, "contrast", VLC_VAR_ADDRESS );
+
+    var_Create( p_input, "highlight", VLC_VAR_BOOL );
+    var_Create( p_input, "highlight-mutex", VLC_VAR_MUTEX );
+
     return 0;
 }
 
@@ -195,6 +207,17 @@ void E_(CloseDVD) ( vlc_object_t *p_this )
     input_thread_t * p_input = (input_thread_t *)p_this;
     dvd_data_t *     p_dvd = (dvd_data_t *)p_input->p_access_data;
 
+    var_Destroy( p_input, "highlight-mutex" );
+    var_Destroy( p_input, "highlight" );
+
+    var_Destroy( p_input, "x-start" );
+    var_Destroy( p_input, "x-end" );
+    var_Destroy( p_input, "y-start" );
+    var_Destroy( p_input, "y-end" );
+
+    var_Destroy( p_input, "color" );
+    var_Destroy( p_input, "contrast" );
+
     /* close libdvdplay */
     dvdplay_close( p_dvd->vmg );
 
@@ -350,6 +373,7 @@ static void pf_vmg_callback( void* p_args, dvdplay_event_t event )
 {
     input_thread_t *    p_input;
     dvd_data_t *        p_dvd;
+    vlc_value_t         val;
     int                 i;
 
     p_input = (input_thread_t*)p_args;
@@ -407,11 +431,38 @@ static void pf_vmg_callback( void* p_args, dvdplay_event_t event )
     case COMPLETE_VIDEO:
         break;
     case NEW_HIGHLIGHT:
-        
+        if( var_Get( p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
+        {
+            vlc_mutex_t *p_mutex = val.p_address;
+            vlc_mutex_lock( p_mutex );
+
+            /* Retrieve the highlight from dvdplay */
+            dvdplay_highlight( p_dvd->vmg, &p_dvd->hli );
+
+            /* Fill our internal variables with this data */
+            val.i_int = p_dvd->hli.i_x_start;
+            var_Set( p_input, "x-start", val );
+            val.i_int = p_dvd->hli.i_y_start;
+            var_Set( p_input, "y-start", val );
+            val.i_int = p_dvd->hli.i_x_end;
+            var_Set( p_input, "x-end", val );
+            val.i_int = p_dvd->hli.i_y_end;
+            var_Set( p_input, "y-end", val );
+
+            val.p_address = (void *)p_dvd->hli.pi_color;
+            var_Set( p_input, "color", val );
+            val.p_address = (void *)p_dvd->hli.pi_contrast;
+            var_Set( p_input, "contrast", val );
+
+            /* Tell the SPU decoder that there's a new highlight */
+            val.b_bool = VLC_TRUE;
+            var_Set( p_input, "highlight", val );
+
+            vlc_mutex_unlock( p_mutex );
+        }
         break;
     default:
-        msg_Err( p_input, "unknown event from libdvdplay (%d)",
-                      event );
+        msg_Err( p_input, "unknown event from libdvdplay (%d)", event );
     }
 
     return;
@@ -494,3 +545,4 @@ static int dvdNewPGC( input_thread_t * p_input )
 
     return 0;
 }
+
index b1418a67f125c0922f3bad7ddd7563f737a9a698..4edbc2ad3ae20f171f75eaf9caf29fe7e41b9a7a 100644 (file)
@@ -2,7 +2,7 @@
  * dvd.h: structure of the dvdplay plugin
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: dvd.h,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: dvd.h,v 1.2 2002/11/06 18:07:57 sam Exp $
  *
  * Author: Stéphane Borel <stef@via.ecp.fr>
  *
@@ -56,6 +56,7 @@ typedef struct
 
     dvdplay_event_t         event;
     dvdplay_ctrl_t          control;   
+    dvdplay_highlight_t     hli;
 
 } dvd_data_t;
 
index 38f0a5f75e3cef6b33992f8c1e0de928a4805f12..4a64683172008f2bcea74e51176624cb009c1670 100644 (file)
@@ -2,7 +2,7 @@
  * intf.c: interface for DVD video manager
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: intf.c,v 1.2 2002/10/17 16:03:18 sam Exp $
+ * $Id: intf.c,v 1.3 2002/11/06 18:07:57 sam Exp $
  *
  * Authors: Stéphane Borel <stef@via.ecp.fr>
  *
@@ -33,6 +33,7 @@
 
 #include "stream_control.h"
 #include "input_ext-intf.h"
+#include "input_ext-dec.h"
 
 #include "dvd.h"
 
@@ -190,10 +191,6 @@ static void RunIntf( intf_thread_t *p_intf )
                 p_intf->p_sys->b_move = VLC_FALSE;
             }
 
-            msg_Dbg( p_intf, "send button coordinates: %dx%d",
-                             p_intf->p_sys->control.mouse.i_x,
-                             p_intf->p_sys->control.mouse.i_y );
-
             /* we can safely interact with libdvdplay
              * with the stream lock */
             vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
@@ -343,7 +340,6 @@ int dvdIntfStillTime( intf_thread_t *p_intf, int i_sec )
 #endif
     vlc_mutex_unlock( &p_intf->change_lock );
 
-    return 0;
+    return VLC_SUCCESS;
 }
 
-
index 742058da61ae482f5af8c83f03ae77b11eebb7be..02e2cd48da9a6b62c7aa0a6c4dcc978c5164f98d 100644 (file)
@@ -2,7 +2,7 @@
  * parse.c: SPU parser
  *****************************************************************************
  * Copyright (C) 2000-2001 VideoLAN
- * $Id: parse.c,v 1.3 2002/10/31 09:40:26 gbazin Exp $
+ * $Id: parse.c,v 1.4 2002/11/06 18:07:57 sam Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
 /*****************************************************************************
  * Local prototypes.
  *****************************************************************************/
-static int  ParseControlSequences( spudec_thread_t *, subpicture_t * );
-static int  ParseRLE             ( spudec_thread_t *, subpicture_t *, u8 * );
+static int  ParseControlSeq  ( spudec_thread_t *, subpicture_t * );
+static int  ParseRLE         ( spudec_thread_t *, subpicture_t *, uint8_t * );
+
+static void DestroySPU       ( subpicture_t * );
+
+static void UpdateSPU        ( subpicture_t *, vlc_object_t * );
+static int  CropCallback     ( vlc_object_t *, char const *,
+                               vlc_value_t, vlc_value_t, void * );
 
 /*****************************************************************************
  * AddNibble: read a nibble from a source packet and add it to our integer.
  *****************************************************************************/
 static inline unsigned int AddNibble( unsigned int i_code,
-                                      u8 *p_src, int *pi_index )
+                                      uint8_t *p_src, int *pi_index )
 {
     if( *pi_index & 0x1 )
     {
@@ -101,7 +107,7 @@ int E_(SyncPacket)( spudec_thread_t *p_spudec )
 void E_(ParsePacket)( spudec_thread_t *p_spudec )
 {
     subpicture_t * p_spu;
-    u8           * p_src;
+    uint8_t      * p_src;
     unsigned int   i_offset;
     mtime_t        i_pts;
 
@@ -117,22 +123,32 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec )
     }
 
     /* Allocate the subpicture internal data. */
-    p_spu = vout_CreateSubPicture( p_spudec->p_vout, MEMORY_SUBPICTURE,
-                                   sizeof( subpicture_sys_t )
-                                    + p_spudec->i_rle_size * 4 );
+    p_spu = vout_CreateSubPicture( p_spudec->p_vout, MEMORY_SUBPICTURE );
+
+    if( p_spu == NULL )
+    {
+        return;
+    }
+
     /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
      * expand the RLE stuff so that we won't need to read nibbles later
      * on. This will speed things up a lot. Plus, we'll only need to do
      * this stupid interlacing stuff once. */
+    p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
+                            + p_spudec->i_rle_size * 4 );
 
-    if( p_spu == NULL )
+    if( p_spu->p_sys == NULL )
     {
+        vout_DestroySubPicture( p_spudec->p_vout, p_spu );
         return;
     }
 
     /* Fill the p_spu structure */
+    vlc_mutex_init( p_spudec->p_fifo, &p_spu->p_sys->lock );
+
     p_spu->pf_render = E_(RenderSPU);
-    p_spu->p_sys->p_data = (u8*)p_spu->p_sys + sizeof( subpicture_sys_t );
+    p_spu->pf_destroy = DestroySPU;
+    p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
     p_spu->p_sys->b_palette = VLC_FALSE;
 
     p_spu->p_sys->pi_alpha[0] = 0x00;
@@ -140,9 +156,30 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec )
     p_spu->p_sys->pi_alpha[2] = 0x0f;
     p_spu->p_sys->pi_alpha[3] = 0x0f;
 
+    p_spu->p_sys->b_crop = VLC_FALSE;
+
     /* Get display time now. If we do it later, we may miss the PTS. */
     p_spu->p_sys->i_pts = i_pts;
 
+    /* Attach to our input thread */
+    p_spu->p_sys->p_input = vlc_object_find( p_spudec->p_fifo,
+                                             VLC_OBJECT_INPUT, FIND_PARENT );
+    if( p_spu->p_sys->p_input )
+    {
+        vlc_value_t val;
+
+        if( !var_Get( p_spu->p_sys->p_input, "highlight-mutex", &val ) )
+        {
+            vlc_mutex_t *p_mutex = val.p_address;
+
+            vlc_mutex_lock( p_mutex );
+            UpdateSPU( p_spu, VLC_OBJECT(p_spu->p_sys->p_input) );
+            var_AddCallback( p_spu->p_sys->p_input,
+                             "highlight", CropCallback, p_spu );
+            vlc_mutex_unlock( p_mutex );
+        }
+    }
+
     /* Allocate the temporary buffer we will parse */
     p_src = malloc( p_spudec->i_rle_size );
 
@@ -176,7 +213,7 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec )
 #endif
 
     /* Getting the control part */
-    if( ParseControlSequences( p_spudec, p_spu ) )
+    if( ParseControlSeq( p_spudec, p_spu ) )
     {
         /* There was a parse error, delete the subpicture */
         free( p_src );
@@ -203,18 +240,20 @@ void E_(ParsePacket)( spudec_thread_t *p_spudec )
     /* SPU is finished - we can ask the video output to display it */
     vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
 
+    /* TODO: do stuff! */
+
     /* Clean up */
     free( p_src );
 }
 
 /*****************************************************************************
- * ParseControlSequences: parse all SPU control sequences
+ * ParseControlSeq: parse all SPU control sequences
  *****************************************************************************
  * This is the most important part in SPU decoding. We get dates, palette
  * information, coordinates, and so on. For more information on the
  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
  *****************************************************************************/
-static int ParseControlSequences( spudec_thread_t *p_spudec,
+static int ParseControlSeq( spudec_thread_t *p_spudec,
                                   subpicture_t * p_spu )
 {
     /* Our current index in the SPU packet */
@@ -224,7 +263,7 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
     int i_next_seq = 0, i_cur_seq = 0;
 
     /* Command and date */
-    u8 i_command = SPU_CMD_END;
+    uint8_t i_command = SPU_CMD_END;
     mtime_t date = 0;
 
     int i, pi_alpha[4];
@@ -275,12 +314,12 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
             if( p_spudec->p_fifo->p_demux_data
                  && *(int*)p_spudec->p_fifo->p_demux_data == 0xBeeF )
             {
-                u32 i_color;
+                uint32_t i_color;
 
                 p_spu->p_sys->b_palette = VLC_TRUE;
                 for( i = 0; i < 4 ; i++ )
                 {
-                    i_color = ((u32*)((char*)p_spudec->p_fifo->
+                    i_color = ((uint32_t*)((char*)p_spudec->p_fifo->
                                 p_demux_data + sizeof(int)))[
                                   GetBits(&p_spudec->bit_stream, 4) ];
 
@@ -431,7 +470,7 @@ static int ParseControlSequences( spudec_thread_t *p_spudec,
  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
  *****************************************************************************/
 static int ParseRLE( spudec_thread_t *p_spudec,
-                     subpicture_t * p_spu, u8 * p_src )
+                     subpicture_t * p_spu, uint8_t * p_src )
 {
     unsigned int i_code;
 
@@ -439,17 +478,19 @@ static int ParseRLE( spudec_thread_t *p_spudec,
     unsigned int i_height = p_spu->i_height;
     unsigned int i_x, i_y;
 
-    u16 *p_dest = (u16 *)p_spu->p_sys->p_data;
+    uint16_t *p_dest = (uint16_t *)p_spu->p_sys->p_data;
 
     /* The subtitles are interlaced, we need two offsets */
     unsigned int  i_id = 0;                   /* Start on the even SPU layer */
     unsigned int  pi_table[ 2 ];
     unsigned int *pi_offset;
 
+#if 0 /* cropping */
     vlc_bool_t b_empty_top = VLC_TRUE,
                b_empty_bottom = VLC_FALSE;
     unsigned int i_skipped_top = 0,
                  i_skipped_bottom = 0;
+#endif
 
     /* Colormap statistics */
     int i_border = -1;
@@ -513,6 +554,7 @@ static int ParseRLE( spudec_thread_t *p_spudec,
                 stats[i_border] += i_code >> 2;
             }
 
+#if 0 /* cropping */
             if( (i_code >> 2) == i_width
                  && p_spu->p_sys->pi_alpha[ i_code & 0x3 ] == 0x00 )
             {
@@ -541,6 +583,9 @@ static int ParseRLE( spudec_thread_t *p_spudec,
                 b_empty_bottom = VLC_FALSE;
                 i_skipped_bottom = 0;
             }
+#else
+            *p_dest++ = i_code;
+#endif
         }
 
         /* Check that we didn't go too far */
@@ -581,6 +626,7 @@ static int ParseRLE( spudec_thread_t *p_spudec,
     msg_Dbg( p_spudec->p_fifo, "valid subtitle, size: %ix%i, position: %i,%i",
              p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
 
+#if 0 /* cropping */
     /* Crop if necessary */
     if( i_skipped_top || i_skipped_bottom )
     {
@@ -590,6 +636,7 @@ static int ParseRLE( spudec_thread_t *p_spudec,
         msg_Dbg( p_spudec->p_fifo, "cropped to: %ix%i, position: %i,%i",
                  p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
     }
+#endif
 
     /* Handle color if no palette was found */
     if( !p_spu->p_sys->b_palette )
@@ -651,3 +698,82 @@ static int ParseRLE( spudec_thread_t *p_spudec,
     return VLC_SUCCESS;
 }
 
+/*****************************************************************************
+ * DestroySPU: subpicture destructor
+ *****************************************************************************/
+static void DestroySPU( subpicture_t *p_spu )
+{
+    if( p_spu->p_sys->p_input )
+    {
+        /* Detach from our input thread */
+        var_DelCallback( p_spu->p_sys->p_input, "highlight",
+                         CropCallback, p_spu );
+        vlc_object_release( p_spu->p_sys->p_input );
+    }
+
+    vlc_mutex_destroy( &p_spu->p_sys->lock );
+    free( p_spu->p_sys );
+}
+
+/*****************************************************************************
+ * UpdateSPU: update subpicture settings
+ *****************************************************************************
+ * This function is called from CropCallback and at initialization time, to
+ * retrieve crop information from the input.
+ *****************************************************************************/
+static void UpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
+{
+    vlc_value_t val;
+
+    if( var_Get( p_object, "highlight", &val ) )
+    {
+        return;
+    }
+
+    p_spu->p_sys->b_crop = val.b_bool;
+    if( !p_spu->p_sys->b_crop )
+    {
+        return;
+    }
+
+    var_Get( p_object, "x-start", &val );
+    p_spu->p_sys->i_x_start = val.i_int;
+    var_Get( p_object, "y-start", &val );
+    p_spu->p_sys->i_y_start = val.i_int;
+    var_Get( p_object, "x-end", &val );
+    p_spu->p_sys->i_x_end = val.i_int;
+    var_Get( p_object, "y-end", &val );
+    p_spu->p_sys->i_y_end = val.i_int;
+
+#if 0
+    if( var_Get( p_object, "color", &val ) == VLC_SUCCESS )
+    {
+        p_spu->p_sys->pi_color[0] = ((uint8_t *)val.p_address)[0];
+        p_spu->p_sys->pi_color[1] = ((uint8_t *)val.p_address)[1];
+        p_spu->p_sys->pi_color[2] = ((uint8_t *)val.p_address)[2];
+        p_spu->p_sys->pi_color[3] = ((uint8_t *)val.p_address)[3];
+    }
+#endif
+
+    if( var_Get( p_object, "contrast", &val ) == VLC_SUCCESS )
+    {
+        p_spu->p_sys->pi_alpha[0] = ((uint8_t *)val.p_address)[0];
+        p_spu->p_sys->pi_alpha[1] = ((uint8_t *)val.p_address)[1];
+        p_spu->p_sys->pi_alpha[2] = ((uint8_t *)val.p_address)[2];
+        p_spu->p_sys->pi_alpha[3] = ((uint8_t *)val.p_address)[3];
+    }
+}
+
+/*****************************************************************************
+ * CropCallback: called when the highlight properties are changed
+ *****************************************************************************
+ * This callback is called from the input thread when we need cropping
+ *****************************************************************************/
+static int CropCallback( vlc_object_t *p_object, char const *psz_var,
+                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    UpdateSPU( (subpicture_t *)p_data, p_object );
+
+    return VLC_SUCCESS;
+}
+
index ba171e1956b66816c90667859ab480f837111b8f..c913280b71b5f7c55352d69130fd0ffd615c2b83 100644 (file)
@@ -2,7 +2,7 @@
  * render.c : SPU renderer
  *****************************************************************************
  * Copyright (C) 2000-2001 VideoLAN
- * $Id: render.c,v 1.2 2002/09/30 18:30:26 titer Exp $
+ * $Id: render.c,v 1.3 2002/11/06 18:07:57 sam Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *          Rudolf Cornelissen <rag.cornelissen@inter.nl.net>
 
 #include "spudec.h"
 
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static void RenderI420( vout_thread_t *, picture_t *, const subpicture_t *,
+                        vlc_bool_t );
+static void RenderRV16( vout_thread_t *, picture_t *, const subpicture_t *,
+                        vlc_bool_t );
+static void RenderRV32( vout_thread_t *, picture_t *, const subpicture_t *,
+                        vlc_bool_t );
+static void RenderYUY2( vout_thread_t *, picture_t *, const subpicture_t *,
+                        vlc_bool_t );
+
 /*****************************************************************************
  * RenderSPU: draw an SPU on a picture
  *****************************************************************************
  *****************************************************************************/
 void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
                     const subpicture_t *p_spu )
+{
+    switch( p_vout->output.i_chroma )
+    {
+        /* I420 target, no scaling */
+        case VLC_FOURCC('I','4','2','0'):
+        case VLC_FOURCC('I','Y','U','V'):
+        case VLC_FOURCC('Y','V','1','2'):
+            RenderI420( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
+            break;
+
+        /* RV16 target, scaling */
+        case VLC_FOURCC('R','V','1','6'):
+            RenderRV16( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
+            break;
+
+        /* RV32 target, scaling */
+        case VLC_FOURCC('R','V','2','4'):
+        case VLC_FOURCC('R','V','3','2'):
+            RenderRV32( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
+            break;
+
+        /* NVidia overlay, no scaling */
+        case VLC_FOURCC('Y','U','Y','2'):
+            RenderYUY2( p_vout, p_pic, p_spu, p_spu->p_sys->b_crop );
+            break;
+
+        default:
+            msg_Err( p_vout, "unknown chroma, can't render SPU" );
+            break;
+    }
+}
+
+/* Following functions are local */
+
+static void RenderI420( vout_thread_t *p_vout, picture_t *p_pic,
+                        const subpicture_t *p_spu, vlc_bool_t b_crop )
 {
     /* Common variables */
-    u16  p_clut16[4];
-    u32  p_clut32[4];
     u8  *p_dest;
     u8  *p_destptr;
     u16 *p_source = (u16 *)p_spu->p_sys->p_data;
@@ -64,33 +110,37 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
     int i_x, i_y;
     int i_len, i_color;
     u16 i_colprecomp, i_destalpha;
-    u8  i_cnt;
-
-    /* RGB-specific */
-    int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
 
-    switch( p_vout->output.i_chroma )
-    {
-    /* I420 target, no scaling */
-    case VLC_FOURCC('I','4','2','0'):
-    case VLC_FOURCC('I','Y','U','V'):
-    case VLC_FOURCC('Y','V','1','2'):
+    /* Crop-specific */
+    int i_x_start, i_y_start, i_x_end, i_y_end;
 
     p_dest = p_pic->Y_PIXELS + p_spu->i_x + p_spu->i_width
               + p_pic->Y_PITCH * ( p_spu->i_y + p_spu->i_height );
 
+    i_x_start = p_spu->i_width - p_spu->p_sys->i_x_end;
+    i_y_start = p_pic->Y_PITCH * (p_spu->i_height - p_spu->p_sys->i_y_end );
+    i_x_end = p_spu->i_width - p_spu->p_sys->i_x_start;
+    i_y_end = p_pic->Y_PITCH * (p_spu->i_height - p_spu->p_sys->i_y_start );
+
     /* Draw until we reach the bottom of the subtitle */
     for( i_y = p_spu->i_height * p_pic->Y_PITCH ;
          i_y ;
          i_y -= p_pic->Y_PITCH )
     {
         /* Draw until we reach the end of the line */
-        for( i_x = p_spu->i_width ; i_x ; )
+        for( i_x = p_spu->i_width ; i_x ; i_x -= i_len )
         {
             /* Get the RLE part, then draw the line */
             i_color = *p_source & 0x3;
             i_len = *p_source++ >> 2;
 
+            if( b_crop
+                 && ( i_x < i_x_start || i_x > i_x_end
+                       || i_y < i_y_start || i_y > i_y_end ) )
+            {
+                continue;
+            }
+
             switch( p_spu->p_sys->pi_alpha[i_color] )
             {
                 case 0x00:
@@ -117,16 +167,27 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
                                         (u16)*p_destptr * i_destalpha ) >> 4;
                     }
                     break;
-
             }
-            i_x -= i_len;
         }
     }
+}
 
-    break;
+static void RenderRV16( vout_thread_t *p_vout, picture_t *p_pic,
+                        const subpicture_t *p_spu, vlc_bool_t b_crop )
+{
+    /* Common variables */
+    u16  p_clut16[4];
+    u8  *p_dest;
+    u16 *p_source = (u16 *)p_spu->p_sys->p_data;
 
-    /* RV16 target, scaling */
-    case VLC_FOURCC('R','V','1','6'):
+    int i_x, i_y;
+    int i_len, i_color;
+
+    /* RGB-specific */
+    int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
+
+    /* Crop-specific */
+    int i_x_start, i_y_start, i_x_end, i_y_end;
 
     /* XXX: this is a COMPLETE HACK, memcpy is unable to do u16s anyway */
     /* FIXME: get this from the DVD */
@@ -147,6 +208,11 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
               + ( (p_spu->i_x * i_xscale) >> 6 ) * 2
               + ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
 
+    i_x_start = i_width - i_xscale * p_spu->p_sys->i_x_end;
+    i_y_start = i_yscale * p_spu->p_sys->i_y_start;
+    i_x_end = i_width - i_xscale * p_spu->p_sys->i_x_start;
+    i_y_end = i_yscale * p_spu->p_sys->i_y_end;
+
     /* Draw until we reach the bottom of the subtitle */
     for( i_y = 0 ; i_y < i_height ; )
     {
@@ -160,35 +226,37 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
             i_yreal = p_pic->p->i_pitch * i_ytmp;
 
             /* Draw until we reach the end of the line */
-            for( i_x = i_width ; i_x ; )
+            for( i_x = i_width ; i_x ; i_x -= i_len )
             {
                 /* Get the RLE part, then draw the line */
                 i_color = *p_source & 0x3;
+                i_len = i_xscale * ( *p_source++ >> 2 );
+
+                if( b_crop
+                     && ( i_x < i_x_start || i_x > i_x_end
+                           || i_y < i_y_start || i_y > i_y_end ) )
+                {
+                    continue;
+                }
 
                 switch( p_spu->p_sys->pi_alpha[ i_color ] )
                 {
                 case 0x00:
-                    i_x -= i_xscale * ( *p_source++ >> 2 );
                     break;
 
                 case 0x0f:
-                    i_len = i_xscale * ( *p_source++ >> 2 );
                     memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
                             p_clut16[ i_color ],
                             2 * ( ( i_len >> 6 ) + 1 ) );
-                    i_x -= i_len;
                     break;
 
                 default:
                     /* FIXME: we should do transparency */
-                    i_len = i_xscale * ( *p_source++ >> 2 );
                     memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
                             p_clut16[ i_color ],
                             2 * ( ( i_len >> 6 ) + 1 ) );
-                    i_x -= i_len;
                     break;
                 }
-
             }
         }
         else
@@ -197,19 +265,25 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
             i_ynext = p_pic->p->i_pitch * i_y >> 6;
 
             /* Draw until we reach the end of the line */
-            for( i_x = i_width ; i_x ; )
+            for( i_x = i_width ; i_x ; i_x -= i_len )
             {
                 /* Get the RLE part, then draw as many lines as needed */
                 i_color = *p_source & 0x3;
+                i_len = i_xscale * ( *p_source++ >> 2 );
+
+                if( b_crop
+                     && ( i_x < i_x_start || i_x > i_x_end
+                           || i_y < i_y_start || i_y > i_y_end ) )
+                {
+                    continue;
+                }
 
                 switch( p_spu->p_sys->pi_alpha[ i_color ] )
                 {
                 case 0x00:
-                    i_x -= i_xscale * ( *p_source++ >> 2 );
                     break;
 
                 case 0x0f:
-                    i_len = i_xscale * ( *p_source++ >> 2 );
                     for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
                          i_ytmp += p_pic->p->i_pitch )
                     {
@@ -217,12 +291,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
                                 p_clut16[ i_color ],
                                 2 * ( ( i_len >> 6 ) + 1 ) );
                     }
-                    i_x -= i_len;
                     break;
 
                 default:
                     /* FIXME: we should do transparency */
-                    i_len = i_xscale * ( *p_source++ >> 2 );
                     for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
                          i_ytmp += p_pic->p->i_pitch )
                     {
@@ -230,18 +302,29 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
                                 p_clut16[ i_color ],
                                 2 * ( ( i_len >> 6 ) + 1 ) );
                     }
-                    i_x -= i_len;
                     break;
                 }
             }
         }
     }
+}
 
-    break;
+static void RenderRV32( vout_thread_t *p_vout, picture_t *p_pic,
+                        const subpicture_t *p_spu, vlc_bool_t b_crop )
+{
+    /* Common variables */
+    u32  p_clut32[4];
+    u8  *p_dest;
+    u16 *p_source = (u16 *)p_spu->p_sys->p_data;
 
-    /* RV32 target, scaling */
-    case VLC_FOURCC('R','V','2','4'):
-    case VLC_FOURCC('R','V','3','2'):
+    int i_x, i_y;
+    int i_len, i_color;
+
+    /* RGB-specific */
+    int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
+
+    /* Crop-specific */
+    int i_x_start, i_y_start, i_x_end, i_y_end;
 
     /* XXX: this is a COMPLETE HACK, memcpy is unable to do u32s anyway */
     /* FIXME: get this from the DVD */
@@ -257,6 +340,11 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
     i_width  = p_spu->i_width  * i_xscale;
     i_height = p_spu->i_height * i_yscale;
 
+    i_x_start = i_width - i_xscale * p_spu->p_sys->i_x_end;
+    i_y_start = i_yscale * p_spu->p_sys->i_y_start;
+    i_x_end = i_width - i_xscale * p_spu->p_sys->i_x_start;
+    i_y_end = i_yscale * p_spu->p_sys->i_y_end;
+
     p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 4
               /* Add the picture coordinates and the SPU coordinates */
               + ( (p_spu->i_x * i_xscale) >> 6 ) * 4
@@ -275,33 +363,35 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
             i_yreal = p_pic->p->i_pitch * i_ytmp;
 
             /* Draw until we reach the end of the line */
-            for( i_x = i_width ; i_x ; )
+            for( i_x = i_width ; i_x ; i_x -= i_len )
             {
                 /* Get the RLE part, then draw the line */
                 i_color = *p_source & 0x3;
+                i_len = i_xscale * ( *p_source++ >> 2 );
+
+                if( b_crop
+                     && ( i_x < i_x_start || i_x > i_x_end
+                           || i_y < i_y_start || i_y > i_y_end ) )
+                {
+                    continue;
+                }
 
                 switch( p_spu->p_sys->pi_alpha[ i_color ] )
                 {
                 case 0x00:
-                    i_x -= i_xscale * ( *p_source++ >> 2 );
                     break;
 
                 case 0x0f:
-                    i_len = i_xscale * ( *p_source++ >> 2 );
                     memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal,
                             p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) );
-                    i_x -= i_len;
                     break;
 
                 default:
                     /* FIXME: we should do transparency */
-                    i_len = i_xscale * ( *p_source++ >> 2 );
                     memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal,
                             p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) );
-                    i_x -= i_len;
                     break;
                 }
-
             }
         }
         else
@@ -310,19 +400,25 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
             i_ynext = p_pic->p->i_pitch * i_y >> 6;
 
             /* Draw until we reach the end of the line */
-            for( i_x = i_width ; i_x ; )
+            for( i_x = i_width ; i_x ; i_x -= i_len )
             {
                 /* Get the RLE part, then draw as many lines as needed */
                 i_color = *p_source & 0x3;
+                i_len = i_xscale * ( *p_source++ >> 2 );
+
+                if( b_crop
+                     && ( i_x < i_x_start || i_x > i_x_end
+                           || i_y < i_y_start || i_y > i_y_end ) )
+                {
+                    continue;
+                }
 
                 switch( p_spu->p_sys->pi_alpha[ i_color ] )
                 {
                 case 0x00:
-                    i_x -= i_xscale * ( *p_source++ >> 2 );
                     break;
 
                 case 0x0f:
-                    i_len = i_xscale * ( *p_source++ >> 2 );
                     for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
                          i_ytmp += p_pic->p->i_pitch )
                     {
@@ -330,12 +426,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
                                 p_clut32[ i_color ],
                                 4 * ( ( i_len >> 6 ) + 1 ) );
                     }
-                    i_x -= i_len;
                     break;
 
                 default:
                     /* FIXME: we should do transparency */
-                    i_len = i_xscale * ( *p_source++ >> 2 );
                     for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
                          i_ytmp += p_pic->p->i_pitch )
                     {
@@ -343,40 +437,63 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
                                 p_clut32[ i_color ],
                                 4 * ( ( i_len >> 6 ) + 1 ) );
                     }
-                    i_x -= i_len;
                     break;
                 }
             }
         }
     }
+}
+
+static void RenderYUY2( vout_thread_t *p_vout, picture_t *p_pic,
+                        const subpicture_t *p_spu, vlc_bool_t b_crop )
+{
+    /* Common variables */
+    u8  *p_dest;
+    u16 *p_source = (u16 *)p_spu->p_sys->p_data;
 
-    break;
+    int i_x, i_y;
+    int i_len, i_color;
+    u8  i_cnt;
 
-    /* NVidia overlay, no scaling */
-    case VLC_FOURCC('Y','U','Y','2'):
+    /* Crop-specific */
+    int i_x_start, i_y_start, i_x_end, i_y_end;
 
     p_dest = p_pic->p->p_pixels +
               + ( p_spu->i_y + p_spu->i_height ) * p_pic->p->i_pitch  // * bytes per line
               + ( p_spu->i_x + p_spu->i_width ) * 2;  // * bytes per pixel
+
+    i_x_start = p_spu->i_width - p_spu->p_sys->i_x_end;
+    i_y_start = (p_spu->i_height - p_spu->p_sys->i_y_end)
+                  * p_pic->p->i_pitch / 2;
+    i_x_end = p_spu->i_width - p_spu->p_sys->i_x_start;
+    i_y_end = (p_spu->i_height - p_spu->p_sys->i_y_start)
+                * p_pic->p->i_pitch / 2;
+
     /* Draw until we reach the bottom of the subtitle */
     for( i_y = p_spu->i_height * p_pic->p->i_pitch / 2;
          i_y ;
          i_y -= p_pic->p->i_pitch / 2 )
     {
         /* Draw until we reach the end of the line */
-        for( i_x = p_spu->i_width ; i_x ; )
+        for( i_x = p_spu->i_width ; i_x ; i_x -= i_len )
         {
             /* Get the RLE part, then draw the line */
             i_color = *p_source & 0x3;
+            i_len = *p_source++ >> 2;
+
+            if( b_crop
+                 && ( i_x < i_x_start || i_x > i_x_end
+                       || i_y < i_y_start || i_y > i_y_end ) )
+            {
+                continue;
+            }
 
             switch( p_spu->p_sys->pi_alpha[ i_color ] )
             {
             case 0x00:
-                i_x -= *p_source++ >> 2;
                 break;
 
             case 0x0f:
-                i_len = *p_source++ >> 2;
                 for( i_cnt = 0; i_cnt < i_len; i_cnt++ )
                 {
                     /* draw a pixel */
@@ -393,12 +510,10 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
                                 0x80, 1);
                     }
                 }
-                i_x -= i_len;
                 break;
 
             default:
                 /* FIXME: we should do transparency */
-                i_len = *p_source++ >> 2;
                 for( i_cnt = 0; i_cnt < i_len; i_cnt++ )
                 {
                     /* draw a pixel */
@@ -415,17 +530,9 @@ void E_(RenderSPU)( vout_thread_t *p_vout, picture_t *p_pic,
                                 0x80, 1);
                     }
                 }
-                i_x -= i_len;
                 break;
             }
         }
     }
-
-    break;
-
-
-    default:
-        msg_Err( p_vout, "unknown chroma, can't render SPU" );
-        break;
-    }
 }
+
index 12617c24a2ee451ee5cfc28ac9fd31f68e474d4f..03383909a551e80bf6fc86fa6a71768a856aa377 100644 (file)
@@ -2,7 +2,7 @@
  * spudec.c : SPU decoder thread
  *****************************************************************************
  * Copyright (C) 2000-2001 VideoLAN
- * $Id: spudec.c,v 1.6 2002/10/31 09:40:26 gbazin Exp $
+ * $Id: spudec.c,v 1.7 2002/11/06 18:07:57 sam Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
@@ -68,14 +68,15 @@ static int OpenDecoder( vlc_object_t *p_this )
 {
     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
 
-    if( p_fifo->i_fourcc == VLC_FOURCC('s','p','u',' ')
-         || p_fifo->i_fourcc == VLC_FOURCC('s','p','u','b') )
+    if( p_fifo->i_fourcc != VLC_FOURCC('s','p','u',' ')
+         && p_fifo->i_fourcc != VLC_FOURCC('s','p','u','b') )
     {   
-        p_fifo->pf_run = RunDecoder;
-        return VLC_SUCCESS;
+        return VLC_EGENERIC;
     }
     
-    return VLC_EGENERIC;
+    p_fifo->pf_run = RunDecoder;
+
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -84,7 +85,7 @@ static int OpenDecoder( vlc_object_t *p_this )
 static int RunDecoder( decoder_fifo_t * p_fifo )
 {
     spudec_thread_t *     p_spudec;
-   
+
     /* Allocate the memory needed to store the thread's structure */
     p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) );
 
@@ -112,10 +113,12 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
      */
     while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
     {
-        if( !E_(SyncPacket)( p_spudec ) )
+        if( E_(SyncPacket)( p_spudec ) )
         {
-            E_(ParsePacket)( p_spudec );
+            continue;
         }
+
+        E_(ParsePacket)( p_spudec );
     }
 
     /*
@@ -183,7 +186,7 @@ static int InitThread( spudec_thread_t *p_spudec )
 static void EndThread( spudec_thread_t *p_spudec )
 {
     if( p_spudec->p_vout != NULL 
-     && p_spudec->p_vout->p_subpicture != NULL )
+         && p_spudec->p_vout->p_subpicture != NULL )
     {
         subpicture_t *  p_subpic;
         int             i_subpic;
index c38b5c7285fd7d22b1efcff66dd07c32548b2bc9..887380e787a34d7627989c28f33bb64089af3c0d 100644 (file)
@@ -2,7 +2,7 @@
  * spudec.h : sub picture unit decoder thread interface
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: spudec.h,v 1.2 2002/08/16 03:07:56 sam Exp $
+ * $Id: spudec.h,v 1.3 2002/11/06 18:07:57 sam Exp $
  *
  * Authors: Samuel Hocevar <sam@zoy.org>
  *
@@ -21,6 +21,8 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
+typedef struct spudec_thread_t spudec_thread_t;
+
 struct subpicture_sys_t
 {
     mtime_t i_pts;                                 /* presentation timestamp */
@@ -30,14 +32,22 @@ struct subpicture_sys_t
 
     /* Color information */
     vlc_bool_t b_palette;
-    u8    pi_alpha[4];
-    u8    pi_yuv[4][3];
+    uint8_t    pi_alpha[4];
+    uint8_t    pi_yuv[4][3];
+
+    /* Link to our input */
+    vlc_object_t * p_input;
+
+    /* Cropping properties */
+    vlc_mutex_t  lock;
+    vlc_bool_t   b_crop;
+    int          i_x_start, i_y_start, i_x_end, i_y_end;
 };
 
 /*****************************************************************************
  * spudec_thread_t : sub picture unit decoder thread descriptor
  *****************************************************************************/
-typedef struct spudec_thread_t
+struct spudec_thread_t
 {
     /*
      * Thread properties and locks
@@ -61,8 +71,7 @@ typedef struct spudec_thread_t
      */
     int                 i_spu_size;            /* size of current SPU packet */
     int                 i_rle_size;                  /* size of the RLE part */
-
-} spudec_thread_t;
+};
 
 /*****************************************************************************
  * Amount of bytes we GetChunk() in one go
index d7affb8dfce55cf47d85877fd96b1598c8eacfd3..545edba938833e2076b8fda848e61c218481ffd6 100644 (file)
@@ -2,7 +2,7 @@
  * vout_subpictures.c : subpicture management functions
  *****************************************************************************
  * Copyright (C) 2000 VideoLAN
- * $Id: vout_subpictures.c,v 1.15 2002/10/17 08:24:12 sam Exp $
+ * $Id: vout_subpictures.c,v 1.16 2002/11/06 18:07:56 sam Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
@@ -77,12 +77,10 @@ void  vout_DisplaySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
  * already allocated zone of memory in the spu data fields. It needs locking
  * since several pictures can be created by several producers threads.
  *****************************************************************************/
-subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
-                                     int i_size )
+subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type )
 {
     int                 i_subpic;                        /* subpicture index */
-    subpicture_t *      p_free_subpic = NULL;       /* first free subpicture */
-    subpicture_t *      p_destroyed_subpic = NULL; /* first destroyed subpic */
+    subpicture_t *      p_subpic = NULL;            /* first free subpicture */
 
     /* Get lock */
     vlc_mutex_lock( &p_vout->subpicture_lock );
@@ -92,78 +90,39 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
      */
     for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
     {
-        if( p_vout->p_subpicture[i_subpic].i_status == DESTROYED_SUBPICTURE )
-        {
-            /* Subpicture is marked for destruction, but is still allocated */
-            if( (p_vout->p_subpicture[i_subpic].i_type  == i_type)   &&
-                (p_vout->p_subpicture[i_subpic].i_size  >= i_size) )
-            {
-                /* Memory size do match or is smaller : memory will not be
-                 * reallocated, and function can end immediately - this is
-                 * the best possible case, since no memory allocation needs
-                 * to be done */
-                p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
-                vlc_mutex_unlock( &p_vout->subpicture_lock );
-                return &p_vout->p_subpicture[i_subpic];
-            }
-            else if( p_destroyed_subpic == NULL )
-            {
-                /* Memory size do not match, but subpicture index will be kept
-                 * in case we find no other place */
-                p_destroyed_subpic = &p_vout->p_subpicture[i_subpic];
-            }
-        }
-        else if( (p_free_subpic == NULL) &&
-                 (p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE ))
+        if( p_vout->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE )
         {
             /* Subpicture is empty and ready for allocation */
-            p_free_subpic = &p_vout->p_subpicture[i_subpic];
+            p_subpic = &p_vout->p_subpicture[i_subpic];
+            p_vout->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
+            break;
         }
     }
 
-    /* If no free subpictures are available, use a destroyed subpicture */
-    if( (p_free_subpic == NULL) && (p_destroyed_subpic != NULL ) )
-    {
-        /* No free subpicture or matching destroyed subpictures have been
-         * found, but a destroyed subpicture is still available */
-        free( p_destroyed_subpic->p_sys_orig );
-        p_free_subpic = p_destroyed_subpic;
-    }
-
-    /* If no free or destroyed subpicture could be found */
-    if( p_free_subpic == NULL )
+    /* If no free subpicture could be found */
+    if( p_subpic == NULL )
     {
         msg_Err( p_vout, "subpicture heap is full" );
         vlc_mutex_unlock( &p_vout->subpicture_lock );
         return NULL;
     }
 
-    p_free_subpic->p_sys =
-        vlc_memalign( &p_free_subpic->p_sys_orig, 16, i_size );
+    /* Copy subpicture information, set some default values */
+    p_subpic->i_type    = i_type;
+    p_subpic->i_status  = RESERVED_SUBPICTURE;
 
-    if( p_free_subpic->p_sys != NULL )
-    {
-        /* Copy subpicture information, set some default values */
-        p_free_subpic->i_type   = i_type;
-        p_free_subpic->i_status = RESERVED_SUBPICTURE;
-        p_free_subpic->i_size   = i_size;
-        p_free_subpic->i_x      = 0;
-        p_free_subpic->i_y      = 0;
-        p_free_subpic->i_width  = 0;
-        p_free_subpic->i_height = 0;
-    }
-    else
-    {
-        /* Memory allocation failed : set subpicture as empty */
-        msg_Err( p_vout, "out of memory" );
-        p_free_subpic->i_type   = EMPTY_SUBPICTURE;
-        p_free_subpic->i_status = FREE_SUBPICTURE;
-        p_free_subpic           = NULL;
-    }
+    p_subpic->i_start   = 0;
+    p_subpic->i_stop    = 0;
+    p_subpic->b_ephemer = VLC_FALSE;
+
+    p_subpic->i_x       = 0;
+    p_subpic->i_y       = 0;
+    p_subpic->i_width   = 0;
+    p_subpic->i_height  = 0;
 
     vlc_mutex_unlock( &p_vout->subpicture_lock );
 
-    return p_free_subpic;
+    return p_subpic;
 }
 
 /*****************************************************************************
@@ -176,15 +135,20 @@ subpicture_t *vout_CreateSubPicture( vout_thread_t *p_vout, int i_type,
  *****************************************************************************/
 void vout_DestroySubPicture( vout_thread_t *p_vout, subpicture_t *p_subpic )
 {
-   /* Check if status is valid */
-   if( ( p_subpic->i_status != RESERVED_SUBPICTURE )
-          && ( p_subpic->i_status != READY_SUBPICTURE ) )
-   {
-       msg_Err( p_vout, "subpicture %p has invalid status %d",
-                        p_subpic, p_subpic->i_status );
-   }
-
-    p_subpic->i_status = DESTROYED_SUBPICTURE;
+    /* Check if status is valid */
+    if( ( p_subpic->i_status != RESERVED_SUBPICTURE )
+           && ( p_subpic->i_status != READY_SUBPICTURE ) )
+    {
+        msg_Err( p_vout, "subpicture %p has invalid status %d",
+                         p_subpic, p_subpic->i_status );
+    }
+
+    if( p_subpic->pf_destroy )
+    {
+        p_subpic->pf_destroy( p_subpic );
+    }
+
+    p_subpic->i_status = FREE_SUBPICTURE;
 }
 
 /*****************************************************************************