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 ) ...@@ -608,7 +608,6 @@ static inline uint64_t GetQWLE( void const * _p )
#define GetQWBE( p ) U64_AT( p ) #define GetQWBE( p ) U64_AT( p )
/* Helper writer functions */ /* Helper writer functions */
#define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v) #define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v)
static inline void _SetWLE( uint8_t *p, uint16_t i_dw ) 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 ) ...@@ -630,6 +629,27 @@ static inline void _SetQWLE( uint8_t *p, uint64_t i_qw )
SetDWLE( p, i_qw&0xffffffff ); SetDWLE( p, i_qw&0xffffffff );
SetDWLE( p+4, ( i_qw >> 32)&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 #if WORDS_BIGENDIAN
# define hton16(i) ( i ) # define hton16(i) ( i )
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
*/ */
struct video_palette_t 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 */ uint8_t palette[256][4]; /**< 4-byte RGBA/YUVA palette */
}; };
......
...@@ -78,6 +78,9 @@ subpicture_t * E_(ParsePacket)( decoder_t *p_dec ) ...@@ -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 = 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->p_data = (uint8_t *)p_spu_data + sizeof(subpicture_data_t);
p_spu_data->b_palette = VLC_FALSE; 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[0] = 0x00;
p_spu_data->pi_alpha[1] = 0x0f; p_spu_data->pi_alpha[1] = 0x0f;
...@@ -249,7 +252,11 @@ static int ParseControlSeq( decoder_t *p_dec, subpicture_t *p_spu, ...@@ -249,7 +252,11 @@ static int ParseControlSeq( decoder_t *p_dec, subpicture_t *p_spu,
((p_sys->buffer[i_index+4]>>4)&0x0f); ((p_sys->buffer[i_index+4]>>4)&0x0f);
p_spu->i_height = (((p_sys->buffer[i_index+4]&0x0f)<<8)| p_spu->i_height = (((p_sys->buffer[i_index+4]&0x0f)<<8)|
p_sys->buffer[i_index+5]) - p_spu->i_y + 1; 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; i_index += 6;
break; break;
...@@ -342,6 +349,11 @@ static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu, ...@@ -342,6 +349,11 @@ static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu,
unsigned int pi_table[ 2 ]; unsigned int pi_table[ 2 ];
unsigned int *pi_offset; 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 */ /* Colormap statistics */
int i_border = -1; int i_border = -1;
int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0; 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, ...@@ -403,7 +415,54 @@ static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu,
stats[i_border] += i_code >> 2; 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 */ /* Check that we didn't go too far */
...@@ -443,6 +502,18 @@ static int ParseRLE( decoder_t *p_dec, subpicture_t * p_spu, ...@@ -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", 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 ); 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 */ /* Handle color if no palette was found */
if( !p_spu_data->b_palette ) if( !p_spu_data->b_palette )
{ {
...@@ -515,7 +586,8 @@ static void Render( decoder_t *p_dec, subpicture_t *p_spu, ...@@ -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_chroma = VLC_FOURCC('Y','U','V','P');
fmt.i_aspect = VOUT_ASPECT_FACTOR; fmt.i_aspect = VOUT_ASPECT_FACTOR;
fmt.i_width = fmt.i_visible_width = p_spu->i_width; 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; fmt.i_x_offset = fmt.i_y_offset = 0;
p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt ); p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
if( !p_spu->p_region ) if( !p_spu->p_region )
...@@ -524,12 +596,14 @@ static void Render( decoder_t *p_dec, subpicture_t *p_spu, ...@@ -524,12 +596,14 @@ static void Render( decoder_t *p_dec, subpicture_t *p_spu,
return; 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; p_p = p_spu->p_region->picture.p->p_pixels;
i_pitch = p_spu->p_region->picture.p->i_pitch; i_pitch = p_spu->p_region->picture.p->i_pitch;
/* Build palette */ /* 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][0] = p_spu_data->pi_yuv[i_x][0];
fmt.p_palette->palette[i_x][1] = p_spu_data->pi_yuv[i_x][1]; 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, ...@@ -540,10 +614,10 @@ static void Render( decoder_t *p_dec, subpicture_t *p_spu,
} }
/* Draw until we reach the bottom of the subtitle */ /* 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 */ /* 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 */ /* Get the RLE part, then draw the line */
i_color = *p_source & 0x3; i_color = *p_source & 0x3;
......
...@@ -48,6 +48,11 @@ typedef struct subpicture_data_t ...@@ -48,6 +48,11 @@ typedef struct subpicture_data_t
uint8_t pi_alpha[4]; uint8_t pi_alpha[4];
uint8_t pi_yuv[4][3]; 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; } subpicture_data_t;
/***************************************************************************** /*****************************************************************************
......
...@@ -824,7 +824,7 @@ static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic, ...@@ -824,7 +824,7 @@ static void BlendPalRV( filter_t *p_filter, picture_t *p_dst_pic,
#define rgbpal rgbpalette.palette #define rgbpal rgbpalette.palette
/* Convert palette first */ /* 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++ ) 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] ); 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, ...@@ -433,14 +433,37 @@ void vout_RenderSubPictures( vout_thread_t *p_vout, picture_t *p_pic_dst,
/* Force cropping if requested */ /* Force cropping if requested */
if( p_vout->b_force_crop ) if( p_vout->b_force_crop )
{ {
p_vout->p_blend->fmt_in.video.i_x_offset = p_vout->i_crop_x; video_format_t *p_fmt = &p_vout->p_blend->fmt_in.video;
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 = /* Find the intersection */
p_vout->i_crop_width; if( p_vout->i_crop_x + p_vout->i_crop_width <= i_x_offset ||
p_vout->p_blend->fmt_in.video.i_visible_height = i_x_offset + (int)p_fmt->i_visible_width <
p_vout->i_crop_height; p_vout->i_crop_x ||
i_x_offset += p_vout->i_crop_x; p_vout->i_crop_y + p_vout->i_crop_height <= i_y_offset ||
i_y_offset += p_vout->i_crop_y; 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 */ /* 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