]> git.sesse.net Git - vlc/commitdiff
* modules/codec/spudec/*: automatic cropping of fullscreen subpictures (most of them...
authorGildas Bazin <gbazin@videolan.org>
Fri, 13 Aug 2004 18:58:25 +0000 (18:58 +0000)
committerGildas Bazin <gbazin@videolan.org>
Fri, 13 Aug 2004 18:58:25 +0000 (18:58 +0000)
* src/video_output/vout_subpictures.c: more correct cropping (cropping coordinates are relative to the video size, not subpicture size).
* include/vlc_es.h, modules/video_filter/blend.c: use the i_entries member of video_palette_t.
* include/vlc_common.h: added SetWBE()/SetDWBE()/SetQWBE() facility.

include/vlc_common.h
include/vlc_es.h
modules/codec/spudec/parse.c
modules/codec/spudec/spudec.h
modules/video_filter/blend.c
src/video_output/vout_subpictures.c

index c330482765c4328d830a8851883827b32b14561d..e748ae2759678dec7400d99d638a275ff7ee69d1 100644 (file)
@@ -608,7 +608,6 @@ static inline uint64_t GetQWLE( void const * _p )
 #define GetQWBE( p )    U64_AT( p )
 
 /* Helper writer functions */
-
 #define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v)
 static inline void _SetWLE( uint8_t *p, uint16_t i_dw )
 {
@@ -630,6 +629,27 @@ static inline void _SetQWLE( uint8_t *p, uint64_t i_qw )
     SetDWLE( p,   i_qw&0xffffffff );
     SetDWLE( p+4, ( i_qw >> 32)&0xffffffff );
 }
+#define SetWBE( p, v ) _SetWBE( (uint8_t*)p, v)
+static inline void _SetWBE( uint8_t *p, uint16_t i_dw )
+{
+    p[0] = ( i_dw >>  8 )&0xff;
+    p[1] = ( i_dw       )&0xff;
+}
+
+#define SetDWBE( p, v ) _SetDWBE( (uint8_t*)p, v)
+static inline void _SetDWBE( uint8_t *p, uint32_t i_dw )
+{
+    p[0] = ( i_dw >> 24 )&0xff;
+    p[1] = ( i_dw >> 16 )&0xff;
+    p[2] = ( i_dw >>  8 )&0xff;
+    p[3] = ( i_dw       )&0xff;
+}
+#define SetQWBE( p, v ) _SetQWBE( (uint8_t*)p, v)
+static inline void _SetQWBE( uint8_t *p, uint64_t i_qw )
+{
+    SetDWBE( p+4,   i_qw&0xffffffff );
+    SetDWBE( p, ( i_qw >> 32)&0xffffffff );
+}
 
 #if WORDS_BIGENDIAN
 #   define hton16(i)   ( i )
index c82b2736ddd2a11841d2a1cb80fcd6965f472837..a47c0f66b012c080d5acfb17c10568db250ef3be 100644 (file)
@@ -36,7 +36,7 @@
  */
 struct video_palette_t
 {
-    int i_dummy;        /**< to keep the compatibility with ffmpeg's palette */
+    int i_entries;      /**< to keep the compatibility with ffmpeg's palette */
     uint8_t palette[256][4];                   /**< 4-byte RGBA/YUVA palette */
 };
 
index c8f50ba5df1ebd5139f3c0884fe735e53c5313e2..983401d2b033362e4646842e88ed59e0ad360ee9 100644 (file)
@@ -78,6 +78,9 @@ subpicture_t * E_(ParsePacket)( decoder_t *p_dec )
     p_spu_data = malloc( sizeof(subpicture_data_t) + 4 * p_sys->i_rle_size );
     p_spu_data->p_data = (uint8_t *)p_spu_data + sizeof(subpicture_data_t);
     p_spu_data->b_palette = VLC_FALSE;
+    p_spu_data->b_auto_crop = VLC_FALSE;
+    p_spu_data->i_y_top_offset = 0;
+    p_spu_data->i_y_bottom_offset = 0;
 
     p_spu_data->pi_alpha[0] = 0x00;
     p_spu_data->pi_alpha[1] = 0x0f;
