/*****************************************************************************
- * Common SVCD and VCD subtitle routines.
+ * Common SVCD and CVD subtitle routines.
*****************************************************************************
* Copyright (C) 2003, 2004 VideoLAN
- * $Id: common.c,v 1.3 2004/01/03 12:54:56 rocky Exp $
+ * $Id$
*
- * Author: Rocky Bernstein
+ * Author: Rocky Bernstein <rocky@panix.com>
* based on code from:
* Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
* Samuel Hocevar <sam@zoy.org>
#include <vlc/decoder.h>
#include "subtitle.h"
+#include "pixmap.h"
#include "common.h"
#ifdef HAVE_LIBPNG
#include "write_png.h"
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
- if( !p_sys->b_packetizer )
+ if( !p_sys->b_packetizer && p_sys->p_vout )
{
/* FIXME check if it's ok to not lock vout */
- if( p_sys->p_vout != NULL && p_sys->p_vout->p_subpicture != NULL )
- {
- subpicture_t * p_subpic;
- int i_subpic;
-
- for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
- {
- p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
-
- if( p_subpic != NULL &&
- ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
- ( p_subpic->i_status == READY_SUBPICTURE ) ) )
- {
- vout_DestroySubPicture( p_sys->p_vout, p_subpic );
- }
- }
- }
+ spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_CLEAR,
+ p_sys->i_subpic_channel );
}
if( p_sys->p_block )
block_ChainRelease( p_sys->p_block );
}
+ free(p_sys->subtitle_data);
free( p_sys );
}
-/* Remove color palette by expanding pixel entries to contain the
+/**
+ Remove color palette by expanding pixel entries to contain the
palette values. We work from the free space at the end to the
beginning so we can expand inline.
- */
-void
-VCDInlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys,
- unsigned int i_height, unsigned int i_width )
+*/
+static void
+InlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys )
{
+ const unsigned int i_width = p_sys->i_width;
+ const unsigned int i_height = p_sys->i_height;
int n = (i_height * i_width) - 1;
uint8_t *p_from = p_dest;
ogt_yuvt_t *p_to = (ogt_yuvt_t *) p_dest;
for ( ; n >= 0 ; n-- ) {
p_to[n] = p_sys->p_palette[p_from[n]];
+ /*p_to[n] = p_sys->p_palette[p_from[3]];*/
+ }
+}
+
+/**
+ Check to see if user has overridden subtitle aspect ratio.
+ 0 is returned for no override which means just counteract any
+ scaling effects.
+*/
+unsigned int
+VCDSubGetAROverride(vlc_object_t * p_input, vout_thread_t *p_vout)
+{
+ char *psz_string = config_GetPsz( p_input, MODULE_STRING "-aspect-ratio" );
+
+ /* Check whether the user tried to override aspect ratio */
+ if( !psz_string ) return 0;
+
+ {
+ unsigned int i_new_aspect = 0;
+ char *psz_parser = strchr( psz_string, ':' );
+
+ if( psz_parser )
+ {
+ *psz_parser++ = '\0';
+ i_new_aspect = atoi( psz_string ) * VOUT_ASPECT_FACTOR
+ / atoi( psz_parser );
+ }
+ else
+ {
+ i_new_aspect = p_vout->output.i_width * VOUT_ASPECT_FACTOR
+ * atof( psz_string )
+ / p_vout->output.i_height;
+ }
+
+ return i_new_aspect;
}
}
-/* Scales down (reduces size) of p_dest in the x direction as
+/**
+ Scales down (reduces size) of p_dest in the x direction as
determined through aspect ratio x_scale by y_scale. Scaling
is done in place. p_spu->i_width, is updated to new width
The aspect ratio is assumed to be between 1/2 and 1.
+
+ Note: the scaling truncates the new width rather than rounds it.
+ Perhaps something one might want to address.
*/
void
VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
uint8_t *p_dst = p_src1;
unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
- unsigned int used=0; /* Number of bytes used up in p_src1. */
+ unsigned int i_used=0; /* Number of bytes used up in p_src1. */
dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) ,
- "Old width: %d, new width: %d",
- p_spu->i_width, i_new_width);
+ "aspect ratio %i:%i, Old width: %d, new width: %d",
+ i_scale_x, i_scale_y, p_spu->i_width, i_new_width);
+
+ if (! (i_scale_x < i_scale_y && i_scale_y < i_scale_x+i_scale_x) )
+ {
+ msg_Warn( p_dec, "Need x < y < 2x. x: %i, y: %i", i_scale_x, i_scale_y );
+ return;
+ }
for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
- if (used != 0) {
+ if (i_used != 0) {
/* Discard the remaining piece of the column of the previous line*/
- used=0;
+ i_used=0;
p_src1 = p_src2;
p_src2 += PIXEL_SIZE;
}
for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
unsigned int i;
- unsigned int w1= i_scale_x - used;
- unsigned int w2= i_scale_y - w1;
-
- used = w2;
- for (i = 0; i < PIXEL_SIZE; i++ ) {
- *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
- p_src1++; p_src2++; p_dst++;
+ unsigned int w1= i_scale_x - i_used;
+ unsigned int w2;
+
+ if ( i_scale_y - w1 <= i_scale_x ) {
+ /* Average spans 2 pixels. */
+ w2 = i_scale_y - w1;
+
+ for (i = 0; i < PIXEL_SIZE; i++ ) {
+ *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
+ p_src1++; p_src2++; p_dst++;
+ }
+ } else {
+ /* Average spans 3 pixels. */
+ unsigned int w0 = w1;
+ unsigned int w1 = i_scale_x;
+ uint8_t *p_src0 = p_src1;
+ w2 = i_scale_y - w0 - w1;
+ p_src1 = p_src2;
+ p_src2 += PIXEL_SIZE;
+
+ for (i = 0; i < PIXEL_SIZE; i++ ) {
+ *p_dst = ( (*p_src0 * w0) + (*p_src1 * w1) + (*p_src2 * w2) )
+ / i_scale_y;
+ p_src0++; p_src1++; p_src2++; p_dst++;
+ }
+ i_col++;
}
- if (i_scale_x == used) {
+ i_used = w2;
+
+ if (i_scale_x == i_used) {
/* End of last pixel was end of p_src2. */
p_src1 = p_src2;
p_src2 += PIXEL_SIZE;
i_col++;
- used = 0;
+ i_used = 0;
}
}
}
if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
{
ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
- for ( i_row=0; i_row < p_spu->i_height - 1; i_row++ ) {
- for ( i_col=0; i_col < p_spu->i_width - 1; i_col++ ) {
+ for ( i_row=0; i_row < p_spu->i_height; i_row++ ) {
+ for ( i_col=0; i_col < p_spu->i_width; i_col++ ) {
printf("%1x", p_source->s.t);
p_source++;
}
}
-/*****************************************************************************
+/**
+ 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.
+
+ We also expand palette entries here, unless we are dealing with a
+ palettized chroma (e.g. RGB2).
+*/
+
+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 );
+ int i_aspect_x, i_aspect_y;
+ uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
+
+ if (p_vout) {
+ /* Check for user-configuration override. */
+ unsigned int i_new_aspect;
+
+ if ( p_vout->output.i_chroma == VLC_FOURCC('R','G','B','2') ) {
+ /* This is an unscaled palettized format. We don't allow
+ user scaling here. And to make the render process faster,
+ we don't expand the palette entries into a color value.
+ */
+ return;
+ }
+
+ InlinePalette( p_dest, p_dec->p_sys );
+ 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 in which scaling is done outside of our
+ blending routine, so we need to compensate for those
+ effects before blending gets called: */
+ 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'):
+ break;
+
+ /* chromas in which scaling is done in our blending
+ routine and thus we don't do it here: */
+ 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'):
+ return;
+ break;
+
+ default:
+ msg_Err( p_vout, "unknown chroma %x",
+ p_vout->output.i_chroma );
+ return;
+ break;
+ }
+ /* We get here only for scaled chromas. */
+ vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
+ VOUT_ASPECT_FACTOR, 0 );
+ } else {
+ /* User knows best? */
+ vlc_reduce( &i_aspect_x, &i_aspect_y, p_vout->render.i_aspect,
+ VOUT_ASPECT_FACTOR, 0 );
+ }
+ VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
+ }
+ }
+}
+
+
+/**
* DestroySPU: subpicture destructor
- *****************************************************************************/
+ */
void VCDSubDestroySPU( subpicture_t *p_spu )
{
if( p_spu->p_sys->p_input )
return;
}
- var_Get( p_object, "x-start", &val );
- p_spu->p_sys->i_x_start = val.i_int;
- var_Get( p_object, "y-start", &val );
- p_spu->p_sys->i_y_start = val.i_int;
- var_Get( p_object, "x-end", &val );
- p_spu->p_sys->i_x_end = val.i_int;
- var_Get( p_object, "y-end", &val );
- p_spu->p_sys->i_y_end = val.i_int;
+ if ( VLC_SUCCESS == var_Get( p_object, "x-start", &val ) )
+ p_spu->p_sys->i_x_start = val.i_int;
+ if ( VLC_SUCCESS == var_Get( p_object, "y-start", &val ) )
+ p_spu->p_sys->i_y_start = val.i_int;
+ if ( VLC_SUCCESS == var_Get( p_object, "x-end", &val ) )
+ p_spu->p_sys->i_x_end = val.i_int;
+ if ( VLC_SUCCESS == var_Get( p_object, "y-end", &val ) )
+ p_spu->p_sys->i_y_end = val.i_int;
}
printf("\n-------------------------------------\n");
}
-/*
- FIXME:
- MOVE clip_8_bit and uuv2rgb TO A MORE GENERIC PLACE.
- */
-
-/* Force v in the range 0.255 */
-static inline uint8_t
-clip_8_bit(int v)
-{
- if (v<0) return 0;
- if (v>255) return 255;
- return (uint8_t) v;
-}
-
-/***************************************************
- Color conversion from
- http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
- http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html
-
- Thanks to Billy Biggs <vektor@dumbterm.net> for the pointer and
- the following conversion.
-
- R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
- G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
- B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
-
- See also vlc/modules/video_chroma/i420_rgb.h and
- vlc/modules/video_chroma/i420_rgb_c.h for a way to do this in a way
- more optimized for integer arithmetic. Would be nice to merge the
- two routines.
-
-***************************************************/
-
-static inline void
-yuv2rgb(ogt_yuvt_t *p_yuv, uint8_t *p_rgb_out )
-{
-
- int i_Y = p_yuv->s.y - 16;
- int i_Cb = p_yuv->s.v - 128;
- int i_Cr = p_yuv->s.u - 128;
-
- int i_red = (1.1644 * i_Y) + (1.5960 * i_Cr);
- 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 );
- i_green = clip_8_bit( i_green );
- i_blue = clip_8_bit( i_blue );
-
- *p_rgb_out++ = i_red;
- *p_rgb_out++ = i_green;
- *p_rgb_out++ = i_blue;
-
-}
-
#ifdef HAVE_LIBPNG
-#define BYTES_PER_RGB 3
#define PALETTE_SIZE 4
/* Note the below assumes the above is a power of 2 */
#define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
{
decoder_sys_t *p_sys = p_dec->p_sys;
uint8_t *p = p_image;
- uint8_t *image_data = malloc(BYTES_PER_RGB * i_height * i_width );
+ uint8_t *image_data = malloc(RGB_SIZE * i_height * i_width );
uint8_t *q = image_data;
unsigned int i_row; /* scanline row number */
unsigned int i_column; /* scanline column number */
- uint8_t rgb_palette[PALETTE_SIZE * BYTES_PER_RGB];
+ uint8_t rgb_palette[PALETTE_SIZE * RGB_SIZE];
int i;
dbg_print( (DECODE_DBG_CALL), "%s", filename);
/* Convert palette YUV into RGB. */
for (i=0; i<PALETTE_SIZE; i++) {
ogt_yuvt_t *p_yuv = &(p_sys->p_palette[i]);
- uint8_t *p_rgb_out = &(rgb_palette[i*BYTES_PER_RGB]);
+ uint8_t *p_rgb_out = &(rgb_palette[i*RGB_SIZE]);
yuv2rgb( p_yuv, p_rgb_out );
}
/* Convert palette entries into linear RGB array. */
for ( i_row=0; i_row < i_height; i_row ++ ) {
for ( i_column=0; i_column<i_width; i_column++ ) {
- uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*BYTES_PER_RGB ];
+ uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*RGB_SIZE ];
*q++ = p_rgb[0];
*q++ = p_rgb[1];
*q++ = p_rgb[2];
free(image_data);
}
#endif /*HAVE_LIBPNG*/
+
+\f
+/*
+ * Local variables:
+ * c-file-style: "gnu"
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ */