1 /*****************************************************************************
2 * Common SVCD and VCD subtitle routines.
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
5 * $Id: common.c,v 1.11 2004/01/30 13:17:12 rocky Exp $
7 * Author: Rocky Bernstein <rocky@panix.com>
9 * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
10 * Samuel Hocevar <sam@zoy.org>
11 * Laurent Aimar <fenrir@via.ecp.fr>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
33 #include <vlc/decoder.h>
39 #include "write_png.h"
42 /*****************************************************************************
43 Free Resources associated with subtitle packet.
44 *****************************************************************************/
45 void VCDSubClose( vlc_object_t *p_this )
47 decoder_t *p_dec = (decoder_t*)p_this;
48 decoder_sys_t *p_sys = p_dec->p_sys;
50 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
52 if( !p_sys->b_packetizer )
54 /* FIXME check if it's ok to not lock vout */
55 if( p_sys->p_vout != NULL && p_sys->p_vout->p_subpicture != NULL )
57 subpicture_t * p_subpic;
60 for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
62 p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
64 if( p_subpic != NULL &&
65 ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
66 ( p_subpic->i_status == READY_SUBPICTURE ) ) )
68 vout_DestroySubPicture( p_sys->p_vout, p_subpic );
76 block_ChainRelease( p_sys->p_block );
82 /*****************************************************************************
84 Initialize so the next packet will start off a new one.
86 *****************************************************************************/
88 VCDSubInitSubtitleBlock( decoder_sys_t * p_sys )
90 p_sys->i_spu_size = 0;
91 p_sys->state = SUBTITLE_BLOCK_EMPTY;
93 p_sys->p_block = NULL;
94 p_sys->subtitle_data_pos = 0;
99 VCDSubInitSubtitleData(decoder_sys_t *p_sys)
101 if ( p_sys->subtitle_data ) {
102 if ( p_sys->subtitle_data_size < p_sys->i_spu_size ) {
103 p_sys->subtitle_data = realloc(p_sys->subtitle_data,
105 p_sys->subtitle_data_size = p_sys->i_spu_size;
108 p_sys->subtitle_data = malloc(p_sys->i_spu_size);
109 p_sys->subtitle_data_size = p_sys->i_spu_size;
110 /* FIXME: wrong place to get p_sys */
113 p_sys->subtitle_data_pos = 0;
117 VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
119 decoder_sys_t *p_sys = p_dec->p_sys;
120 int chunk_length = buf_len;
122 if ( chunk_length > p_sys->i_spu_size - p_sys->subtitle_data_pos ) {
123 msg_Warn( p_dec, "too much data (%d) expecting at most %u",
124 chunk_length, p_sys->i_spu_size - p_sys->subtitle_data_pos );
126 chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
129 if ( chunk_length > 0 ) {
133 for (i=0; i<chunk_length; i++)
134 printf ("%02x", b[i]);
138 memcpy(p_sys->subtitle_data + p_sys->subtitle_data_pos,
139 buffer, chunk_length);
140 p_sys->subtitle_data_pos += chunk_length;
141 dbg_print(DECODE_DBG_PACKET, "%d bytes appended, pointer now %d",
142 chunk_length, p_sys->subtitle_data_pos);
147 /*****************************************************************************
148 * FindVout: Find a vout or wait for one to be created.
149 *****************************************************************************/
150 vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
152 vout_thread_t *p_vout = NULL;
154 /* Find an available video output */
157 if( p_dec->b_die || p_dec->b_error )
162 p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
168 msleep( VOUT_OUTMEM_SLEEP );
178 Remove color palette by expanding pixel entries to contain the
179 palette values. We work from the free space at the end to the
180 beginning so we can expand inline.
183 InlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys )
185 const unsigned int i_width = p_sys->i_width;
186 const unsigned int i_height = p_sys->i_height;
187 int n = (i_height * i_width) - 1;
188 uint8_t *p_from = p_dest;
189 ogt_yuvt_t *p_to = (ogt_yuvt_t *) p_dest;
191 for ( ; n >= 0 ; n-- ) {
192 p_to[n] = p_sys->p_palette[p_from[n]];
193 /*p_to[n] = p_sys->p_palette[p_from[3]];*/
198 Check to see if user has overridden subtitle aspect ratio.
199 0 is returned for no override which means just counteract any
203 VCDSubGetAROverride(vlc_object_t * p_input, vout_thread_t *p_vout)
205 char *psz_string = config_GetPsz( p_input, MODULE_STRING "-aspect-ratio" );
207 /* Check whether the user tried to override aspect ratio */
208 if( !psz_string ) return 0;
211 unsigned int i_new_aspect = 0;
212 char *psz_parser = strchr( psz_string, ':' );
216 *psz_parser++ = '\0';
217 i_new_aspect = atoi( psz_string ) * VOUT_ASPECT_FACTOR
218 / atoi( psz_parser );
222 i_new_aspect = p_vout->output.i_width * VOUT_ASPECT_FACTOR
224 / p_vout->output.i_height;
233 Scales down (reduces size) of p_dest in the x direction as
234 determined through aspect ratio x_scale by y_scale. Scaling
235 is done in place. p_spu->i_width, is updated to new width
237 The aspect ratio is assumed to be between 1/2 and 1.
239 Note: the scaling truncates the new width rather than rounds it.
240 Perhaps something one might want to address.
243 VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
244 unsigned int i_scale_x, unsigned int i_scale_y )
248 decoder_sys_t *p_sys = p_dec->p_sys;
249 uint8_t *p_src1 = p_spu->p_sys->p_data;
250 uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
251 uint8_t *p_dst = p_src1;
252 unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
253 unsigned int i_used=0; /* Number of bytes used up in p_src1. */
255 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) ,
256 "aspect ratio %i:%i, Old width: %d, new width: %d",
257 i_scale_x, i_scale_y, p_spu->i_width, i_new_width);
259 if (! (i_scale_x < i_scale_y && i_scale_y < i_scale_x+i_scale_x) )
261 msg_Warn( p_dec, "Need x < y < 2x. x: %i, y: %i", i_scale_x, i_scale_y );
265 for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
268 /* Discard the remaining piece of the column of the previous line*/
271 p_src2 += PIXEL_SIZE;
274 for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
276 unsigned int w1= i_scale_x - i_used;
279 if ( i_scale_y - w1 <= i_scale_x ) {
280 /* Average spans 2 pixels. */
283 for (i = 0; i < PIXEL_SIZE; i++ ) {
284 *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
285 p_src1++; p_src2++; p_dst++;
288 /* Average spans 3 pixels. */
289 unsigned int w0 = w1;
290 unsigned int w1 = i_scale_x;
291 uint8_t *p_src0 = p_src1;
292 w2 = i_scale_y - w0 - w1;
294 p_src2 += PIXEL_SIZE;
296 for (i = 0; i < PIXEL_SIZE; i++ ) {
297 *p_dst = ( (*p_src0 * w0) + (*p_src1 * w1) + (*p_src2 * w2) )
299 p_src0++; p_src1++; p_src2++; p_dst++;
306 if (i_scale_x == i_used) {
307 /* End of last pixel was end of p_src2. */
309 p_src2 += PIXEL_SIZE;
315 p_spu->i_width = i_new_width;
317 if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
319 ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
320 for ( i_row=0; i_row < p_spu->i_height; i_row++ ) {
321 for ( i_col=0; i_col < p_spu->i_width; i_col++ ) {
322 printf("%1x", p_source->s.t);
332 The video may be scaled. However subtitle bitmaps assume an 1:1
333 aspect ratio. So unless the user has specified otherwise, we
334 need to scale to compensate for or undo the effects of video
337 Perhaps this should go in the Render routine? The advantage would
338 be that it will deal with a dynamically changing aspect ratio.
339 The downside is having to scale many times for each render call.
341 We also expand palette entries here, unless we are dealing with a
342 palettized chroma (e.g. RGB2).
346 VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec )
348 vlc_object_t * p_input = p_spu->p_sys->p_input;
349 vout_thread_t *p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT,
351 unsigned int i_aspect_x, i_aspect_y;
352 uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
355 /* Check for user-configuration override. */
356 unsigned int i_new_aspect;
358 if ( p_vout->output.i_chroma == VLC_FOURCC('R','G','B','2') ) {
359 /* This is an unscaled palettized format. We don't allow
360 user scaling here. And to make the render process faster,
361 we don't expand the palette entries into a color value.
366 InlinePalette( p_dest, p_dec->p_sys );
367 i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
369 if (i_new_aspect == VOUT_ASPECT_FACTOR) {
370 /* For scaling 1:1, nothing needs to be done. Note this means
371 subtitles will get scaled the same way the video does.
375 if (0 == i_new_aspect) {
376 /* Counteract the effects of background video scaling when
377 there is scaling. That's why x and y are reversed from
378 the else branch in the call below.
380 switch( p_vout->output.i_chroma )
382 /* chromas in which scaling is done outside of our
383 blending routine, so we need to compensate for those
384 effects before blending gets called: */
385 case VLC_FOURCC('I','4','2','0'):
386 case VLC_FOURCC('I','Y','U','V'):
387 case VLC_FOURCC('Y','V','1','2'):
388 case VLC_FOURCC('Y','U','Y','2'):
391 /* chromas in which scaling is done in our blending
392 routine and thus we don't do it here: */
393 case VLC_FOURCC('R','V','1','6'):
394 case VLC_FOURCC('R','V','2','4'):
395 case VLC_FOURCC('R','V','3','2'):
396 case VLC_FOURCC('R','G','B','2'):
401 msg_Err( p_vout, "unknown chroma %x",
402 p_vout->output.i_chroma );
406 /* We get here only for scaled chromas. */
407 vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
410 /* User knows best? */
411 vout_AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y );
413 VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
420 * DestroySPU: subpicture destructor
422 void VCDSubDestroySPU( subpicture_t *p_spu )
424 if( p_spu->p_sys->p_input )
426 /* Detach from our input thread */
427 vlc_object_release( p_spu->p_sys->p_input );
430 vlc_mutex_destroy( &p_spu->p_sys->lock );
431 free( p_spu->p_sys );
434 /*****************************************************************************
435 This callback is called from the input thread when we need cropping
436 *****************************************************************************/
437 int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
438 vlc_value_t oldval, vlc_value_t newval, void *p_data )
440 VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
446 /*****************************************************************************
447 update subpicture settings
448 *****************************************************************************
449 This function is called from CropCallback and at initialization time, to
450 retrieve crop information from the input.
451 *****************************************************************************/
452 void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
456 p_spu->p_sys->b_crop = val.b_bool;
457 if( !p_spu->p_sys->b_crop )
462 if ( VLC_SUCCESS == var_Get( p_object, "x-start", &val ) )
463 p_spu->p_sys->i_x_start = val.i_int;
464 if ( VLC_SUCCESS == var_Get( p_object, "y-start", &val ) )
465 p_spu->p_sys->i_y_start = val.i_int;
466 if ( VLC_SUCCESS == var_Get( p_object, "x-end", &val ) )
467 p_spu->p_sys->i_x_end = val.i_int;
468 if ( VLC_SUCCESS == var_Get( p_object, "y-end", &val ) )
469 p_spu->p_sys->i_y_end = val.i_int;
474 Dump an a subtitle image to standard output - for debugging.
476 void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
478 uint8_t *p = p_image;
479 unsigned int i_row; /* scanline row number */
480 unsigned int i_column; /* scanline column number */
482 printf("-------------------------------------\n++");
483 for ( i_row=0; i_row < i_height; i_row ++ ) {
484 for ( i_column=0; i_column<i_width; i_column++ ) {
485 printf("%1d", *p++ & 0x03);
489 printf("\n-------------------------------------\n");
494 #define PALETTE_SIZE 4
495 /* Note the below assumes the above is a power of 2 */
496 #define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
499 Dump an a subtitle image to a Portable Network Graphics (PNG) file.
500 All we do here is convert YUV palette entries to RGB, expand
501 the image into a linear RGB pixel array, and call the routine
502 that does the PNG writing.
506 VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
507 uint32_t i_height, uint32_t i_width, const char *filename,
508 png_text *text_ptr, int i_text_count )
510 decoder_sys_t *p_sys = p_dec->p_sys;
511 uint8_t *p = p_image;
512 uint8_t *image_data = malloc(RGB_SIZE * i_height * i_width );
513 uint8_t *q = image_data;
514 unsigned int i_row; /* scanline row number */
515 unsigned int i_column; /* scanline column number */
516 uint8_t rgb_palette[PALETTE_SIZE * RGB_SIZE];
519 dbg_print( (DECODE_DBG_CALL), "%s", filename);
521 if (NULL == image_data) return;
523 /* Convert palette YUV into RGB. */
524 for (i=0; i<PALETTE_SIZE; i++) {
525 ogt_yuvt_t *p_yuv = &(p_sys->p_palette[i]);
526 uint8_t *p_rgb_out = &(rgb_palette[i*RGB_SIZE]);
527 yuv2rgb( p_yuv, p_rgb_out );
530 /* Convert palette entries into linear RGB array. */
531 for ( i_row=0; i_row < i_height; i_row ++ ) {
532 for ( i_column=0; i_column<i_width; i_column++ ) {
533 uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*RGB_SIZE ];
541 write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
544 #endif /*HAVE_LIBPNG*/
549 * c-file-style: "gnu"
551 * indent-tabs-mode: nil