From 1374a69a5672071424e2af15bf8e281db7a6e126 Mon Sep 17 00:00:00 2001 From: Gildas Bazin Date: Fri, 13 Aug 2004 18:58:25 +0000 Subject: [PATCH] * 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. --- include/vlc_common.h | 22 +++++++- include/vlc_es.h | 2 +- modules/codec/spudec/parse.c | 88 ++++++++++++++++++++++++++--- modules/codec/spudec/spudec.h | 5 ++ modules/video_filter/blend.c | 2 +- src/video_output/vout_subpictures.c | 39 ++++++++++--- 6 files changed, 140 insertions(+), 18 deletions(-) diff --git a/include/vlc_common.h b/include/vlc_common.h index c330482765..e748ae2759 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -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 ) diff --git a/include/vlc_es.h b/include/vlc_es.h index c82b2736dd..a47c0f66b0 100644 --- a/include/vlc_es.h +++ b/include/vlc_es.h @@ -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 */ }; diff --git a/modules/codec/spudec/parse.c b/modules/codec/spudec/parse.c index c8f50ba5df..983401d2b0 100644 --- a/modules/codec/spudec/parse.c +++ b/modules/codec/spudec/parse.c @@ -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; diff --git a/modules/codec/spudec/spudec.h b/modules/codec/spudec/spudec.h index 157481d5b8..123ca86654 100644 --- a/modules/codec/spudec/spudec.h +++ b/modules/codec/spudec/spudec.h @@ -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; /***************************************************************************** diff --git a/modules/video_filter/blend.c b/modules/video_filter/blend.c index abc0fde931..3e904cac21 100644 --- a/modules/video_filter/blend.c +++ b/modules/video_filter/blend.c @@ -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] ); diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c index f37a932527..70761d6be0 100644 --- a/src/video_output/vout_subpictures.c +++ b/src/video_output/vout_subpictures.c @@ -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 */ -- 2.39.2