1 /*****************************************************************************
2 * Common SVCD and VCD subtitle routines.
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
5 * $Id: common.c,v 1.3 2004/01/03 12:54:56 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 );
176 /* Remove color palette by expanding pixel entries to contain the
177 palette values. We work from the free space at the end to the
178 beginning so we can expand inline.
181 VCDInlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys,
182 unsigned int i_height, unsigned int i_width )
184 int n = (i_height * i_width) - 1;
185 uint8_t *p_from = p_dest;
186 ogt_yuvt_t *p_to = (ogt_yuvt_t *) p_dest;
188 for ( ; n >= 0 ; n-- ) {
189 p_to[n] = p_sys->p_palette[p_from[n]];
194 /* Scales down (reduces size) of p_dest in the x direction as
195 determined through aspect ratio x_scale by y_scale. Scaling
196 is done in place. p_spu->i_width, is updated to new width
198 The aspect ratio is assumed to be between 1/2 and 1.
201 VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu,
202 unsigned int i_scale_x, unsigned int i_scale_y )
206 decoder_sys_t *p_sys = p_dec->p_sys;
207 uint8_t *p_src1 = p_spu->p_sys->p_data;
208 uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
209 uint8_t *p_dst = p_src1;
210 unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
211 unsigned int used=0; /* Number of bytes used up in p_src1. */
213 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) ,
214 "Old width: %d, new width: %d",
215 p_spu->i_width, i_new_width);
217 for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
220 /* Discard the remaining piece of the column of the previous line*/
223 p_src2 += PIXEL_SIZE;
226 for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
228 unsigned int w1= i_scale_x - used;
229 unsigned int w2= i_scale_y - w1;
232 for (i = 0; i < PIXEL_SIZE; i++ ) {
233 *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
234 p_src1++; p_src2++; p_dst++;
237 if (i_scale_x == used) {
238 /* End of last pixel was end of p_src2. */
240 p_src2 += PIXEL_SIZE;
246 p_spu->i_width = i_new_width;
248 if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
250 ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
251 for ( i_row=0; i_row < p_spu->i_height - 1; i_row++ ) {
252 for ( i_col=0; i_col < p_spu->i_width - 1; i_col++ ) {
253 printf("%1x", p_source->s.t);
262 /*****************************************************************************
263 * DestroySPU: subpicture destructor
264 *****************************************************************************/
265 void VCDSubDestroySPU( subpicture_t *p_spu )
267 if( p_spu->p_sys->p_input )
269 /* Detach from our input thread */
270 vlc_object_release( p_spu->p_sys->p_input );
273 vlc_mutex_destroy( &p_spu->p_sys->lock );
274 free( p_spu->p_sys );
277 /*****************************************************************************
278 This callback is called from the input thread when we need cropping
279 *****************************************************************************/
280 int VCDSubCropCallback( vlc_object_t *p_object, char const *psz_var,
281 vlc_value_t oldval, vlc_value_t newval, void *p_data )
283 VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
289 /*****************************************************************************
290 update subpicture settings
291 *****************************************************************************
292 This function is called from CropCallback and at initialization time, to
293 retrieve crop information from the input.
294 *****************************************************************************/
295 void VCDSubUpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
299 p_spu->p_sys->b_crop = val.b_bool;
300 if( !p_spu->p_sys->b_crop )
305 var_Get( p_object, "x-start", &val );
306 p_spu->p_sys->i_x_start = val.i_int;
307 var_Get( p_object, "y-start", &val );
308 p_spu->p_sys->i_y_start = val.i_int;
309 var_Get( p_object, "x-end", &val );
310 p_spu->p_sys->i_x_end = val.i_int;
311 var_Get( p_object, "y-end", &val );
312 p_spu->p_sys->i_y_end = val.i_int;
317 Dump an a subtitle image to standard output - for debugging.
319 void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
321 uint8_t *p = p_image;
322 unsigned int i_row; /* scanline row number */
323 unsigned int i_column; /* scanline column number */
325 printf("-------------------------------------\n++");
326 for ( i_row=0; i_row < i_height; i_row ++ ) {
327 for ( i_column=0; i_column<i_width; i_column++ ) {
328 printf("%1d", *p++ & 0x03);
332 printf("\n-------------------------------------\n");
337 MOVE clip_8_bit and uuv2rgb TO A MORE GENERIC PLACE.
340 /* Force v in the range 0.255 */
341 static inline uint8_t
345 if (v>255) return 255;
349 /***************************************************
350 Color conversion from
351 http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
352 http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html
354 Thanks to Billy Biggs <vektor@dumbterm.net> for the pointer and
355 the following conversion.
357 R' = [ 1.1644 0 1.5960 ] ([ Y' ] [ 16 ])
358 G' = [ 1.1644 -0.3918 -0.8130 ] * ([ Cb ] - [ 128 ])
359 B' = [ 1.1644 2.0172 0 ] ([ Cr ] [ 128 ])
361 See also vlc/modules/video_chroma/i420_rgb.h and
362 vlc/modules/video_chroma/i420_rgb_c.h for a way to do this in a way
363 more optimized for integer arithmetic. Would be nice to merge the
366 ***************************************************/
369 yuv2rgb(ogt_yuvt_t *p_yuv, uint8_t *p_rgb_out )
372 int i_Y = p_yuv->s.y - 16;
373 int i_Cb = p_yuv->s.v - 128;
374 int i_Cr = p_yuv->s.u - 128;
376 int i_red = (1.1644 * i_Y) + (1.5960 * i_Cr);
377 int i_green = (1.1644 * i_Y) - (0.3918 * i_Cb) - (0.8130 * i_Cr);
378 int i_blue = (1.1644 * i_Y) + (2.0172 * i_Cb);
380 i_red = clip_8_bit( i_red );
381 i_green = clip_8_bit( i_green );
382 i_blue = clip_8_bit( i_blue );
384 *p_rgb_out++ = i_red;
385 *p_rgb_out++ = i_green;
386 *p_rgb_out++ = i_blue;
392 #define BYTES_PER_RGB 3
393 #define PALETTE_SIZE 4
394 /* Note the below assumes the above is a power of 2 */
395 #define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
398 Dump an a subtitle image to a Portable Network Graphics (PNG) file.
399 All we do here is convert YUV palette entries to RGB, expand
400 the image into a linear RGB pixel array, and call the routine
401 that does the PNG writing.
405 VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
406 uint32_t i_height, uint32_t i_width, const char *filename,
407 png_text *text_ptr, int i_text_count )
409 decoder_sys_t *p_sys = p_dec->p_sys;
410 uint8_t *p = p_image;
411 uint8_t *image_data = malloc(BYTES_PER_RGB * i_height * i_width );
412 uint8_t *q = image_data;
413 unsigned int i_row; /* scanline row number */
414 unsigned int i_column; /* scanline column number */
415 uint8_t rgb_palette[PALETTE_SIZE * BYTES_PER_RGB];
418 dbg_print( (DECODE_DBG_CALL), "%s", filename);
420 if (NULL == image_data) return;
422 /* Convert palette YUV into RGB. */
423 for (i=0; i<PALETTE_SIZE; i++) {
424 ogt_yuvt_t *p_yuv = &(p_sys->p_palette[i]);
425 uint8_t *p_rgb_out = &(rgb_palette[i*BYTES_PER_RGB]);
426 yuv2rgb( p_yuv, p_rgb_out );
429 /* Convert palette entries into linear RGB array. */
430 for ( i_row=0; i_row < i_height; i_row ++ ) {
431 for ( i_column=0; i_column<i_width; i_column++ ) {
432 uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*BYTES_PER_RGB ];
440 write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
443 #endif /*HAVE_LIBPNG*/