chroma does the scaling.
* Common SVCD and VCD subtitle routines.
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
- * $Id: common.c,v 1.5 2004/01/11 01:54:20 rocky Exp $
+ * $Id: common.c,v 1.6 2004/01/14 11:47:19 rocky Exp $
*
* Author: Rocky Bernstein
* based on code from:
for ( ; n >= 0 ; n-- ) {
p_to[n] = p_sys->p_palette[p_from[n]];
+ /*p_to[n] = p_sys->p_palette[p_from[3]];*/
}
}
}
+/* The video may be scaled. However subtitle bitmaps assume an 1:1
+ aspect ratio. So unless the user has specified otherwise, we
+ need to scale to compensate for or undo the effects of video
+ output scaling.
+
+ Perhaps this should go in the Render routine? The advantage would
+ be that it will deal with a dynamically changing aspect ratio.
+ The downside is having to scale many times for each render call.
+*/
+
+void
+VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec )
+{
+ vlc_object_t * p_input = p_spu->p_sys->p_input;
+ vout_thread_t *p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT,
+ FIND_CHILD );
+ unsigned int i_aspect_x, i_aspect_y;
+ if (p_vout) {
+ /* Check for user-configuration override. */
+ unsigned int i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
+ if (i_new_aspect == VOUT_ASPECT_FACTOR) {
+ /* For scaling 1:1, nothing needs to be done. Note this means
+ subtitles will get scaled the same way the video does.
+ */
+ ;
+ } else {
+ if (0 == i_new_aspect) {
+ /* Counteract the effects of background video scaling when
+ there is scaling. That's why x and y are reversed from
+ the else branch in the call below.
+ */
+ switch( p_vout->output.i_chroma )
+ {
+ /* chromas which are not scaled: */
+ case VLC_FOURCC('I','4','2','0'):
+ case VLC_FOURCC('I','Y','U','V'):
+ case VLC_FOURCC('Y','V','1','2'):
+ case VLC_FOURCC('Y','U','Y','2'):
+ return;
+ break;
+
+ /* chromas which are scaled: */
+ case VLC_FOURCC('R','V','1','6'):
+ case VLC_FOURCC('R','V','2','4'):
+ case VLC_FOURCC('R','V','3','2'):
+ case VLC_FOURCC('R','G','B','2'):
+ break;
+
+ default:
+ msg_Err( p_vout, "unknown chroma %x",
+ p_vout->output.i_chroma );
+ return;
+ break;
+ }
+ /* We get here only for scaled chromas. */
+ vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
+ &i_aspect_x );
+ } else {
+ /* User knows best? */
+ vout_AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y );
+ }
+ VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
+ }
+ }
+}
+
+
/**
* DestroySPU: subpicture destructor
*/
* Header for Common SVCD and VCD subtitle routines.
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
- * $Id: common.h,v 1.4 2004/01/11 01:54:20 rocky Exp $
+ * $Id: common.h,v 1.5 2004/01/14 11:47:19 rocky Exp $
*
* Author: Rocky Bernstein
*
uint32_t buf_len );
vout_thread_t *VCDSubFindVout( decoder_t *p_dec );
+void VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec ) ;
+
+
void VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
unsigned int i_scale_x, unsigned int i_scale_y );
* cvd.c : CVD Subtitle decoder thread
*****************************************************************************
* Copyright (C) 2003 VideoLAN
- * $Id: cvd.c,v 1.9 2004/01/11 01:54:20 rocky Exp $
+ * $Id: cvd.c,v 1.10 2004/01/14 11:47:19 rocky Exp $
*
* Authors: Rocky Bernstein
* based on code from:
SUB_ASPECT_RATIO_TEXT, SUB_ASPECT_RATIO_LONGTEXT,
VLC_TRUE );
+ add_integer( MODULE_STRING "-duration-scaling", 9, NULL,
+ DURATION_SCALE_TEXT, DURATION_SCALE_LONGTEXT,
+ VLC_TRUE );
+
add_submodule();
set_description( _("Chaoji VCD subtitle packetizer") );
set_capability( "packetizer", 50 );
* parse.c: Philips OGT (SVCD subtitle) packet parser
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
- * $Id: cvd_parse.c,v 1.10 2004/01/11 01:54:20 rocky Exp $
+ * $Id: cvd_parse.c,v 1.11 2004/01/14 11:47:19 rocky Exp $
*
* Authors: Rocky Bernstein
* based on code from:
switch ( p[0] ) {
case 0x04: /* subtitle duration in 1/90000ths of a second */
+ {
+ mtime_t i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
+ mtime_t i_duration_scale = config_GetInt( p_dec, MODULE_STRING
+ "-duration-scaling" );
+
+ dbg_print( DECODE_DBG_PACKET,
+ "subtitle display duration %lu secs (scaled %lu secs)",
+ (long unsigned int) (i_duration / 90000),
+ (long unsigned int) (i_duration * i_duration_scale / 90000)
+ );
+ p_sys->i_duration = i_duration * i_duration_scale ;
+ break;
+ }
- p_sys->i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
-
- dbg_print( DECODE_DBG_PACKET,
- "subtitle display duration %u", p_sys->i_duration);
- break;
case 0x0c: /* unknown */
dbg_print( DECODE_DBG_PACKET,
#endif /*HAVE_LIBPNG*/
VCDInlinePalette( p_dest, p_sys, i_height, i_width );
-
- /* The video may be scaled. However subtitle bitmaps assume an 1:1
- aspect ratio. So unless the user has specified otherwise, we
- need to scale to compensate for or undo the effects of video
- output scaling.
-
- Perhaps this should go in the Render routine? The advantage would
- be that it will deal with a dynamically changing aspect ratio.
- The downside is having to scale many times for each render call.
- */
-
- {
- vlc_object_t * p_input = p_spu->p_sys->p_input;
- vout_thread_t *p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT,
- FIND_CHILD );
- unsigned int i_aspect_x, i_aspect_y;
- if (p_vout) {
- /* Check for user-configuration override. */
- unsigned int i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
- if (i_new_aspect == VOUT_ASPECT_FACTOR) {
- /* For scaling 1:1, nothing needs to be done. Note this means
- subtitles will get scaled the same way the video does.
- */
- ;
- } else {
- if (0 == i_new_aspect) {
- /* Counteract the effects of background video
- scaling. That's why x and y are reversed from the
- else branch in the call below.
- */
- vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
- &i_aspect_x );
- } else {
- /* User knows best? */
- vout_AspectRatio( i_new_aspect, &i_aspect_y, &i_aspect_x );
- }
- VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
- }
- }
- }
+ VCDSubHandleScaling( p_spu, p_dec );
return VLC_SUCCESS;
* ogt.c : Overlay Graphics Text (SVCD subtitles) decoder thread
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
- * $Id: ogt.c,v 1.9 2004/01/11 01:54:20 rocky Exp $
+ * $Id: ogt.c,v 1.10 2004/01/14 11:47:19 rocky Exp $
*
* Author: Rocky Bernstein
* based on code from:
SUB_ASPECT_RATIO_TEXT, SUB_ASPECT_RATIO_LONGTEXT,
VLC_TRUE );
+ add_integer( MODULE_STRING "-duration-scaling", 9, NULL,
+ DURATION_SCALE_TEXT, DURATION_SCALE_LONGTEXT,
+ VLC_TRUE );
+
add_submodule();
set_description( _("Philips OGT (SVCD subtitle) packetizer") );
set_capability( "packetizer", 50 );
* Philips OGT (SVCD subtitle) packet parser
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
- * $Id: ogt_parse.c,v 1.8 2004/01/11 01:54:20 rocky Exp $
+ * $Id: ogt_parse.c,v 1.9 2004/01/14 11:47:19 rocky Exp $
*
* Author: Rocky Bernstein
* based on code from:
decoder_sys_t *p_sys = p_dec->p_sys;
uint8_t *p = p_buffer;
int i;
-
+
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
p_sys->i_pts = p_block->i_pts;
if ( p_sys->i_options & 0x08 ) {
p_sys->i_duration = GETINT32(p);
+ p_sys->i_duration *= config_GetInt( p_dec, MODULE_STRING
+ "-duration-scaling" );
} else {
/* 0 means display until next subtitle comes in. */
p_sys->i_duration = 0;
if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
- "spu size: %d, duration: %u (d:%d p:%d)",
+ "spu size: %d, duration: %lu (d:%d p:%d)",
p_sys->i_x_start, p_sys->i_y_start,
p_sys->i_width, p_sys->i_height,
- p_sys->i_spu_size, p_sys->i_duration,
+ p_sys->i_spu_size, (long unsigned int) p_sys->i_duration,
p_sys->i_image_length, p_sys->i_image_offset);
for (i=0; i<4; i++) {
p_spu->i_height = p_sys->i_height;
p_spu->i_start = p_sys->i_pts;
- p_spu->i_stop = p_sys->i_pts + (p_sys->i_duration * 10);
+ p_spu->i_stop = p_sys->i_pts + p_sys->i_duration;
p_spu->p_sys->b_crop = VLC_FALSE;
p_spu->p_sys->i_debug = p_sys->i_debug;
#endif /*HAVE_LIBPNG*/
VCDInlinePalette( p_dest, p_sys, i_height, i_width );
-
- /* The video may be scaled. However subtitle bitmaps assume an 1:1
- aspect ratio. So unless the user has specified otherwise, we
- need to scale to compensate for or undo the effects of video
- output scaling.
-
- Perhaps this should go in the Render routine? The advantage would
- be that it will deal with a dynamically changing aspect ratio.
- The downside is having to scale many times for each render call.
- */
-
- {
- vlc_object_t * p_input = p_spu->p_sys->p_input;
- vout_thread_t *p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT,
- FIND_CHILD );
- unsigned int i_aspect_x, i_aspect_y;
- if (p_vout) {
- /* Check for user-configuration override. */
- unsigned int i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
- if (i_new_aspect == VOUT_ASPECT_FACTOR) {
- /* For scaling 1:1, nothing needs to be done. Note this means
- subtitles will get scaled the same way the video does.
- */
- ;
- } else {
- if (0 == i_new_aspect) {
- /* Counteract the effects of background video
- scaling. That's why x and y are reversed from the
- else branch in the call below.
- */
- vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
- &i_aspect_x );
- } else {
- /* User knows best? */
- vout_AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y );
- }
- VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
- }
- }
- }
-
+ VCDSubHandleScaling( p_spu, p_dec );
return VLC_SUCCESS;
}
* render.c : Philips OGT (SVCD Subtitle) renderer
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
- * $Id: render.c,v 1.12 2004/01/14 04:50:02 rocky Exp $
+ * $Id: render.c,v 1.13 2004/01/14 11:47:19 rocky Exp $
*
* Author: Rocky Bernstein
* based on code from:
ogt_yuvt_t *p_source;
int i_x, i_y;
- const uint16_t i_spu_width = p_spu->i_width;
/* Crop-specific */
int i_x_start, i_y_start, i_x_end, i_y_end;
/* Draw until we reach the bottom of the subtitle */
for( i_y = 0;
- i_y < p_spu->i_height * p_pic->p->i_pitch;
- i_y += p_pic->p->i_pitch )
+ i_y < p_spu->i_height * p_pic->p[Y_PLANE].i_pitch ;
+ i_y += p_pic->p[Y_PLANE].i_pitch )
{
uint8_t *p_pixel_base_y = p_pixel_base + i_y;
/* Draw until we reach the end of the line */
- for( ; i_x < i_spu_width; i_x++, p_source++ )
+ for( ; i_x < p_spu->i_width; i_x++, p_source++ )
{
if( b_crop ) {
/* Force v in the range 0.255 */
static inline uint8_t
-clip_8_bit(int v)
+clip_5_bit(int v)
{
if (v<0) return 0;
- if (v>255) return 255;
+ if (v>31) return 31;
return (uint8_t) v;
}
int i_green = (1.1644 * i_Y) - (0.3918 * i_Cb) - (0.8130 * i_Cr);
int i_blue = (1.1644 * i_Y) + (2.0172 * i_Cb);
- i_red = clip_8_bit( i_red ) >> 3;
- i_green = clip_8_bit( i_green ) >> 3;
- i_blue = clip_8_bit( i_blue ) >> 3;
+ i_red = clip_5_bit( i_red >> 3 );
+ i_green = clip_5_bit( i_green >> 3 );
+ i_blue = clip_5_bit( i_blue >> 3 );
- *p_rgb1 = (i_blue << 3) | (i_red & 0x18 >> 3);
+ *p_rgb1 = ((i_blue & 0x1F) << 3) | (i_red & 0x18 >> 3);
*p_rgb2 = (i_red & 0x07 << 5) | (i_green & 0x1F);
uint8_t *p_pixel_base;
ogt_yuvt_t *p_src_start = (ogt_yuvt_t *)p_spu->p_sys->p_data;
ogt_yuvt_t *p_src_end = &p_src_start[p_spu->i_height * p_spu->i_width];
+ ogt_yuvt_t *p_source;
int i_x, i_y;
- int i_x_src, i_y_src;
+ int i_y_src;
/* RGB-specific */
int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_ynext;
p_pixel_base = p_pic->p->p_pixels + ( (p_spu->i_x * i_xscale) >> 6 ) * 2
+ ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
- i_x_start = i_xscale * p_spu->p_sys->i_x_start;
- i_y_start = i_yscale * p_spu->p_sys->i_y_start;
- i_x_end = i_xscale * p_spu->p_sys->i_x_end;
- i_y_end = i_yscale * p_spu->p_sys->i_y_end;
+ i_x_start = p_sys->i_x_start;
+ i_y_start = i_yscale * p_sys->i_y_start;
+ i_x_end = p_sys->i_x_end;
+ i_y_end = i_yscale * p_sys->i_y_end;
+ p_source = (ogt_yuvt_t *)p_sys->p_data;
+
/* Draw until we reach the bottom of the subtitle */
i_y = 0;
for( i_y_src = 0 ; i_y_src < p_spu->i_height * p_spu->i_width;
p_pixel_base_y = p_pixel_base + (i_ytmp * p_pic->p->i_pitch);
i_x = 0;
+ if ( b_crop ) {
+ if ( i_y > i_y_end ) break;
+ if (i_x_start) {
+ i_x = i_x_start;
+ p_source += i_x_start;
+ }
+ }
+
/* Check whether we need to draw one line or more than one */
if( i_ytmp + 1 >= ( i_y >> 6 ) )
{
- /* Draw until we reach the end of the line */
- for( i_x_src = 0; i_x_src < p_spu->i_width; i_x_src++ )
+ /* Draw until we reach the end of the line */
+ for( ; i_x < p_spu->i_width; i_x++, p_source++ )
{
- ogt_yuvt_t *p_source;
- i_x += (1<<6);
-
- if( b_crop
- && ( i_x < i_x_start || i_x > i_x_end
- || i_y < i_y_start || i_y > i_y_end ) )
- {
- continue;
- }
-
- p_source = &p_src_start[i_y_src + i_x_src];
+ if( b_crop ) {
+
+ /* FIXME: y cropping should be dealt with outside of this
+ loop.*/
+ if ( i_y < i_y_start) continue;
+
+ if ( i_x > i_x_end )
+ {
+ p_source += p_spu->i_width - i_x;
+ break;
+ }
+ }
if (p_source >= p_src_end) {
msg_Err( p_vout, "Trying to access beyond subtitle %dx%d %d",
/* This is the location that's going to get changed.
*/
- uint8_t *p_dest = p_pixel_base_y + 2 * (i_x >> 6 );
+ uint8_t *p_dest = p_pixel_base_y + 2 * i_x;
int i;
uint8_t i_rgb1;
uint8_t i_rgb2;
yuv2rgb16(p_source, &i_rgb1, &i_rgb2);
- for (i=0; i< 2*i_xscale; i+=2) {
+ for (i=0; i < i_xscale; i++) {
*p_dest++ = i_rgb1;
*p_dest++ = i_rgb2;
}
be completely transparent and is not correct, but
that's handled in a special case above anyway. */
- uint8_t *p_pixel = p_pixel_base + 2*( i_x >> 6 );
+ uint8_t *p_pixel = p_pixel_base + 2*i_x;
uint16_t i_colprecomp = Y2RV16(p_source->plane[Y_PLANE])
* ( (uint16_t) (p_source->s.t+1) );
uint16_t i_destalpha = MAX_ALPHA - p_source->s.t;
/* Draw until we reach the end of the line */
- for( i_x_src = 0; i_x_src < p_spu->i_width; i_x_src++ )
+ for( ; i_x < p_spu->i_width; i_x++, p_source++ )
{
- ogt_yuvt_t *p_source;
- i_x += (1<<6);
- if( b_crop
- && ( i_x < i_x_start || i_x > i_x_end
- || i_y < i_y_start || i_y > i_y_end ) )
- {
- continue;
- }
+ if( b_crop ) {
+
+ /* FIXME: y cropping should be dealt with outside of this
+ loop.*/
+ if ( i_y < i_y_start) continue;
+
+ if ( i_x > i_x_end )
+ {
+ p_source += p_spu->i_width - i_x;
+ break;
+ }
+ }
- p_source = &p_src_start[i_y_src + i_x_src];
-
if (p_source >= p_src_end) {
msg_Err( p_vout, "Trying to access beyond subtitle %dx%d %d",
i_x, i_y / i_yscale, i_height);
/* This is the location that's going to get changed.
*/
- uint8_t *p_pixel_base_x = p_pixel_base + 2 * ( i_x >> 6 );
+ uint8_t *p_pixel_base_x = p_pixel_base + 2 * i_x;
for( ; i_ytmp < i_ynext ; i_ytmp += p_pic->p->i_pitch )
{
/* This is the location that's going to get changed. */
uint8_t *p_dest = p_pixel_base_x + i_ytmp;
-#if 1
- int i;
- uint8_t i_rgb1;
- uint8_t i_rgb2;
- yuv2rgb16(p_source, &i_rgb1, &i_rgb2);
- for (i=0; i< 2*i_xscale; i+=2) {
- *p_dest++ = i_rgb1;
- *p_dest++ = i_rgb2;
- }
-#else
- memset( p_dest, 0xFF, 2*i_xscale );
-#endif
+ int i;
+ uint8_t i_rgb1;
+ uint8_t i_rgb2;
+ yuv2rgb16(p_source, &i_rgb1, &i_rgb2);
+ for (i=0; i < i_xscale; i++) {
+ *p_dest++ = i_rgb1;
+ *p_dest++ = i_rgb2;
+ }
}
break;
}
* subtitle.h : Common SVCD and CVD subtitles header
*****************************************************************************
* Copyright (C) 2003,2004 VideoLAN
- * $Id: subtitle.h,v 1.6 2004/01/11 01:54:20 rocky Exp $
+ * $Id: subtitle.h,v 1.7 2004/01/14 11:47:19 rocky Exp $
*
* Author: Rocky Bernstein
* based on code from:
"4:3 and 16:9 respectively." \
)
+#define DURATION_SCALE_TEXT N_("factor to increase subtitle display interval")
+#define DURATION_SCALE_LONGTEXT N_( \
+ "If you find you need extra time for reading subtitles, " \
+ "you can set this higher and it will multiply the display " \
+ "time by that amount. Use 0 to mean until the next " \
+ "subtitle.")
+
#define DECODE_DEBUG 1
#if DECODE_DEBUG
#define dbg_print(mask, s, args...) \
int subtitle_data_pos; /* where to write next chunk */
- uint32_t i_duration; /* how long to display the image, 0 stands
+ mtime_t i_duration; /* how long to display the image, 0 stands
for "until next subtitle" */
uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of