@@ -249,7 +252,11 @@ static int ParseControlSeq( decoder_t *p_dec, subpicture_t *p_spu,
                          ((p_sys->buffer[i_index+4]>>4)&0x0f);
             p_spu->i_height = (((p_sys->buffer[i_index+4]&0x0f)<<8)|
                               p_sys->buffer[i_index+5]) - p_spu->i_y + 1;
-            
+
+            /* Auto crop fullscreen subtitles */
+            if( p_spu->i_height > 250 )
+                p_spu_data->b_auto_crop = VLC_TRUE;
+
             i_index += 6;
             break;
 
@@ -342,6 +349,11 @@ static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu,
     unsigned int  pi_table[ 2 ];
     unsigned int *pi_offset;
 
+    /* Cropping */
+    vlc_bool_t b_empty_top = VLC_TRUE;
+    unsigned int i_skipped_top = 0, i_skipped_bottom = 0;
+    unsigned int i_transparent_code = 0;
     /* Colormap statistics */
     int i_border = -1;
     int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0;
@@ -403,7 +415,54 @@ static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu,
                 stats[i_border] += i_code >> 2;
             }
 
-            *p_dest++ = i_code;
+            /* Auto crop subtitles (a lot more optimized) */
+            if( p_spu_data->b_auto_crop )
+            {
+                if( !i_y )
+                {
+                    /* We assume that if the first line is transparent, then
+                     * it is using the palette index for the
+                     * (background) transparent color */
+                    if( (i_code >> 2) == i_width &&
+                        p_spu_data->pi_alpha[ i_code & 0x3 ] == 0x00 )
+                    {
+                        i_transparent_code = i_code;
+                    }
+                    else
+                    {
+                        p_spu_data->b_auto_crop = VLC_FALSE;
+                    }
+                }
+
+                if( i_code == i_transparent_code )
+                {
+                    if( b_empty_top )
+                    {
+                        /* This is a blank top line, we skip it */
+                      i_skipped_top++;
+                    }
+                    else
+                    {
+                        /* We can't be sure the current lines will be skipped,
+                         * so we store the code just in case. */
+                      *p_dest++ = i_code;
+                      i_skipped_bottom++;
+                    }
+                }
+                else
+                {
+                    /* We got a valid code, store it */
+                    *p_dest++ = i_code;
+
+                    /* Valid code means no blank line */
+                    b_empty_top = VLC_FALSE;
+                    i_skipped_bottom = 0;
+                }
+            }
+            else
+            {
+                *p_dest++ = i_code;
+            }
         }
 
         /* Check that we didn't go too far */
