]> git.sesse.net Git - vlc/commitdiff
* src/video_output/vout_subpictures.c: support for subpictures filters.
authorGildas Bazin <gbazin@videolan.org>
Fri, 17 Sep 2004 09:11:50 +0000 (09:11 +0000)
committerGildas Bazin <gbazin@videolan.org>
Fri, 17 Sep 2004 09:11:50 +0000 (09:11 +0000)
* src/libvlc.h: new --sub-filter config option + added a new subpictures category that regroups all the subpictures options.

include/vlc_filter.h
include/vlc_spu.h
modules/misc/freetype.c
modules/stream_out/transcode.c
src/libvlc.h
src/video_output/video_output.c
src/video_output/vout_subpictures.c

index f032946fd5981cf24cf39adacf439dbbda77d0fa..b6e2251ede764cd6f2869b54613a4b4ee8378aa3 100644 (file)
@@ -57,8 +57,7 @@ struct filter_t
                                                 picture_t *, picture_t *,
                                                 int, int );
 
-    subpicture_t *      ( *pf_subpicture_filter ) ( filter_t * );
-
+    subpicture_t *      ( *pf_sub_filter ) ( filter_t *, mtime_t );
     subpicture_t *      ( *pf_render_string ) ( filter_t *, block_t * );
 
     /*
@@ -75,8 +74,8 @@ struct filter_t
     void            ( * pf_picture_unlink)  ( filter_t *, picture_t * );
 
     /* SPU output callbacks */
-    subpicture_t *  ( * pf_spu_buffer_new) ( filter_t * );
-    void            ( * pf_spu_buffer_del) ( filter_t *, subpicture_t * );
+    subpicture_t *  ( * pf_sub_buffer_new) ( filter_t * );
+    void            ( * pf_sub_buffer_del) ( filter_t *, subpicture_t * );
 
     /* Private structure for the owner of the decoder */
     filter_owner_sys_t *p_owner;
index dfffd86f224d279314a3fda2d6f233fd89a5d495..f02dca0b41c23dbe40d8976c8d368e55f6047ff4 100644 (file)
@@ -52,6 +52,10 @@ struct spu_t
     uint8_t pi_alpha[4];                           /**< forced alpha palette */
 
     int ( *pf_control ) ( spu_t *, int, va_list );
+
+    /* Supciture filters */
+    filter_t *pp_filter[10];
+    int      i_filter;
 };
 
 static inline int spu_vaControl( spu_t *p_spu, int i_query, va_list args )
@@ -83,8 +87,9 @@ enum spu_query_e
  * \addtogroup subpicture
  * @{
  */
-#define spu_Init(a) __spu_Init(VLC_OBJECT(a))
-VLC_EXPORT( spu_t *, __spu_Init, ( vlc_object_t * ) );
+#define spu_Create(a) __spu_Create(VLC_OBJECT(a))
+VLC_EXPORT( spu_t *, __spu_Create, ( vlc_object_t * ) );
+VLC_EXPORT( int, spu_Init, ( spu_t * ) );
 VLC_EXPORT( void, spu_Destroy, ( spu_t * ) );
 void spu_Attach( spu_t *, vlc_object_t *, vlc_bool_t );
 
index e1599ad9ff4e8550c6cb1836f2e45ba4e9c22175..0acceb60950a5310780519a05cc6d5df750abbd9 100644 (file)
@@ -419,7 +419,7 @@ static subpicture_t *RenderText( filter_t *p_filter, block_t *p_block )
     line.yMax = 0;
 
     /* Create and initialize a subpicture */
-    p_subpic = p_filter->pf_spu_buffer_new( p_filter );
+    p_subpic = p_filter->pf_sub_buffer_new( p_filter );
     if( !p_subpic ) goto error;
 
     p_subpic->i_start = p_block->i_pts;
@@ -601,7 +601,7 @@ static subpicture_t *RenderText( filter_t *p_filter, block_t *p_block )
 
  error:
     FreeString( p_string );
-    if( p_subpic ) p_filter->pf_spu_buffer_del( p_filter, p_subpic );
+    if( p_subpic ) p_filter->pf_sub_buffer_del( p_filter, p_subpic );
     block_Release( p_block );
     return NULL;
 }
