1 /*****************************************************************************
2 * Common SVCD and VCD subtitle routines.
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
5 * $Id: common.c,v 1.5 2004/01/11 01:54:20 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>
38 #include "write_png.h"
41 /*****************************************************************************
42 Free Resources associated with subtitle packet.
43 *****************************************************************************/
44 void VCDSubClose( vlc_object_t *p_this )
46 decoder_t *p_dec = (decoder_t*)p_this;
47 decoder_sys_t *p_sys = p_dec->p_sys;
49 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
51 if( !p_sys->b_packetizer )
53 /* FIXME check if it's ok to not lock vout */
54 if( p_sys->p_vout != NULL && p_sys->p_vout->p_subpicture != NULL )
56 subpicture_t * p_subpic;
59 for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
61 p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
63 if( p_subpic != NULL &&
64 ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
65 ( p_subpic->i_status == READY_SUBPICTURE ) ) )
67 vout_DestroySubPicture( p_sys->p_vout, p_subpic );
75 block_ChainRelease( p_sys->p_block );
81 /*****************************************************************************
83 Initialize so the next packet will start off a new one.
85 *****************************************************************************/
87 VCDSubInitSubtitleBlock( decoder_sys_t * p_sys )
89 p_sys->i_spu_size = 0;
90 p_sys->state = SUBTITLE_BLOCK_EMPTY;
92 p_sys->p_block = NULL;
93 p_sys->subtitle_data_pos = 0;
98 VCDSubInitSubtitleData(decoder_sys_t *p_sys)
100 if ( p_sys->subtitle_data ) {
101 if ( p_sys->subtitle_data_size < p_sys->i_spu_size ) {
102 p_sys->subtitle_data = realloc(p_sys->subtitle_data,
104 p_sys->subtitle_data_size = p_sys->i_spu_size;
107 p_sys->subtitle_data = malloc(p_sys->i_spu_size);
108 p_sys->subtitle_data_size = p_sys->i_spu_size;
109 /* FIXME: wrong place to get p_sys */
112 p_sys->subtitle_data_pos = 0;
116 VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
118 decoder_sys_t *p_sys = p_dec->p_sys;
119 int chunk_length = buf_len;
121 if ( chunk_length > p_sys->i_spu_size - p_sys->subtitle_data_pos ) {
122 msg_Warn( p_dec, "too much data (%d) expecting at most %u",
123 chunk_length, p_sys->i_spu_size - p_sys->subtitle_data_pos );
125 chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
128 if ( chunk_length > 0 ) {
132 for (i=0; i<chunk_length; i++)
133 printf ("%02x", b[i]);
137 memcpy(p_sys->subtitle_data + p_sys->subtitle_data_pos,
138 buffer, chunk_length);
139 p_sys->subtitle_data_pos += chunk_length;
140 dbg_print(DECODE_DBG_PACKET, "%d bytes appended, pointer now %d",
141 chunk_length, p_sys->subtitle_data_pos);
146 /*****************************************************************************
147 * FindVout: Find a vout or wait for one to be created.
148 *****************************************************************************/
149 vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
151 vout_thread_t *p_vout = NULL;
153 /* Find an available video output */
156 if( p_dec->b_die || p_dec->b_error )
161 p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
167 msleep( VOUT_OUTMEM_SLEEP );
177 Remove color palette by expanding pixel entries to contain the
178 palette values. We work from the free space at the end to the
179 beginning so we can expand inline.
182 VCDInlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys,
183 unsigned int i_height, unsigned int i_width )
185 int n = (i_height * i_width) - 1;
186 uint8_t *p_from = p_dest;
187 ogt_yuvt_t *p_to = (ogt_yuvt_t *) p_dest;
189 for ( ; n >= 0 ; n-- ) {
190 p_to[n] = p_sys->p_palette[p_from[n]];
195 Check to see if user has overridden subtitle aspect ratio.
196 0 is returned for no override which means just counteract any
200 VCDSubGetAROverride(vlc_object_t * p_input, vout_thread_t *p_vout)
202 char *psz_string = config_GetPsz( p_input, "sub-aspect-ratio" );
204 /* Check whether the user tried to override aspect ratio */
205 if( !psz_string ) return 0;
208 unsigned int i_new_aspect = 0;
209 char *psz_parser = strchr( psz_string, ':' );
213 *psz_parser++ = '\0';
214 i_new_aspect = atoi( psz_string ) * VOUT_ASPECT_FACTOR
215 / atoi( psz_parser );
219 i_new_aspect = p_vout->output.i_width * VOUT_ASPECT_FACTOR
221 / p_vout->output.i_height;
230 Scales down (reduces size) of p_dest in the x direction as
231 determined through aspect ratio x_scale by y_scale. Scaling
232 is done in place. p_spu->i_width, is updated to new width
234 The aspect ratio is assumed to be between 1/2 and 1.
236 Note: the scaling truncates the new width rather than rounds it.
237 Perhaps something one might want to address.
240 VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
241 unsigned int i_scale_x, unsigned int i_scale_y )
245 decoder_sys_t *p_sys = p_dec->p_sys;
246 uint8_t *p_src1 = p_spu->p_sys->p_data;
247 uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
248 uint8_t *p_dst = p_src1;
249 unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
250 unsigned int i_used=0; /* Number of bytes used up in p_src1. */
252 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) ,
253 "aspect ratio %i:%i, Old width: %d, new width: %d",
254 i_scale_x, i_scale_y, p_spu->i_width, i_new_width);
256 if (! (i_scale_x < i_scale_y && i_scale_y < i_scale_x+i_scale_x) )
258 msg_Warn( p_dec, "Need x < y < 2x. x: %i, y: %i", i_scale_x, i_scale_y );
262 for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
265 /* Discard the remaining piece of the column of the previous line*/
268 p_src2 += PIXEL_SIZE;
271 for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
273 unsigned int w1= i_scale_x - i_used;
276 if ( i_scale_y - w1 <= i_scale_x ) {
277 /* Average spans 2 pixels. */
280 for (i = 0; i < PIXEL_SIZE; i++ ) {
281 *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
282 p_src1++; p_src2++; p_dst++;
285 /* Average spans 3 pixels. */
286 unsigned int w0 = w1;
287 unsigned int w1 = i_scale_x;
288 uint8_t *p_src0 = p_src1;
289 w2 = i_scale_y - w0 - w1;
291 p_src2 += PIXEL_SIZE;
293 for (i = 0; i < PIXEL_SIZE; i++ ) {
294 *p_dst = ( (*p_src0 * w0) + (*p_src1 * w1) + (*p_src2 * w2) )
296 p_src0++; p_src1++; p_src2++; p_dst++;
303 if (i_scale_x == i_used) {
304 /* End of last pixel was end of p_src2. */
306 p_src2 += PIXEL_SIZE;
312 p_spu->i_width = i_new_width;
314 if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
316 ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
317 for ( i_row=0; i_row < p_spu->i_height; i_row++ ) {
318 for ( i_col=0; i_col < p_spu->i_width; i_col++ ) {
319 printf("%1x", p_source->s.t);
329 * DestroySPU: subpicture destructor
331 void VCDSubDestroySPU( subpicture_t *p_spu )
333 if( p_spu->p_sys->p_input )
335 /* Detach from our input thread */
336 vlc_object_release( p_spu->p_sys->p_input );
339 vlc_mutex_destroy( &p_spu->p_sys->lock );
340 free( p_spu->p_sys );
343 /*****************************************************************************
344 This callback is called from the input thread when we need cropping
345 *****************************************************************************/
346 int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
347 vlc_value_t oldval, vlc_value_t newval, void *p_data )
349 VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
355 /*****************************************************************************
356 update subpicture settings
357 *****************************************************************************
358 This function is called from CropCallback and at initialization time, to
359 retrieve crop information from the input.
360 *****************************************************************************/
361 void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
365 p_spu->p_sys->b_crop = val.b_bool;
366 if( !p_spu->p_sys->b_crop )
371 if ( VLC_SUCCESS == var_Get( p_object, "x-start", &val ) )
372 p_spu->p_sys->i_x_start = val.i_int;
373 if ( VLC_SUCCESS == var_Get( p_object, "y-start", &val ) )
374 p_spu->p_sys->i_y_start = val.i_int;
375 if ( VLC_SUCCESS == var_Get( p_object, "x-end", &val ) )
376 p_spu->p_sys->i_x_end = val.i_int;
377 if ( VLC_SUCCESS == var_Get( p_object, "y-end", &val ) )
378 p_spu->p_sys->i_y_end = val.i_int;
383 Dump an a subtitle image to standard output - for debugging.
385 void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
387 uint8_t *p = p_image;
388 unsigned int i_row; /* scanline row number */
389 unsigned int i_column; /* scanline column number */
391 printf("-------------------------------------\n++");
392 for ( i_row=0; i_row < i_height; i_row ++ ) {
393 for ( i_column=0; i_column<i_width; i_column++ ) {
394 printf("%1d", *p++ & 0x03);
398 printf("\n-------------------------------------\n");
403 MOVE clip_8_bit and uuv2rgb TO A MORE GENERIC PLACE.
406 /* Force v in the range 0.255 */
407 static inline uint8_t
411 if (v>255) return 255;
415 /***************************************************
416 Color conversion from
417 http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
418 http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html
420 Thanks to Billy Biggs <vektor@dumbterm.net> for the pointer and
421 the following conversion.
423 R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
424 G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
425 B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
427 See also vlc/modules/video_chroma/i420_rgb.h and
428 vlc/modules/video_chroma/i420_rgb_c.h for a way to do this in a way
429 more optimized for integer arithmetic. Would be nice to merge the
432 ***************************************************/
435 yuv2rgb(ogt_yuvt_t *p_yuv, uint8_t *p_rgb_out )
438 int i_Y = p_yuv->s.y - 16;
439 int i_Cb = p_yuv->s.v - 128;
440 int i_Cr = p_yuv->s.u - 128;
442 int i_red = (1.1644 * i_Y) + (1.5960 * i_Cr);
443 int i_green = (1.1644 * i_Y) - (0.3918 * i_Cb) - (0.8130 * i_Cr);
444 int i_blue = (1.1644 * i_Y) + (2.0172 * i_Cb);
446 i_red = clip_8_bit( i_red );
447 i_green = clip_8_bit( i_green );
448 i_blue = clip_8_bit( i_blue );
450 *p_rgb_out++ = i_red;
451 *p_rgb_out++ = i_green;
452 *p_rgb_out++ = i_blue;
458 #define BYTES_PER_RGB 3
459 #define PALETTE_SIZE 4
460 /* Note the below assumes the above is a power of 2 */
461 #define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
464 Dump an a subtitle image to a Portable Network Graphics (PNG) file.
465 All we do here is convert YUV palette entries to RGB, expand
466 the image into a linear RGB pixel array, and call the routine
467 that does the PNG writing.
471 VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
472 uint32_t i_height, uint32_t i_width, const char *filename,
473 png_text *text_ptr, int i_text_count )
475 decoder_sys_t *p_sys = p_dec->p_sys;
476 uint8_t *p = p_image;
477 uint8_t *image_data = malloc(BYTES_PER_RGB * i_height * i_width );
478 uint8_t *q = image_data;
479 unsigned int i_row; /* scanline row number */
480 unsigned int i_column; /* scanline column number */
481 uint8_t rgb_palette[PALETTE_SIZE * BYTES_PER_RGB];
484 dbg_print( (DECODE_DBG_CALL), "%s", filename);
486 if (NULL == image_data) return;
488 /* Convert palette YUV into RGB. */
489 for (i=0; i<PALETTE_SIZE; i++) {
490 ogt_yuvt_t *p_yuv = &(p_sys->p_palette[i]);
491 uint8_t *p_rgb_out = &(rgb_palette[i*BYTES_PER_RGB]);
492 yuv2rgb( p_yuv, p_rgb_out );
495 /* Convert palette entries into linear RGB array. */
496 for ( i_row=0; i_row < i_height; i_row ++ ) {
497 for ( i_column=0; i_column<i_width; i_column++ ) {
498 uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*BYTES_PER_RGB ];
506 write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
509 #endif /*HAVE_LIBPNG*/
514 * c-file-style: "gnu"
516 * indent-tabs-mode: nil