1 /*****************************************************************************
2 * Common SVCD and CVD subtitle routines.
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
5 * $Id: common.c,v 1.13 2004/02/22 10:52:23 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 );
79 free(p_sys->subtitle_data);
83 /*****************************************************************************
85 Initialize so the next packet will start off a new one.
87 *****************************************************************************/
89 VCDSubInitSubtitleBlock( decoder_sys_t * p_sys )
91 p_sys->i_spu_size = 0;
92 p_sys->state = SUBTITLE_BLOCK_EMPTY;
94 p_sys->p_block = NULL;
95 p_sys->subtitle_data_pos = 0;
100 VCDSubInitSubtitleData(decoder_sys_t *p_sys)
102 if ( p_sys->subtitle_data ) {
103 if ( p_sys->subtitle_data_size < p_sys->i_spu_size ) {
104 p_sys->subtitle_data = realloc(p_sys->subtitle_data,
106 p_sys->subtitle_data_size = p_sys->i_spu_size;
109 p_sys->subtitle_data = malloc(p_sys->i_spu_size);
110 p_sys->subtitle_data_size = p_sys->i_spu_size;
111 /* FIXME: wrong place to get p_sys */
114 p_sys->subtitle_data_pos = 0;
118 VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
120 decoder_sys_t *p_sys = p_dec->p_sys;
121 int chunk_length = buf_len;
123 if ( chunk_length > p_sys->i_spu_size - p_sys->subtitle_data_pos ) {
124 msg_Warn( p_dec, "too much data (%d) expecting at most %u",
125 chunk_length, p_sys->i_spu_size - p_sys->subtitle_data_pos );
127 chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
130 if ( chunk_length > 0 ) {
134 for (i=0; i<chunk_length; i++)
135 printf ("%02x", b[i]);
139 memcpy(p_sys->subtitle_data + p_sys->subtitle_data_pos,
140 buffer, chunk_length);
141 p_sys->subtitle_data_pos += chunk_length;
142 dbg_print(DECODE_DBG_PACKET, "%d bytes appended, pointer now %d",
143 chunk_length, p_sys->subtitle_data_pos);
148 /*****************************************************************************
149 * FindVout: Find a vout or wait for one to be created.
150 *****************************************************************************/
151 vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
153 vout_thread_t *p_vout = NULL;
155 /* Find an available video output */
158 if( p_dec->b_die || p_dec->b_error )
163 p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
169 msleep( VOUT_OUTMEM_SLEEP );
179 Remove color palette by expanding pixel entries to contain the
180 palette values. We work from the free space at the end to the
181 beginning so we can expand inline.
184 InlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys )
186 const unsigned int i_width = p_sys->i_width;
187 const unsigned int i_height = p_sys->i_height;
188 int n = (i_height * i_width) - 1;
189 uint8_t *p_from = p_dest;
190 ogt_yuvt_t *p_to = (ogt_yuvt_t *) p_dest;
192 for ( ; n >= 0 ; n-- ) {
193 p_to[n] = p_sys->p_palette[p_from[n]];
194 /*p_to[n] = p_sys->p_palette[p_from[3]];*/
199 Check to see if user has overridden subtitle aspect ratio.
200 0 is returned for no override which means just counteract any
204 VCDSubGetAROverride(vlc_object_t * p_input, vout_thread_t *p_vout)
206 char *psz_string = config_GetPsz( p_input, MODULE_STRING "-aspect-ratio" );
208 /* Check whether the user tried to override aspect ratio */
209 if( !psz_string ) return 0;
212 unsigned int i_new_aspect = 0;
213 char *psz_parser = strchr( psz_string, ':' );
217 *psz_parser++ = '\0';
218 i_new_aspect = atoi( psz_string ) * VOUT_ASPECT_FACTOR
219 / atoi( psz_parser );
223 i_new_aspect = p_vout->output.i_width * VOUT_ASPECT_FACTOR
225 / p_vout->output.i_height;
234 Scales down (reduces size) of p_dest in the x direction as
235 determined through aspect ratio x_scale by y_scale. Scaling
236 is done in place. p_spu->i_width, is updated to new width
238 The aspect ratio is assumed to be between 1/2 and 1.
240 Note: the scaling truncates the new width rather than rounds it.
241 Perhaps something one might want to address.
244 VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
245 unsigned int i_scale_x, unsigned int i_scale_y )
249 decoder_sys_t *p_sys = p_dec->p_sys;
250 uint8_t *p_src1 = p_spu->p_sys->p_data;
251 uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
252 uint8_t *p_dst = p_src1;
253 unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
254 unsigned int i_used=0; /* Number of bytes used up in p_src1. */
256 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) ,
257 "aspect ratio %i:%i, Old width: %d, new width: %d",
258 i_scale_x, i_scale_y, p_spu->i_width, i_new_width);
260 if (! (i_scale_x < i_scale_y && i_scale_y < i_scale_x+i_scale_x) )
262 msg_Warn( p_dec, "Need x < y < 2x. x: %i, y: %i", i_scale_x, i_scale_y );
266 for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
269 /* Discard the remaining piece of the column of the previous line*/
272 p_src2 += PIXEL_SIZE;
275 for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
277 unsigned int w1= i_scale_x - i_used;
280 if ( i_scale_y - w1 <= i_scale_x ) {
281 /* Average spans 2 pixels. */
284 for (i = 0; i < PIXEL_SIZE; i++ ) {
285 *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
286 p_src1++; p_src2++; p_dst++;
289 /* Average spans 3 pixels. */
290 unsigned int w0 = w1;
291 unsigned int w1 = i_scale_x;
292 uint8_t *p_src0 = p_src1;
293 w2 = i_scale_y - w0 - w1;
295 p_src2 += PIXEL_SIZE;
297 for (i = 0; i < PIXEL_SIZE; i++ ) {
298 *p_dst = ( (*p_src0 * w0) + (*p_src1 * w1) + (*p_src2 * w2) )
300 p_src0++; p_src1++; p_src2++; p_dst++;
307 if (i_scale_x == i_used) {
308 /* End of last pixel was end of p_src2. */
310 p_src2 += PIXEL_SIZE;
316 p_spu->i_width = i_new_width;
318 if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
320 ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
321 for ( i_row=0; i_row < p_spu->i_height; i_row++ ) {
322 for ( i_col=0; i_col < p_spu->i_width; i_col++ ) {
323 printf("%1x", p_source->s.t);
333 The video may be scaled. However subtitle bitmaps assume an 1:1
334 aspect ratio. So unless the user has specified otherwise, we
335 need to scale to compensate for or undo the effects of video
338 Perhaps this should go in the Render routine? The advantage would
339 be that it will deal with a dynamically changing aspect ratio.
340 The downside is having to scale many times for each render call.
342 We also expand palette entries here, unless we are dealing with a
343 palettized chroma (e.g. RGB2).
347 VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec )
349 vlc_object_t * p_input = p_spu->p_sys->p_input;
350 vout_thread_t *p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT,
352 unsigned int i_aspect_x, i_aspect_y;
353 uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
356 /* Check for user-configuration override. */
357 unsigned int i_new_aspect;
359 if ( p_vout->output.i_chroma == VLC_FOURCC('R','G','B','2') ) {
360 /* This is an unscaled palettized format. We don't allow
361 user scaling here. And to make the render process faster,
362 we don't expand the palette entries into a color value.
367 InlinePalette( p_dest, p_dec->p_sys );
368 i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
370 if (i_new_aspect == VOUT_ASPECT_FACTOR) {
371 /* For scaling 1:1, nothing needs to be done. Note this means
372 subtitles will get scaled the same way the video does.
376 if (0 == i_new_aspect) {
377 /* Counteract the effects of background video scaling when
378 there is scaling. That's why x and y are reversed from
379 the else branch in the call below.
381 switch( p_vout->output.i_chroma )
383 /* chromas in which scaling is done outside of our
384 blending routine, so we need to compensate for those
385 effects before blending gets called: */
386 case VLC_FOURCC('I','4','2','0'):
387 case VLC_FOURCC('I','Y','U','V'):
388 case VLC_FOURCC('Y','V','1','2'):
389 case VLC_FOURCC('Y','U','Y','2'):
392 /* chromas in which scaling is done in our blending
393 routine and thus we don't do it here: */
394 case VLC_FOURCC('R','V','1','6'):
395 case VLC_FOURCC('R','V','2','4'):
396 case VLC_FOURCC('R','V','3','2'):
397 case VLC_FOURCC('R','G','B','2'):
402 msg_Err( p_vout, "unknown chroma %x",
403 p_vout->output.i_chroma );
407 /* We get here only for scaled chromas. */
408 vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
411 /* User knows best? */
412 vout_AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y );
414 VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
421 * DestroySPU: subpicture destructor
423 void VCDSubDestroySPU( subpicture_t *p_spu )
425 if( p_spu->p_sys->p_input )
427 /* Detach from our input thread */
428 vlc_object_release( p_spu->p_sys->p_input );
431 vlc_mutex_destroy( &p_spu->p_sys->lock );
432 free( p_spu->p_sys );
435 /*****************************************************************************
436 This callback is called from the input thread when we need cropping
437 *****************************************************************************/
438 int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
439 vlc_value_t oldval, vlc_value_t newval, void *p_data )
441 VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
447 /*****************************************************************************
448 update subpicture settings
449 *****************************************************************************
450 This function is called from CropCallback and at initialization time, to
451 retrieve crop information from the input.
452 *****************************************************************************/
453 void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
457 p_spu->p_sys->b_crop = val.b_bool;
458 if( !p_spu->p_sys->b_crop )
463 if ( VLC_SUCCESS == var_Get( p_object, "x-start", &val ) )
464 p_spu->p_sys->i_x_start = val.i_int;
465 if ( VLC_SUCCESS == var_Get( p_object, "y-start", &val ) )
466 p_spu->p_sys->i_y_start = val.i_int;
467 if ( VLC_SUCCESS == var_Get( p_object, "x-end", &val ) )
468 p_spu->p_sys->i_x_end = val.i_int;
469 if ( VLC_SUCCESS == var_Get( p_object, "y-end", &val ) )
470 p_spu->p_sys->i_y_end = val.i_int;
475 Dump an a subtitle image to standard output - for debugging.
477 void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
479 uint8_t *p = p_image;
480 unsigned int i_row; /* scanline row number */
481 unsigned int i_column; /* scanline column number */
483 printf("-------------------------------------\n++");
484 for ( i_row=0; i_row < i_height; i_row ++ ) {
485 for ( i_column=0; i_column<i_width; i_column++ ) {
486 printf("%1d", *p++ & 0x03);
490 printf("\n-------------------------------------\n");
495 #define PALETTE_SIZE 4
496 /* Note the below assumes the above is a power of 2 */
497 #define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
500 Dump an a subtitle image to a Portable Network Graphics (PNG) file.
501 All we do here is convert YUV palette entries to RGB, expand
502 the image into a linear RGB pixel array, and call the routine
503 that does the PNG writing.
507 VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
508 uint32_t i_height, uint32_t i_width, const char *filename,
509 png_text *text_ptr, int i_text_count )
511 decoder_sys_t *p_sys = p_dec->p_sys;
512 uint8_t *p = p_image;
513 uint8_t *image_data = malloc(RGB_SIZE * i_height * i_width );
514 uint8_t *q = image_data;
515 unsigned int i_row; /* scanline row number */
516 unsigned int i_column; /* scanline column number */
517 uint8_t rgb_palette[PALETTE_SIZE * RGB_SIZE];
520 dbg_print( (DECODE_DBG_CALL), "%s", filename);
522 if (NULL == image_data) return;
524 /* Convert palette YUV into RGB. */
525 for (i=0; i<PALETTE_SIZE; i++) {
526 ogt_yuvt_t *p_yuv = &(p_sys->p_palette[i]);
527 uint8_t *p_rgb_out = &(rgb_palette[i*RGB_SIZE]);
528 yuv2rgb( p_yuv, p_rgb_out );
531 /* Convert palette entries into linear RGB array. */
532 for ( i_row=0; i_row < i_height; i_row ++ ) {
533 for ( i_column=0; i_column<i_width; i_column++ ) {
534 uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*RGB_SIZE ];
542 write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
545 #endif /*HAVE_LIBPNG*/
550 * c-file-style: "gnu"
552 * indent-tabs-mode: nil