1 /*****************************************************************************
2 * Common SVCD and VCD subtitle routines.
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
5 * $Id: common.c,v 1.8 2004/01/16 13:32:37 rocky Exp $
7 * Author: Rocky Bernstein
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 which are not scaled: */
383 case VLC_FOURCC('I','4','2','0'):
384 case VLC_FOURCC('I','Y','U','V'):
385 case VLC_FOURCC('Y','V','1','2'):
386 case VLC_FOURCC('Y','U','Y','2'):
389 /* chromas which are scaled: */
390 case VLC_FOURCC('R','V','1','6'):
391 case VLC_FOURCC('R','V','2','4'):
392 case VLC_FOURCC('R','V','3','2'):
393 case VLC_FOURCC('R','G','B','2'):
398 msg_Err( p_vout, "unknown chroma %x",
399 p_vout->output.i_chroma );
403 /* We get here only for scaled chromas. */
404 vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y,
407 /* User knows best? */
408 vout_AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y );
410 VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
417 * DestroySPU: subpicture destructor
419 void VCDSubDestroySPU( subpicture_t *p_spu )
421 if( p_spu->p_sys->p_input )
423 /* Detach from our input thread */
424 vlc_object_release( p_spu->p_sys->p_input );
427 vlc_mutex_destroy( &p_spu->p_sys->lock );
428 free( p_spu->p_sys );
431 /*****************************************************************************
432 This callback is called from the input thread when we need cropping
433 *****************************************************************************/
434 int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
435 vlc_value_t oldval, vlc_value_t newval, void *p_data )
437 VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
443 /*****************************************************************************
444 update subpicture settings
445 *****************************************************************************
446 This function is called from CropCallback and at initialization time, to
447 retrieve crop information from the input.
448 *****************************************************************************/
449 void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
453 p_spu->p_sys->b_crop = val.b_bool;
454 if( !p_spu->p_sys->b_crop )
459 if ( VLC_SUCCESS == var_Get( p_object, "x-start", &val ) )
460 p_spu->p_sys->i_x_start = val.i_int;
461 if ( VLC_SUCCESS == var_Get( p_object, "y-start", &val ) )
462 p_spu->p_sys->i_y_start = val.i_int;
463 if ( VLC_SUCCESS == var_Get( p_object, "x-end", &val ) )
464 p_spu->p_sys->i_x_end = val.i_int;
465 if ( VLC_SUCCESS == var_Get( p_object, "y-end", &val ) )
466 p_spu->p_sys->i_y_end = val.i_int;
471 Dump an a subtitle image to standard output - for debugging.
473 void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
475 uint8_t *p = p_image;
476 unsigned int i_row; /* scanline row number */
477 unsigned int i_column; /* scanline column number */
479 printf("-------------------------------------\n++");
480 for ( i_row=0; i_row < i_height; i_row ++ ) {
481 for ( i_column=0; i_column<i_width; i_column++ ) {
482 printf("%1d", *p++ & 0x03);
486 printf("\n-------------------------------------\n");
489 /***************************************************
490 Color conversion from
491 http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
492 http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html
494 Thanks to Billy Biggs <vektor@dumbterm.net> for the pointer and
495 the following conversion.
497 R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
498 G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
499 B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
501 See also vlc/modules/video_chroma/i420_rgb.h and
502 vlc/modules/video_chroma/i420_rgb_c.h for a way to do this in a way
503 more optimized for integer arithmetic. Would be nice to merge the
506 ***************************************************/
510 #define BYTES_PER_RGB 3
511 #define PALETTE_SIZE 4
512 /* Note the below assumes the above is a power of 2 */
513 #define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
516 Dump an a subtitle image to a Portable Network Graphics (PNG) file.
517 All we do here is convert YUV palette entries to RGB, expand
518 the image into a linear RGB pixel array, and call the routine
519 that does the PNG writing.
523 VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
524 uint32_t i_height, uint32_t i_width, const char *filename,
525 png_text *text_ptr, int i_text_count )
527 decoder_sys_t *p_sys = p_dec->p_sys;
528 uint8_t *p = p_image;
529 uint8_t *image_data = malloc(BYTES_PER_RGB * i_height * i_width );
530 uint8_t *q = image_data;
531 unsigned int i_row; /* scanline row number */
532 unsigned int i_column; /* scanline column number */
533 uint8_t rgb_palette[PALETTE_SIZE * BYTES_PER_RGB];
536 dbg_print( (DECODE_DBG_CALL), "%s", filename);
538 if (NULL == image_data) return;
540 /* Convert palette YUV into RGB. */
541 for (i=0; i<PALETTE_SIZE; i++) {
542 ogt_yuvt_t *p_yuv = &(p_sys->p_palette[i]);
543 uint8_t *p_rgb_out = &(rgb_palette[i*BYTES_PER_RGB]);
544 yuv2rgb( p_yuv, p_rgb_out );
547 /* Convert palette entries into linear RGB array. */
548 for ( i_row=0; i_row < i_height; i_row ++ ) {
549 for ( i_column=0; i_column<i_width; i_column++ ) {
550 uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*BYTES_PER_RGB ];
558 write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
561 #endif /*HAVE_LIBPNG*/
566 * c-file-style: "gnu"
568 * indent-tabs-mode: nil