@@ -443,6 +502,18 @@ static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu,
     msg_Dbg( p_dec, "valid subtitle, size: %ix%i, position: %i,%i",
              p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
 
+    /* Crop if necessary */
+    if( i_skipped_top || i_skipped_bottom )
+    {
+        int i_y = p_spu->i_y + i_skipped_top;
+        int i_height = p_spu->i_height - (i_skipped_top + i_skipped_bottom);
+
+        p_spu_data->i_y_top_offset = i_skipped_top;
+        p_spu_data->i_y_bottom_offset = i_skipped_bottom;
+        msg_Dbg( p_dec, "cropped to: %ix%i, position: %i,%i",
+                 p_spu->i_width, i_height, p_spu->i_x, i_y );
+    }
     /* Handle color if no palette was found */
     if( !p_spu_data->b_palette )
     {
@@ -515,7 +586,8 @@ static void Render( decoder_t *p_dec, subpicture_t *p_spu,
     fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
     fmt.i_aspect = VOUT_ASPECT_FACTOR;
     fmt.i_width = fmt.i_visible_width = p_spu->i_width;
-    fmt.i_height = fmt.i_visible_height = p_spu->i_height;
+    fmt.i_height = fmt.i_visible_height = p_spu->i_height -
+        p_spu_data->i_y_top_offset - p_spu_data->i_y_bottom_offset;
     fmt.i_x_offset = fmt.i_y_offset = 0;
     p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
     if( !p_spu->p_region )
@@ -524,12 +596,14 @@ static void Render( decoder_t *p_dec, subpicture_t *p_spu,
         return;
     }
 
-    p_spu->p_region->i_x = p_spu->p_region->i_y = 0;
+    p_spu->p_region->i_x = 0;
+    p_spu->p_region->i_y = p_spu_data->i_y_top_offset;
     p_p = p_spu->p_region->picture.p->p_pixels;
     i_pitch = p_spu->p_region->picture.p->i_pitch;
 
     /* Build palette */
-    for( i_x = 0; i_x < 4; i_x++ )
+    fmt.p_palette->i_entries = 4;
+    for( i_x = 0; i_x < fmt.p_palette->i_entries; i_x++ )
     {
         fmt.p_palette->palette[i_x][0] = p_spu_data->pi_yuv[i_x][0];
         fmt.p_palette->palette[i_x][1] = p_spu_data->pi_yuv[i_x][1];
@@ -540,10 +614,10 @@ static void Render( decoder_t *p_dec, subpicture_t *p_spu,
     }
 
     /* Draw until we reach the bottom of the subtitle */
-    for( i_y = 0; i_y < p_spu->i_height * i_pitch; i_y += i_pitch )
+    for( i_y = 0; i_y < (int)fmt.i_height * i_pitch; i_y += i_pitch )
     {
         /* Draw until we reach the end of the line */
-        for( i_x = 0 ; i_x < p_spu->i_width; i_x += i_len )
+        for( i_x = 0 ; i_x < (int)fmt.i_width; i_x += i_len )
         {
             /* Get the RLE part, then draw the line */
             i_color = *p_source & 0x3;
index 157481d5b87164f86233bf3c66a1d2c365b4c3af..123ca86654283932e59c136da8b734e9a67c032d 100644 (file)
@@ -48,6 +48,11 @@ typedef struct subpicture_data_t
     uint8_t    pi_alpha[4];
     uint8_t    pi_yuv[4][3];
 
+    /* Auto crop fullscreen subtitles */
+    vlc_bool_t b_auto_crop;
+    int i_y_top_offset;
+    int i_y_bottom_offset;
+
 } subpicture_data_t;
 
 /*****************************************************************************
index abc0fde931b317f22ab605236829879177f76f30..3e904cac2170938fc6ec6a61f151a173a780f4ee 100644 (file)
@@ -824,7 +824,7 @@ static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
 #define rgbpal rgbpalette.palette
 
     /* Convert palette first */
-    for( i_y = 0; //i_y < p_filter->fmt_in.video.p_palette->i_dummy &&
+    for( i_y = 0; i_y < p_filter->fmt_in.video.p_palette->i_entries &&
          i_y < 256; i_y++ )
     {
         yuv_to_rgb( &r, &g, &b, p_pal[i_y][0], p_pal[i_y][1], p_pal[i_y][2] );
index f37a9325272c6cf6228379767f4e308dcb19b2a3..70761d6be0c9e0b242942b4ebbea3bce203afc83 100644 (file)
@@ -433,14 +433,37 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst,
             /* Force cropping if requested */
             if( p_vout->b_force_crop )
             {
-                p_vout->p_blend->fmt_in.video.i_x_offset = p_vout->i_crop_x;
-                p_vout->p_blend->fmt_in.video.i_y_offset = p_vout->i_crop_y;
-                p_vout->p_blend->fmt_in.video.i_visible_width =
-                    p_vout->i_crop_width;
-                p_vout->p_blend->fmt_in.video.i_visible_height =
-                    p_vout->i_crop_height;
-                i_x_offset += p_vout->i_crop_x;
-                i_y_offset += p_vout->i_crop_y;
+                video_format_t *p_fmt = &p_vout->p_blend->fmt_in.video;
+
+                /* Find the intersection */
+                if( p_vout->i_crop_x + p_vout->i_crop_width <= i_x_offset ||
+                    i_x_offset + (int)p_fmt->i_visible_width <
+                        p_vout->i_crop_x ||
+                    p_vout->i_crop_y + p_vout->i_crop_height <= i_y_offset ||
+                    i_y_offset + (int)p_fmt->i_visible_height <
+                        p_vout->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( p_vout->i_crop_x, i_x_offset );
+                    i_y = __MAX( p_vout->i_crop_y, i_y_offset );
+                    i_x_end = __MIN( p_vout->i_crop_x + p_vout->i_crop_width,
+                                   i_x_offset + (int)p_fmt->i_visible_width );
+                    i_y_end = __MIN( p_vout->i_crop_y + p_vout->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;
+                }
             }
 
             /* Force palette if requested */