Commit 1374a69a authored by Gildas Bazin's avatar Gildas Bazin

* modules/codec/spudec/*: automatic cropping of fullscreen subpictures (most...

* modules/codec/spudec/*: automatic cropping of fullscreen subpictures (most of them contain large transparent areas).
* 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.
parent cb047ed8
......@@ -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 )
......
......@@ -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 */
};
......
......@@ -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;
......@@ -250,6 +253,10 @@ static int ParseControlSeq( decoder_t *p_dec, subpicture_t *p_spu,
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,8 +415,55 @@ static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu,
stats[i_border] += i_code >> 2;
}
/* 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 */
if( i_x > i_width )
......@@ -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;
......
......@@ -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;
/*****************************************************************************
......
......@@ -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] );
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment