]> git.sesse.net Git - vlc/blobdiff - src/video_output/vout_subpictures.c
Remove check for pthread_once - we never used it
[vlc] / src / video_output / vout_subpictures.c
index 06a7dbaedc6b7920cf824b187985583bad415842..3b7ff37c35e6a1716a5e63d217782a768d904541 100644 (file)
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #include <vlc/vlc.h>
 #include <vlc_vout.h>
 #include <vlc_block.h>
@@ -114,7 +118,7 @@ int spu_Init( spu_t *p_spu )
 
     spu_ParseChain( p_spu );
 
-    return VLC_EGENERIC;
+    return VLC_SUCCESS;
 }
 
 int spu_ParseChain( spu_t *p_spu )
@@ -145,10 +149,13 @@ int spu_ParseChain( spu_t *p_spu )
         if( p_spu->pp_filter[p_spu->i_filter]->p_module )
         {
             filter_owner_sys_t *p_sys = malloc( sizeof(filter_owner_sys_t) );
-            p_spu->pp_filter[p_spu->i_filter]->p_owner = p_sys;
-            spu_Control( p_spu, SPU_CHANNEL_REGISTER, &p_sys->i_channel );
-            p_sys->p_spu = p_spu;
-            p_spu->i_filter++;
+            if( p_sys )
+            {
+                p_spu->pp_filter[p_spu->i_filter]->p_owner = p_sys;
+                spu_Control( p_spu, SPU_CHANNEL_REGISTER, &p_sys->i_channel );
+                p_sys->p_spu = p_spu;
+                p_spu->i_filter++;
+            }
         }
         else
         {
@@ -167,7 +174,7 @@ int spu_ParseChain( spu_t *p_spu )
     }
     if( val.psz_string ) free( val.psz_string );
 
-    return VLC_EGENERIC;
+    return VLC_SUCCESS;
 }
 
 /**
@@ -226,8 +233,9 @@ void spu_Destroy( spu_t *p_spu )
 static void spu_DeleteChain( spu_t *p_spu )
 {
     if( p_spu->i_filter )
-    while( p_spu->i_filter-- )
+    while( p_spu->i_filter )
     {
+        p_spu->i_filter--;
         module_Unneed( p_spu->pp_filter[p_spu->i_filter],
                        p_spu->pp_filter[p_spu->i_filter]->p_module );
         free( p_spu->pp_filter[p_spu->i_filter]->p_owner );
@@ -281,10 +289,10 @@ subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this,
     if( !p_region ) return NULL;
 
     memset( p_region, 0, sizeof(subpicture_region_t) );
-    p_region->p_next = 0;
-    p_region->p_cache = 0;
+    p_region->p_next = NULL;
+    p_region->p_cache = NULL;
     p_region->fmt = *p_fmt;
-    p_region->psz_text = 0;
+    p_region->psz_text = NULL;
     p_region->p_style = NULL;
 
     if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') )
@@ -324,6 +332,7 @@ subpicture_region_t *__spu_MakeRegion( vlc_object_t *p_this,
 {
     subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
     (void)p_this;
+    if( !p_region ) return NULL;
     memset( p_region, 0, sizeof(subpicture_region_t) );
     p_region->p_next = 0;
     p_region->p_cache = 0;
@@ -440,10 +449,10 @@ subpicture_t *spu_CreateSubpicture( spu_t *p_spu )
     p_subpic->b_pausable = VLC_FALSE;
     p_subpic->b_fade     = VLC_FALSE;
     p_subpic->i_alpha    = 0xFF;
-    p_subpic->p_region   = 0;
-    p_subpic->pf_render  = 0;
-    p_subpic->pf_destroy = 0;
-    p_subpic->p_sys      = 0;
+    p_subpic->p_region   = NULL;
+    p_subpic->pf_render  = NULL;
+    p_subpic->pf_destroy = NULL;
+    p_subpic->p_sys      = NULL;
     vlc_mutex_unlock( &p_spu->subpicture_lock );
 
     p_subpic->pf_create_region = __spu_CreateRegion;
@@ -508,24 +517,66 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                             subpicture_t *p_subpic,
                             int i_scale_width_orig, int i_scale_height_orig )
 {
-    int i_source_video_width  = p_fmt->i_width  * 1000 / i_scale_width_orig;
-    int i_source_video_height = p_fmt->i_height * 1000 / i_scale_height_orig;
+    int i_source_video_width;
+    int i_source_video_height;
+    subpicture_t *p_subpic_v = p_subpic;
 
     /* Get lock */
     vlc_mutex_lock( &p_spu->subpicture_lock );
 