index bdaa17281fee58f9f3caa849a9db9b6471669818..cde12c19a6fc88597221fdd2605bac53b32f5d0f 100644 (file)
@@ -1820,7 +1820,8 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id )
     }
     else if( !p_sys->p_spu )
     {
-        p_sys->p_spu = spu_Init( p_stream );
+        p_sys->p_spu = spu_Create( p_stream );
+        spu_Init( p_sys->p_spu );
     }
 
     return VLC_SUCCESS;
index 9f9a6c8b45d6f71b05175f44d816e58d94680469..896f5a3d7b23db196b51fd179b1ced788fedc89e 100644 (file)
@@ -232,16 +232,6 @@ static char *ppsz_align_descriptions[] =
 #define VIDEO_ON_TOP_LONGTEXT N_("Always place the video window on top of " \
     "other windows." )
 
-#define SPUMARGIN_TEXT N_("Force SPU position")
-#define SPUMARGIN_LONGTEXT N_( \
-    "You can use this option to place the subtitles under the movie, " \
-    "instead of over the movie. Try several positions.")
-
-#define OSD_TEXT N_("On Screen Display")
-#define OSD_LONGTEXT N_( \
-    "VLC can display messages on the video. This is called OSD (On Screen " \
-    "Display). You can disable this feature here.")
-
 #define FILTER_TEXT N_("Video filter module")
 #define FILTER_LONGTEXT N_( \
     "This will allow you to add a post-processing filter to enhance the " \
@@ -299,12 +289,12 @@ static char *ppsz_align_descriptions[] =
 #define INPUT_CHAN_TEXT N_("Choose audio channel")
 #define INPUT_CHAN_LONGTEXT N_( \
     "Give the stream number of the audio channel you want to use in a DVD " \
-    "(from 1 to n).")
+    "(from 0 to n).")
 
-#define INPUT_SUBT_TEXT N_("Choose subtitle track")
-#define INPUT_SUBT_LONGTEXT N_( \
+#define INPUT_SUB_TEXT N_("Choose subtitle track")
+#define INPUT_SUB_LONGTEXT N_( \
     "Give the stream number of the subtitle channel you want to use " \
-    "(from 1 to n).")
+    "(from 0 to n).")
 
 #define INPUT_REPEAT_TEXT N_("Number of time the same input will be repeated")
 #define INPUT_REPEAT_LONGTEXT N_("Number of time the same input will be repeated")
@@ -323,6 +313,28 @@ static char *ppsz_align_descriptions[] =
     "the form \"{name=bookmark-name,time=optional-time-offset," \
     "bytes=optional-byte-offset},{etc...}\"")
 
+#define SUB_CAT_LONGTEXT N_( \
+    "These options allow you to modify the behavior of the subpictures " \
+    "subsystem. You can for example enable subpictures filters (logo, ...). " \
+    "Enable these filters here and configure them in the " \
+    "\"subpictures filters\" modules section. You can also set many " \
+    "miscellaneous subpictures options." )
+
+#define SPUMARGIN_TEXT N_("Force SPU position")
+#define SPUMARGIN_LONGTEXT N_( \
+    "You can use this option to place the subtitles under the movie, " \
+    "instead of over the movie. Try several positions.")
+
+#define OSD_TEXT N_("On Screen Display")
+#define OSD_LONGTEXT N_( \
+    "VLC can display messages on the video. This is called OSD (On Screen " \
+    "Display). You can disable this feature here.")
+
+#define SUB_FILTER_TEXT N_("Subpictures filter module")
+#define SUB_FILTER_LONGTEXT N_( \
+    "This will allow you to add a subpictures filter for instance to overlay "\
+    "a logo.")
+
 #define SUB_AUTO_TEXT N_("Autodetect subtitle files")
 #define SUB_AUTO_LONGTEXT \
     N_("Automatically detect a subtitle file, if no subtitle filename is " \
@@ -795,17 +807,19 @@ vlc_module_begin();
     add_integer_with_range( "saved-volume", AOUT_VOLUME_DEFAULT,
                             AOUT_VOLUME_MIN, AOUT_VOLUME_MAX, NULL,
                             VOLUME_SAVE_TEXT, VOLUME_SAVE_LONGTEXT, VLC_TRUE );
-    add_integer( "aout-rate", -1, NULL, AOUT_RATE_TEXT, AOUT_RATE_LONGTEXT, VLC_TRUE );
+    add_integer( "aout-rate", -1, NULL, AOUT_RATE_TEXT,
+                 AOUT_RATE_LONGTEXT, VLC_TRUE );
 #if !defined( SYS_DARWIN )
-    add_bool( "hq-resampling", 1, NULL, AOUT_RESAMP_TEXT, AOUT_RESAMP_LONGTEXT, VLC_TRUE );
+    add_bool( "hq-resampling", 1, NULL, AOUT_RESAMP_TEXT,
+              AOUT_RESAMP_LONGTEXT, VLC_TRUE );
 #endif
     add_bool( "spdif", 0, NULL, SPDIF_TEXT, SPDIF_LONGTEXT, VLC_FALSE );
-    add_integer( "audio-desync", 0, NULL, DESYNC_TEXT, DESYNC_LONGTEXT, VLC_TRUE );
-    add_string("audio-filter",0,NULL,AUDIO_FILTER_TEXT,
-                    AUDIO_FILTER_LONGTEXT,VLC_FALSE);
+    add_integer( "audio-desync", 0, NULL, DESYNC_TEXT,
+                 DESYNC_LONGTEXT, VLC_TRUE );
+    add_string( "audio-filter", 0, NULL,AUDIO_FILTER_TEXT,
+                AUDIO_FILTER_LONGTEXT, VLC_FALSE );
     add_module( "audio-channel-mixer", "audio filter", NULL, NULL,
-                    AUDIO_CHANNEL_MIXER, AUDIO_CHANNEL_MIXER_LONGTEXT,
-                    VLC_FALSE );
+                AUDIO_CHANNEL_MIXER, AUDIO_CHANNEL_MIXER_LONGTEXT, VLC_FALSE );
 
     /* Video options */
     add_category_hint( N_("Video"), VOUT_CAT_LONGTEXT , VLC_FALSE );
@@ -822,17 +836,17 @@ vlc_module_begin();
     add_integer( "align", 0, NULL, ALIGN_TEXT, ALIGN_LONGTEXT, VLC_TRUE );
         change_integer_list( pi_align_values, ppsz_align_descriptions, 0 );
     add_float( "zoom", 1, NULL, ZOOM_TEXT, ZOOM_LONGTEXT, VLC_TRUE );
-    add_bool( "grayscale", 0, NULL, GRAYSCALE_TEXT, GRAYSCALE_LONGTEXT, VLC_TRUE );
+    add_bool( "grayscale", 0, NULL, GRAYSCALE_TEXT,
+              GRAYSCALE_LONGTEXT, VLC_TRUE );
     add_bool( "fullscreen", 0, NULL, FULLSCREEN_TEXT,
-                        FULLSCREEN_LONGTEXT, VLC_FALSE );
+              FULLSCREEN_LONGTEXT, VLC_FALSE );
+        change_short('F');
 #ifndef SYS_DARWIN
     add_bool( "overlay", 1, NULL, OVERLAY_TEXT, OVERLAY_LONGTEXT, VLC_TRUE );
 #endif
 