+    for( p_subpic_v = p_subpic;
+            p_subpic_v != NULL && p_subpic_v->i_status != FREE_SUBPICTURE;
+            p_subpic_v = p_subpic_v->p_next )
+    {
+        if( p_subpic_v->pf_pre_render )
+        {
+            p_subpic_v->pf_pre_render( p_fmt, p_spu, p_subpic_v, mdate() );
+        }
+    }
+
+    if( i_scale_width_orig <= 0 )
+        i_scale_width_orig = 1;
+    if( i_scale_height_orig <= 0 )
+        i_scale_height_orig = 1;
+
+    i_source_video_width  = p_fmt->i_width  * 1000 / i_scale_width_orig;
+    i_source_video_height = p_fmt->i_height * 1000 / i_scale_height_orig;
+
     /* Check i_status again to make sure spudec hasn't destroyed the subpic */
-    while( p_subpic != NULL && p_subpic->i_status != FREE_SUBPICTURE )
+    while( ( p_subpic != NULL ) && ( p_subpic->i_status != FREE_SUBPICTURE ) )
     {
-        subpicture_region_t *p_region = p_subpic->p_region;
+        subpicture_region_t *p_region;
         int pi_scale_width[ SCALE_SIZE ];
         int pi_scale_height[ SCALE_SIZE ];
         int pi_subpic_x[ SCALE_SIZE ];
         int k;
 
-        for( k=0; k< SCALE_SIZE ; k++ )
+        /* If the source video and subtitles stream agree on the size of
+         * the video then disregard all further references to the subtitle
+         * stream.
+         */
+        if( ( i_source_video_height == p_subpic->i_original_picture_height ) &&
+            ( i_source_video_width  == p_subpic->i_original_picture_width ) )
+        {
+            p_subpic->i_original_picture_height = 0;
+            p_subpic->i_original_picture_width = 0;
+        }
+
+        for( k = 0; k < SCALE_SIZE ; k++ )
             pi_subpic_x[ k ] = p_subpic->i_x;
 
+        if( p_subpic->pf_update_regions )
+        {
+            if ( p_subpic->p_region ) {
+                spu_DestroyRegion( p_spu, p_subpic->p_region );
+            }
+            p_subpic->p_region = p_region = p_subpic->pf_update_regions( p_fmt, p_spu, p_subpic, mdate() );
+        }
+        else
+        {
+            p_region = p_subpic->p_region;
+        }
+
         /* Load the blending module */
         if( !p_spu->p_blend && p_region )
         {
@@ -535,11 +586,11 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                 p_spu->p_blend->fmt_out.video.i_y_offset = 0;
             p_spu->p_blend->fmt_out.video.i_aspect = p_fmt->i_aspect;
             p_spu->p_blend->fmt_out.video.i_chroma = p_fmt->i_chroma;
-            p_spu->p_blend->fmt_in.video.i_chroma = VLC_FOURCC('Y','U','V','P');
-            /* XXX: We'll also be using it for YUVA and RGBA blending ... */
 
-            p_spu->p_blend->p_module =
-                module_Need( p_spu->p_blend, "video blending", 0, 0 );
+            /* The blend module will be loaded when needed with the real
+            * input format */
+            memset( &p_spu->p_blend->fmt_in, 0, sizeof(p_spu->p_blend->fmt_in) );
+            p_spu->p_blend->p_module = NULL;
         }
 
         /* Load the text rendering module; it is possible there is a
@@ -577,49 +628,78 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
             }
             if( psz_modulename ) free( psz_modulename );
         }
+
         if( p_spu->p_text )
         {
             subpicture_region_t *p_text_region = p_subpic->p_region;
 
-            /* Only overwrite the size fields if the region is still in pre-rendered
-             * TEXT format. We have to traverse the subregion list because if more
-             * than one subregion is present, the text region isn't guarentteed to
-             * be the first in the list, and only text regions use this flag.
-             * All of this effort assists with the rescaling of text that has been
-             * rendered at native resolution, rather than video resolution.
+            /* Only overwrite the size fields if the region is still in
+             * pre-rendered TEXT format. We have to traverse the subregion
+             * list because if more than one subregion is present, the text
+             * region isn't guarentteed to be the first in the list, and
+             * only text regions use this flag. All of this effort assists
+             * with the rescaling of text that has been rendered at native
+             * resolution, rather than video resolution.
              */
             while( p_text_region &&
-                p_text_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') )
+                   ( p_text_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') ) )
             {
                 p_text_region = p_text_region->p_next;
             }
-            if( p_text_region && ((p_text_region->i_align & SUBPICTURE_RENDERED) == 0) )
+
+            if( p_text_region &&
+                ( ( p_text_region->i_align & SUBPICTURE_RENDERED ) == 0 ) )
             {
-                p_spu->p_text->fmt_out.video.i_width =
-                    p_spu->p_text->fmt_out.video.i_visible_width =
-                    p_fmt->i_width;
-                p_spu->p_text->fmt_out.video.i_height =
-                    p_spu->p_text->fmt_out.video.i_visible_height =
-                    p_fmt->i_height;
+                if( (p_subpic->i_original_picture_height > 0) &&
+                    (p_subpic->i_original_picture_width  > 0) )
+                {
+                    p_spu->p_text->fmt_out.video.i_width =
+                        p_spu->p_text->fmt_out.video.i_visible_width =
+                        p_subpic->i_original_picture_width;
+                    p_spu->p_text->fmt_out.video.i_height =
+                        p_spu->p_text->fmt_out.video.i_visible_height =
+                        p_subpic->i_original_picture_height;
+                }
+                else
+                {
+                    p_spu->p_text->fmt_out.video.i_width =
+                        p_spu->p_text->fmt_out.video.i_visible_width =
+                        p_fmt->i_width;
+                    p_spu->p_text->fmt_out.video.i_height =
+                        p_spu->p_text->fmt_out.video.i_visible_height =
+                        p_fmt->i_height;
+                }
             }
         }
 
         pi_scale_width[ SCALE_DEFAULT ]  = i_scale_width_orig;
         pi_scale_height[ SCALE_DEFAULT ] = i_scale_height_orig;
-        pi_scale_width[ SCALE_TEXT ]     = p_fmt->i_width  * 1000 / p_spu->p_text->fmt_out.video.i_width;
-        pi_scale_height[ SCALE_TEXT ]    = p_fmt->i_height * 1000 / p_spu->p_text->fmt_out.video.i_height;
 
-        for( k=0; k< SCALE_SIZE ; k++ )
+        if( p_spu->p_text )
+        {
+            pi_scale_width[ SCALE_TEXT ]     = ( p_fmt->i_width * 1000 ) /
+                                          p_spu->p_text->fmt_out.video.i_width;
+            pi_scale_height[ SCALE_TEXT ]    = ( p_fmt->i_height * 1000 ) /
+                                          p_spu->p_text->fmt_out.video.i_height;
+        }
+        /* If we have an explicit size plane to render to, then turn off
+         * the fontsize rescaling.
+         */
+        if( (p_subpic->i_original_picture_height > 0) &&
+            (p_subpic->i_original_picture_width  > 0) )
+        {
+            i_scale_width_orig  = 1000;
+            i_scale_height_orig = 1000;
+        }
+
+        for( k = 0; k < SCALE_SIZE ; k++ )
         {
+            /* Case of both width and height being specified has been dealt
+             * with above by instead rendering to an output pane of the
+             * explicit dimensions specified - we don't need to scale it.
+             */
             if( (p_subpic->i_original_picture_height > 0) &&
-                (p_subpic->i_original_picture_width  > 0) )
-            {
-                pi_scale_width[ k ]  = pi_scale_width[ k ]  * i_source_video_width /
-                                 p_subpic->i_original_picture_width;
-                pi_scale_height[ k ] = pi_scale_height[ k ] * i_source_video_height /
-                                 p_subpic->i_original_picture_height;
-            }
-            else if( p_subpic->i_original_picture_height > 0 )
+                (p_subpic->i_original_picture_width <= 0) )
             {
                 pi_scale_height[ k ] = pi_scale_height[ k ] * i_source_video_height /
                                  p_subpic->i_original_picture_height;
@@ -630,23 +710,24 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
 
         /* Set default subpicture aspect ratio */
         if( p_region && p_region->fmt.i_aspect &&
-            (!p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den) )
+            ( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den ) )
         {
             p_region->fmt.i_sar_den = p_region->fmt.i_aspect;
             p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR;
         }
         if( p_region &&
-            (!p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den) )
+            ( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den ) )
         {
             p_region->fmt.i_sar_den = p_fmt->i_sar_den;
             p_region->fmt.i_sar_num = p_fmt->i_sar_num;
         }
 
         /* Take care of the aspect ratio */
-        if( p_region && p_region->fmt.i_sar_num * p_fmt->i_sar_den !=
-            p_region->fmt.i_sar_den * p_fmt->i_sar_num )
+        if( p_region &&
+            ( ( p_region->fmt.i_sar_num * p_fmt->i_sar_den ) !=
+              ( p_region->fmt.i_sar_den * p_fmt->i_sar_num ) ) )
         {
-            for( k=0; k< SCALE_SIZE ; k++ )
+            for( k = 0; k < SCALE_SIZE ; k++ )
             {
                 pi_scale_width[ k ] = pi_scale_width[ k ] *
                     (int64_t)p_region->fmt.i_sar_num * p_fmt->i_sar_den /
@@ -667,7 +748,8 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
             p_spu->p_scale->fmt_out.video.i_chroma =
                 p_spu->p_scale->fmt_in.video.i_chroma =
                     VLC_FOURCC('Y','U','V','P');
-            /* XXX: We'll also be using it for YUVA and RGBA blending ... */
+            /* FIXME: We'll also be using it for YUVA and RGBA blending ... */
+
             p_spu->p_scale->fmt_in.video.i_width =
                 p_spu->p_scale->fmt_in.video.i_height = 32;
             p_spu->p_scale->fmt_out.video.i_width =
@@ -679,7 +761,7 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                 module_Need( p_spu->p_scale, "video filter2", 0, 0 );
         }
 
-        while( p_region && p_spu->p_blend && p_spu->p_blend->pf_video_blend )
+        while( p_region )
         {
             video_format_t orig_fmt = p_region->fmt;
             vlc_bool_t b_rerender_text = VLC_FALSE;
@@ -750,6 +832,7 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                 }
                 p_region->i_align |= SUBPICTURE_RENDERED;
             }
+
             if( p_region->i_align & SUBPICTURE_RENDERED )
             {
                 i_scale_idx   = SCALE_TEXT;
@@ -762,14 +845,15 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
 
             /* Force palette if requested */
             if( p_spu->b_force_palette &&
-                (VLC_FOURCC('Y','U','V','P') == p_region->fmt.i_chroma) )
+                ( VLC_FOURCC('Y','U','V','P') == p_region->fmt.i_chroma ) )
             {
                 memcpy( p_region->fmt.p_palette->palette,
                         p_spu->palette, 16 );
             }
 
             /* Scale SPU if necessary */
-            if( p_region->p_cache )
+            if( p_region->p_cache &&
+                ( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') ) )
             {
                 if( pi_scale_width[ i_scale_idx ] * p_region->fmt.i_width / 1000 !=
                     p_region->p_cache->fmt.i_width ||
@@ -782,9 +866,12 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                 }
             }
 
-            if( ((pi_scale_width[ i_scale_idx ] != 1000) || (pi_scale_height[ i_scale_idx ] != 1000)) &&
-                ((pi_scale_width[ i_scale_idx ] > 0) || (pi_scale_height[ i_scale_idx ] > 0)) &&
-                p_spu->p_scale && !p_region->p_cache )
+            if( ( ( pi_scale_width[ i_scale_idx ] != 1000 ) ||
+                  ( pi_scale_height[ i_scale_idx ] != 1000 ) ) &&
+                ( ( pi_scale_width[ i_scale_idx ] > 0 ) ||
+                  ( pi_scale_height[ i_scale_idx ] > 0 ) ) &&
+                p_spu->p_scale && !p_region->p_cache &&
+                ( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') ) )
             {
                 picture_t *p_pic;
 
@@ -825,9 +912,13 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                     free( p_pic );
                 }
             }
-            if( ((pi_scale_width[ i_scale_idx ] != 1000) || (pi_scale_height[ i_scale_idx ] != 1000)) &&
-                ((pi_scale_width[ i_scale_idx ] > 0) || (pi_scale_height[ i_scale_idx ] > 0)) &&
-                p_spu->p_scale && p_region->p_cache )
+
+            if( ( ( pi_scale_width[ i_scale_idx ] != 1000 ) ||
+                  ( pi_scale_height[ i_scale_idx ] != 1000 ) ) &&
+                ( ( pi_scale_width[ i_scale_idx ] > 0 ) ||
+                  ( pi_scale_height[ i_scale_idx ] > 0 ) ) &&
+                p_spu->p_scale && p_region->p_cache &&
+                ( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') )  )
             {
                 p_region = p_region->p_cache;
             }
@@ -868,7 +959,8 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
             i_x_offset = __MAX( i_x_offset, 0 );
             i_y_offset = __MAX( i_y_offset, 0 );
 
-            if( p_spu->i_margin != 0 && p_spu->b_force_crop == VLC_FALSE )
+            if( ( p_spu->i_margin != 0 ) &&
+                ( p_spu->b_force_crop == VLC_FALSE ) )
             {
                 int i_diff = 0;
                 int i_low = (i_y_offset - p_spu->i_margin) * i_inv_scale_y / 1000;
@@ -882,58 +974,6 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                 i_y_offset -= ( p_spu->i_margin * i_inv_scale_y / 1000 + i_diff );
             }
 
-            p_spu->p_blend->fmt_in.video = p_region->fmt;
-
-            /* Force cropping if requested */
-            if( p_spu->b_force_crop )
-            {
-                video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video;
-                int i_crop_x = p_spu->i_crop_x * pi_scale_width[ i_scale_idx ] / 1000
-                                    * i_inv_scale_x / 1000;
-                int i_crop_y = p_spu->i_crop_y * pi_scale_height[ i_scale_idx ] / 1000
-                                    * i_inv_scale_y / 1000;
-                int i_crop_width = p_spu->i_crop_width * pi_scale_width[ i_scale_idx ] / 1000
-                                    * i_inv_scale_x / 1000;
-                int i_crop_height = p_spu->i_crop_height * pi_scale_height[ i_scale_idx ] / 1000
-                                    * i_inv_scale_y / 1000;
-
-                /* Find the intersection */
-                if( i_crop_x + i_crop_width <= i_x_offset ||
-                    i_x_offset + (int)p_fmt->i_visible_width < i_crop_x ||
-                    i_crop_y + i_crop_height <= i_y_offset ||
-                    i_y_offset + (int)p_fmt->i_visible_height < i_crop_y )
-                {
-                    /* No intersection */
-                    p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
-                }
-                else
-                {
-                    int i_x, i_y, i_x_end, i_y_end;
-                    i_x = __MAX( i_crop_x, i_x_offset );
-                    i_y = __MAX( i_crop_y, i_y_offset );
-                    i_x_end = __MIN( i_crop_x + i_crop_width,
-                                   i_x_offset + (int)p_fmt->i_visible_width );
-                    i_y_end = __MIN( i_crop_y + i_crop_height,
-                                   i_y_offset + (int)p_fmt->i_visible_height );
-
-                    p_fmt->i_x_offset = i_x - i_x_offset;
-                    p_fmt->i_y_offset = i_y - i_y_offset;
-                    p_fmt->i_visible_width = i_x_end - i_x;
-                    p_fmt->i_visible_height = i_y_end - i_y;
-
-                    i_x_offset = i_x;
-                    i_y_offset = i_y;
-                }
-            }
-
-            /* Update the output picture size */
-            p_spu->p_blend->fmt_out.video.i_width =
-                p_spu->p_blend->fmt_out.video.i_visible_width =
-                    p_fmt->i_width;
-            p_spu->p_blend->fmt_out.video.i_height =
-                p_spu->p_blend->fmt_out.video.i_visible_height =
-                    p_fmt->i_height;
-
             if( p_subpic->b_fade )
             {
                 mtime_t i_fade_start = ( p_subpic->i_stop +
@@ -946,12 +986,89 @@ void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                 }
             }
 
-            i_x_offset = __MAX( i_x_offset, 0 );
-            i_y_offset = __MAX( i_y_offset, 0 );
+            if( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') )
+            {
+                if( p_spu->p_blend->fmt_in.video.i_chroma != p_region->fmt.i_chroma )
+                {
+                    /* The chroma is not the same, we need to reload the blend module
+                     * XXX to match the old behaviour just test !p_spu->p_blend->fmt_in.video.i_chroma */
+                    if( p_spu->p_blend->p_module )
+                        module_Unneed( p_spu->p_blend, p_spu->p_blend->p_module );
 
-            p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
-                p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
-                i_fade_alpha * p_subpic->i_alpha / 255 );
+                    p_spu->p_blend->fmt_in.video = p_region->fmt;
+                    p_spu->p_blend->p_module = module_Need( p_spu->p_blend, "video blending", 0, 0 );
+                }
+                else
+                {
+                    p_spu->p_blend->fmt_in.video = p_region->fmt;
+                }
+
+                /* Force cropping if requested */
+                if( p_spu->b_force_crop )
+                {
+                    video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video;
+                    int i_crop_x = p_spu->i_crop_x * pi_scale_width[ i_scale_idx ] / 1000
+                                        * i_inv_scale_x / 1000;
+                    int i_crop_y = p_spu->i_crop_y * pi_scale_height[ i_scale_idx ] / 1000
+                                        * i_inv_scale_y / 1000;
+                    int i_crop_width = p_spu->i_crop_width * pi_scale_width[ i_scale_idx ] / 1000
+                                        * i_inv_scale_x / 1000;
+                    int i_crop_height = p_spu->i_crop_height * pi_scale_height[ i_scale_idx ] / 1000
+                                        * i_inv_scale_y / 1000;
+
+                    /* Find the intersection */
+                    if( i_crop_x + i_crop_width <= i_x_offset ||
+                        i_x_offset + (int)p_fmt->i_visible_width < i_crop_x ||
+                        i_crop_y + i_crop_height <= i_y_offset ||
+                        i_y_offset + (int)p_fmt->i_visible_height < i_crop_y )
+                    {
+                        /* No intersection */
+                        p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
+                    }
+                    else
+                    {
+                        int i_x, i_y, i_x_end, i_y_end;
+                        i_x = __MAX( i_crop_x, i_x_offset );
+                        i_y = __MAX( i_crop_y, i_y_offset );
+                        i_x_end = __MIN( i_crop_x + i_crop_width,
+                                       i_x_offset + (int)p_fmt->i_visible_width );
+                        i_y_end = __MIN( i_crop_y + i_crop_height,
+                                       i_y_offset + (int)p_fmt->i_visible_height );
+
+                        p_fmt->i_x_offset = i_x - i_x_offset;
+                        p_fmt->i_y_offset = i_y - i_y_offset;
+                        p_fmt->i_visible_width = i_x_end - i_x;
+                        p_fmt->i_visible_height = i_y_end - i_y;
+
+                        i_x_offset = i_x;
+                        i_y_offset = i_y;
+                    }
+                }
+
+                i_x_offset = __MAX( i_x_offset, 0 );
+                i_y_offset = __MAX( i_y_offset, 0 );
+
+                /* Update the output picture size */
+                p_spu->p_blend->fmt_out.video.i_width =
+                    p_spu->p_blend->fmt_out.video.i_visible_width =
+                        p_fmt->i_width;
+                p_spu->p_blend->fmt_out.video.i_height =
+                    p_spu->p_blend->fmt_out.video.i_visible_height =
+                        p_fmt->i_height;
+
+                if( p_spu->p_blend->p_module )
+                {
+                    p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
+                        p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
+                        i_fade_alpha * p_subpic->i_alpha / 255 );
+                }
+                else
+                {
+                    msg_Err( p_spu, "blending %4.4s to %4.4s failed",
+                             (char *)&p_spu->p_blend->fmt_out.video.i_chroma,
+                             (char *)&p_spu->p_blend->fmt_out.video.i_chroma );
+                }
+            }
 
             if( b_rerender_text )
             {
@@ -1218,8 +1335,9 @@ static void sub_del_buffer( filter_t *p_filter, subpicture_t *p_subpic )
 
 static subpicture_t *spu_new_buffer( filter_t *p_filter )
 {
-    subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t));
     (void)p_filter;
+    subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t));
+    if( !p_subpic ) return NULL;
     memset( p_subpic, 0, sizeof(subpicture_t) );
     p_subpic->b_absolute = VLC_TRUE;
 
@@ -1245,7 +1363,7 @@ static void spu_del_buffer( filter_t *p_filter, subpicture_t *p_subpic )
 static picture_t *spu_new_video_buffer( filter_t *p_filter )
 {
     picture_t *p_picture = malloc( sizeof(picture_t) );
-
+    if( !p_picture ) return NULL;
     if( vout_AllocatePicture( p_filter, p_picture,
                               p_filter->fmt_out.video.i_chroma,
                               p_filter->fmt_out.video.i_width,
@@ -1265,8 +1383,11 @@ static picture_t *spu_new_video_buffer( filter_t *p_filter )
 static void spu_del_video_buffer( filter_t *p_filter, picture_t *p_pic )
 {
     (void)p_filter;
-    if( p_pic && p_pic->p_data_orig ) free( p_pic->p_data_orig );
-    if( p_pic ) free( p_pic );
+    if( p_pic )
+    {
+        if( p_pic->p_data_orig ) free( p_pic->p_data_orig );
+        free( p_pic );
+    }
 }
 
 static int SubFilterCallback( vlc_object_t *p_object, char const *psz_var,
@@ -1274,13 +1395,10 @@ static int SubFilterCallback( vlc_object_t *p_object, char const *psz_var,
 {
     (void)p_object; (void)oldval; (void)newval;
 
-    if( !strcmp( psz_var, "sub-filter" ) )
-    {
-        spu_t *p_spu = (spu_t *)p_data;
-        vlc_mutex_lock( &p_spu->subpicture_lock );
-        spu_DeleteChain( p_spu );
-        spu_ParseChain( p_spu );
-        vlc_mutex_unlock( &p_spu->subpicture_lock );
-    }
+    spu_t *p_spu = (spu_t *)p_data;
+    vlc_mutex_lock( &p_spu->subpicture_lock );
+    spu_DeleteChain( p_spu );
+    spu_ParseChain( p_spu );
+    vlc_mutex_unlock( &p_spu->subpicture_lock );
     return VLC_SUCCESS;
 }