-    add_bool( "video-on-top", 0, NULL, VIDEO_ON_TOP_TEXT, VIDEO_ON_TOP_LONGTEXT, VLC_FALSE );
-    add_integer( "spumargin", -1, NULL, SPUMARGIN_TEXT,
-                        SPUMARGIN_LONGTEXT, VLC_TRUE );
-    add_bool( "osd", 1, NULL, OSD_TEXT, OSD_LONGTEXT, VLC_FALSE );
+    add_bool( "video-on-top", 0, NULL, VIDEO_ON_TOP_TEXT,
+              VIDEO_ON_TOP_LONGTEXT, VLC_FALSE );
     add_module( "filter", "video filter", NULL, NULL,
                 FILTER_TEXT, FILTER_LONGTEXT, VLC_FALSE );
     add_string( "aspect-ratio", "", NULL,
@@ -841,6 +855,27 @@ vlc_module_begin();
     add_string( "pixel-ratio", "1", NULL, PIXEL_RATIO_TEXT, PIXEL_RATIO_TEXT );
 #endif
 
+    /* Subpictures options */
+    add_category_hint( N_("Subpictures"), SUB_CAT_LONGTEXT , VLC_FALSE );
+    add_bool( "osd", 1, NULL, OSD_TEXT, OSD_LONGTEXT, VLC_FALSE );
+    add_bool( "sub-autodetect-file", VLC_TRUE, NULL,
+                 SUB_AUTO_TEXT, SUB_AUTO_LONGTEXT, VLC_FALSE );
+    add_integer( "sub-autodetect-fuzzy", 3, NULL,
+                 SUB_FUZZY_TEXT, SUB_FUZZY_LONGTEXT, VLC_TRUE );
+#ifdef WIN32
+#   define SUB_PATH ".\\subtitles"
+#else
+#   define SUB_PATH "./Subtitles, ./subtitles"
+#endif
+    add_string( "sub-autodetect-path", SUB_PATH, NULL,
+                 SUB_PATH_TEXT, SUB_PATH_LONGTEXT, VLC_TRUE );
+    add_file( "sub-file", NULL, NULL, SUB_FILE_TEXT,
+              SUB_FILE_LONGTEXT, VLC_TRUE );
+    add_integer( "spumargin", -1, NULL, SPUMARGIN_TEXT,
+                 SPUMARGIN_LONGTEXT, VLC_TRUE );
+    add_module( "sub-filter", "subpicture filter", NULL, NULL,
+                SUB_FILTER_TEXT, SUB_FILTER_LONGTEXT, VLC_TRUE );
+
     /* Input options */
     add_category_hint( N_("Input"), INPUT_CAT_LONGTEXT , VLC_FALSE );
     add_integer( "cr-average", 40, NULL, CR_AVERAGE_TEXT,
@@ -848,7 +883,8 @@ vlc_module_begin();
     add_integer( "server-port", 1234, NULL,
                  SERVER_PORT_TEXT, SERVER_PORT_LONGTEXT, VLC_FALSE );
     add_integer( "mtu", 1500, NULL, MTU_TEXT, MTU_LONGTEXT, VLC_TRUE );
-    add_string( "iface-addr", "", NULL, IFACE_ADDR_TEXT, IFACE_ADDR_LONGTEXT, VLC_TRUE );
+    add_string( "iface-addr", "", NULL, IFACE_ADDR_TEXT,
+                IFACE_ADDR_LONGTEXT, VLC_TRUE );
 
     add_integer( "program", 0, NULL,
                  INPUT_PROGRAM_TEXT, INPUT_PROGRAM_LONGTEXT, VLC_TRUE );
@@ -857,20 +893,7 @@ vlc_module_begin();
     add_integer( "audio-channel", -1, NULL,
                  INPUT_CHAN_TEXT, INPUT_CHAN_LONGTEXT, VLC_FALSE );
     add_integer( "spu-channel", -1, NULL,
-                 INPUT_SUBT_TEXT, INPUT_SUBT_LONGTEXT, VLC_FALSE );
-    add_bool( "sub-autodetect-file", VLC_TRUE, NULL,
-                 SUB_AUTO_TEXT, SUB_AUTO_LONGTEXT, VLC_FALSE );
-    add_integer( "sub-autodetect-fuzzy", 3, NULL,
-                 SUB_FUZZY_TEXT, SUB_FUZZY_LONGTEXT, VLC_TRUE );
-#ifdef WIN32
-#   define SUB_PATH ".\\subtitles"
-#else
-#   define SUB_PATH "./Subtitles, ./subtitles"
-#endif
-    add_string( "sub-autodetect-path", SUB_PATH, NULL,
-                 SUB_PATH_TEXT, SUB_PATH_LONGTEXT, VLC_TRUE );
-    add_file( "sub-file", NULL, NULL,
-                 SUB_FILE_TEXT, SUB_FILE_LONGTEXT, VLC_TRUE );
+                 INPUT_SUB_TEXT, INPUT_SUB_LONGTEXT, VLC_FALSE );
     add_integer( "input-repeat", 0, NULL,
                  INPUT_REPEAT_TEXT, INPUT_REPEAT_LONGTEXT, VLC_TRUE );
     add_integer( "start-time", 0, NULL,
@@ -914,8 +937,10 @@ vlc_module_begin();
 
     /* Decoder options */
     add_category_hint( N_("Decoders"), CODEC_CAT_LONGTEXT , VLC_TRUE );
-    add_module( "codec", "decoder", NULL, NULL, CODEC_TEXT, CODEC_LONGTEXT, VLC_TRUE );
-    add_module( "encoder", "encoder", NULL, NULL, ENCODER_TEXT, ENCODER_LONGTEXT, VLC_TRUE );
+    add_module( "codec", "decoder", NULL, NULL, CODEC_TEXT,
+                CODEC_LONGTEXT, VLC_TRUE );
+    add_module( "encoder", "encoder", NULL, NULL, ENCODER_TEXT,
+                ENCODER_LONGTEXT, VLC_TRUE );
 
 
     /* Stream output options */
index a4a1736e52c4a7d4247fbd52a4bc0b3576f881c5..5bdbb12b854f351f3517551f97d0cee79cc4cbf5 100644 (file)
@@ -287,12 +287,14 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent,
     var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
 
     /* Initialize subpicture unit */
-    p_vout->p_spu = spu_Init( p_vout );
+    p_vout->p_spu = spu_Create( p_vout );
     spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
 
     /* Attach the new object now so we can use var inheritance below */
     vlc_object_attach( p_vout, p_parent );
 
+    spu_Init( p_vout->p_spu );
+
     /* Take care of some "interface/control" related initialisations */
     vout_IntfInit( p_vout );
 
index 725e0823e3ee1dab0c722b9f670fabe5b7118b2d..2515b99e7b95b4912b9ad82445c7fec7ee4f6b95 100644 (file)
@@ -46,17 +46,19 @@ static void UpdateSPU   ( spu_t *, vlc_object_t * );
 static int  CropCallback( vlc_object_t *, char const *,
                           vlc_value_t, vlc_value_t, void * );
 
+static subpicture_t *sub_new_buffer( filter_t * );
+static void sub_del_buffer( filter_t *, subpicture_t * );
 static subpicture_t *spu_new_buffer( filter_t * );
 static void spu_del_buffer( filter_t *, subpicture_t * );
 static picture_t *spu_new_video_buffer( filter_t * );
 static void spu_del_video_buffer( filter_t *, picture_t * );
 
 /**
- * Initialise the subpicture unit
+ * Creates the subpicture unit
  *
  * \param p_this the parent object which creates the subpicture unit
  */
-spu_t *__spu_Init( vlc_object_t *p_this )
+spu_t *__spu_Create( vlc_object_t *p_this )
 {
     int i_index;
     spu_t *p_spu = vlc_object_create( p_this, VLC_OBJECT_SPU );
@@ -70,6 +72,7 @@ spu_t *__spu_Init( vlc_object_t *p_this )
     p_spu->p_blend = NULL;
     p_spu->p_text = NULL;
     p_spu->p_scale = NULL;
+    p_spu->i_filter = 0;
 
     /* Register the default subpicture channel */
     p_spu->i_channel = 1;
@@ -78,10 +81,50 @@ spu_t *__spu_Init( vlc_object_t *p_this )
 
     vlc_object_attach( p_spu, p_this );
 
+    return p_spu;
+}
+
+/**
+ * Initialise the subpicture unit
+ *
+ * \param p_spu the subpicture unit object
+ */
+int spu_Init( spu_t *p_spu )
+{
+    char *psz_filter, *psz_filter_orig;
+    vlc_value_t val;
+
     /* If the user requested an SPU margin, we force the position. */
-    p_spu->i_margin = config_GetInt( p_spu, "spumargin" );
+    var_Create( p_spu, "spumargin", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+    var_Get( p_spu, "spumargin", &val );
+    p_spu->i_margin = val.i_int;
+
+    var_Create( p_spu, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+    var_Get( p_spu, "sub-filter", &val );
+    psz_filter = psz_filter_orig = val.psz_string;
+    if( psz_filter && *psz_filter )
+    {
+        p_spu->pp_filter[p_spu->i_filter] =
+            vlc_object_create( p_spu, VLC_OBJECT_FILTER );
+        vlc_object_attach( p_spu->pp_filter[p_spu->i_filter], p_spu );
+        p_spu->pp_filter[p_spu->i_filter]->pf_sub_buffer_new = sub_new_buffer;
+        p_spu->pp_filter[p_spu->i_filter]->pf_sub_buffer_del = sub_del_buffer;
+        p_spu->pp_filter[p_spu->i_filter]->p_owner =
+            (filter_owner_sys_t *)p_spu;
+        p_spu->pp_filter[p_spu->i_filter]->p_module =
+            module_Need( p_spu->pp_filter[p_spu->i_filter],
+                         "subpicture filter", psz_filter, 0 );
+        if( p_spu->pp_filter[p_spu->i_filter]->p_module ) p_spu->i_filter++;
+        else
+        {
+            msg_Dbg( p_spu, "no subpicture filter found" );
+            vlc_object_detach( p_spu->pp_filter[p_spu->i_filter] );
+            vlc_object_destroy( p_spu->pp_filter[p_spu->i_filter] );
+        }
+    }
+    if( psz_filter_orig ) free( psz_filter_orig );
 
-    return p_spu;
+    return VLC_EGENERIC;
 }
 
 /**
@@ -131,6 +174,14 @@ void spu_Destroy( spu_t *p_spu )
         vlc_object_destroy( p_spu->p_scale );
     }
 
+    while( p_spu->i_filter-- )
+    {
+        module_Unneed( p_spu->pp_filter[p_spu->i_filter],
+                       p_spu->pp_filter[p_spu->i_filter]->p_module );
+        vlc_object_detach( p_spu->pp_filter[p_spu->i_filter] );
+        vlc_object_destroy( p_spu->pp_filter[p_spu->i_filter] );
+    }
+
     vlc_mutex_destroy( &p_spu->subpicture_lock );
     vlc_object_destroy( p_spu );
 }
@@ -401,8 +452,8 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                 p_spu->p_text->fmt_out.video.i_visible_height =
                     p_fmt->i_height;
 
-            p_spu->p_text->pf_spu_buffer_new = spu_new_buffer;
-            p_spu->p_text->pf_spu_buffer_del = spu_del_buffer;
+            p_spu->p_text->pf_sub_buffer_new = spu_new_buffer;
+            p_spu->p_text->pf_sub_buffer_del = spu_del_buffer;
 
             p_spu->p_text->p_module =
                 module_Need( p_spu->p_text, "text renderer", 0, 0 );
@@ -473,7 +524,7 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                             *p_region = *p_subpic_tmp->p_region;
                             p_region->p_next = tmp_region.p_next;
                             *p_subpic_tmp->p_region = tmp_region;
-                            p_spu->p_text->pf_spu_buffer_del( p_spu->p_text,
+                            p_spu->p_text->pf_sub_buffer_del( p_spu->p_text,
                                                               p_subpic_tmp );
                         }
                     }
@@ -670,6 +721,18 @@ subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date )
     subpicture_t *p_ephemer    = NULL;
     mtime_t       ephemer_date = 0;
 
+    /* Run subpicture filters */
+    for( i_index = 0; i_index < p_spu->i_filter; i_index++ )
+    {
+        subpicture_t *p_subpic_filter;
+        p_subpic_filter = p_spu->pp_filter[i_index]->
+            pf_sub_filter( p_spu->pp_filter[i_index], display_date );
+        if( p_subpic_filter )
+        {
+            spu_DisplaySubpicture( p_spu, p_subpic_filter );
+        }
+    }
+
     /* We get an easily parsable chained list of subpictures which
      * ends with NULL since p_subpic was initialized to NULL. */
     for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
@@ -905,6 +968,18 @@ static int CropCallback( vlc_object_t *p_object, char const *psz_var,
 /*****************************************************************************
  * Buffers allocation callbacks for the filters
  *****************************************************************************/
+static subpicture_t *sub_new_buffer( filter_t *p_filter )
+{
+    spu_t *p_spu = (spu_t *)p_filter->p_owner;
+    return spu_CreateSubpicture( p_spu );
+}
+
+static void sub_del_buffer( filter_t *p_filter, subpicture_t *p_subpic )
+{
+    spu_t *p_spu = (spu_t *)p_filter->p_owner;
+    spu_DestroySubpicture( p_spu, p_subpic );
+}
+
 static subpicture_t *spu_new_buffer( filter_t *p_filter )
 {
     subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t));