Small doc changes.
[vlc.git] / modules / codec / ogt / common.c
1 /*****************************************************************************
2  * Common SVCD and VCD subtitle routines.
3  *****************************************************************************
4  * Copyright (C) 2003, 2004 VideoLAN
5  * $Id: common.c,v 1.9 2004/01/23 10:19:37 rocky Exp $
6  *
7  * Author: Rocky Bernstein <rocky@panix.com>
8  *   based on code from:
9  *       Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
10  *       Samuel Hocevar <sam@zoy.org>
11  *       Laurent Aimar <fenrir@via.ecp.fr>
12  *
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.
17  *
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.
22  *
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  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <vlc/vlc.h>
32 #include <vlc/vout.h>
33 #include <vlc/decoder.h>
34
35 #include "subtitle.h"
36 #include "pixmap.h"
37 #include "common.h"
38 #ifdef HAVE_LIBPNG
39 #include "write_png.h"
40 #endif
41
42 /*****************************************************************************
43  Free Resources associated with subtitle packet.
44  *****************************************************************************/
45 void VCDSubClose( vlc_object_t *p_this )
46 {
47     decoder_t     *p_dec = (decoder_t*)p_this;
48     decoder_sys_t *p_sys = p_dec->p_sys;
49
50     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
51
52     if( !p_sys->b_packetizer )
53     {
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 )
56         {
57             subpicture_t *  p_subpic;
58             int             i_subpic;
59
60             for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
61             {
62                 p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
63
64                 if( p_subpic != NULL &&
65                     ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
66                       ( p_subpic->i_status == READY_SUBPICTURE ) ) )
67                 {
68                     vout_DestroySubPicture( p_sys->p_vout, p_subpic );
69                 }
70             }
71         }
72     }
73
74     if( p_sys->p_block )
75     {
76         block_ChainRelease( p_sys->p_block );
77     }
78
79     free( p_sys );
80 }
81
82 /*****************************************************************************
83
84 Initialize so the next packet will start off a new one.
85
86  *****************************************************************************/
87 void 
88 VCDSubInitSubtitleBlock( decoder_sys_t * p_sys ) 
89 {
90   p_sys->i_spu_size = 0;
91   p_sys->state      = SUBTITLE_BLOCK_EMPTY;
92   p_sys->i_spu      = 0;
93   p_sys->p_block    = NULL;
94   p_sys->subtitle_data_pos = 0;
95
96 }
97
98 void 
99 VCDSubInitSubtitleData(decoder_sys_t *p_sys)
100 {
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,
104                                     p_sys->i_spu_size);
105       p_sys->subtitle_data_size = p_sys->i_spu_size;
106     }
107   } else {
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 */
111     p_sys->i_image = 0;
112   }
113   p_sys->subtitle_data_pos = 0;
114 }
115
116 void 
117 VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
118 {
119   decoder_sys_t *p_sys = p_dec->p_sys;
120   int chunk_length = buf_len;
121
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 );
125
126     chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
127   }
128
129   if ( chunk_length > 0 ) {
130 #if 0
131     int i;
132     int8_t *b=buffer;
133     for (i=0; i<chunk_length; i++)
134       printf ("%02x", b[i]);
135     printf("\n");
136 #endif
137     
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);
143   }
144 }
145
146
147 /*****************************************************************************
148  * FindVout: Find a vout or wait for one to be created.
149  *****************************************************************************/
150 vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
151 {
152     vout_thread_t *p_vout = NULL;
153
154     /* Find an available video output */
155     do
156     {
157         if( p_dec->b_die || p_dec->b_error )
158         {
159             break;
160         }
161
162         p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
163         if( p_vout )
164         {
165             break;
166         }
167
168         msleep( VOUT_OUTMEM_SLEEP );
169     }
170     while( 1 );
171
172     return p_vout;
173 }
174
175
176
177 /**
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.
181 */
182 static void
183 InlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys )
184 {
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;
190   
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]];*/
194   }
195 }
196
197 /**
198    Check to see if user has overridden subtitle aspect ratio. 
199    0 is returned for no override which means just counteract any
200    scaling effects.
201 */
202 unsigned int 
203 VCDSubGetAROverride(vlc_object_t * p_input, vout_thread_t *p_vout)
204 {
205   char *psz_string = config_GetPsz( p_input, MODULE_STRING "-aspect-ratio" );
206
207   /* Check whether the user tried to override aspect ratio */
208   if( !psz_string ) return 0;
209
210   {
211     unsigned int i_new_aspect = 0;
212     char *psz_parser = strchr( psz_string, ':' );
213     
214     if( psz_parser )
215       {
216         *psz_parser++ = '\0';
217         i_new_aspect = atoi( psz_string ) * VOUT_ASPECT_FACTOR
218           / atoi( psz_parser );
219       }
220     else
221       {
222         i_new_aspect = p_vout->output.i_width * VOUT_ASPECT_FACTOR
223           * atof( psz_string )
224           / p_vout->output.i_height;
225       }
226     
227     return i_new_aspect;
228   }
229 }
230
231
232 /**
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
236
237    The aspect ratio is assumed to be between 1/2 and 1.
238
239    Note: the scaling truncates the new width rather than rounds it.
240    Perhaps something one might want to address.
241 */
242 void
243 VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu, 
244               unsigned int i_scale_x, unsigned int i_scale_y )
245 {
246   int i_row, i_col;
247
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. */
254
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);
258
259   if (! (i_scale_x < i_scale_y && i_scale_y < i_scale_x+i_scale_x) )
260     {
261       msg_Warn( p_dec, "Need x < y < 2x. x: %i, y: %i", i_scale_x, i_scale_y );
262       return;
263     }
264   
265   for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
266
267     if (i_used != 0) {
268       /* Discard the remaining piece of the column of the previous line*/
269       i_used=0;
270       p_src1 = p_src2;
271       p_src2 += PIXEL_SIZE;
272     }
273     
274     for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
275       unsigned int i;
276       unsigned int w1= i_scale_x - i_used;
277       unsigned int w2;
278       
279       if ( i_scale_y - w1 <= i_scale_x ) {
280         /* Average spans 2 pixels. */
281         w2 = i_scale_y - w1;
282
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++;
286         }
287       } else {
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;
293         p_src1 = p_src2;
294         p_src2 += PIXEL_SIZE;
295         
296         for (i = 0; i < PIXEL_SIZE; i++ ) {
297           *p_dst = ( (*p_src0 * w0) + (*p_src1 * w1) + (*p_src2 * w2) ) 
298                      / i_scale_y;
299           p_src0++; p_src1++; p_src2++; p_dst++;
300         }
301         i_col++;
302       }
303
304       i_used = w2;
305
306       if (i_scale_x == i_used) {
307         /* End of last pixel was end of p_src2. */
308         p_src1 = p_src2;
309         p_src2 += PIXEL_SIZE;
310         i_col++;
311         i_used = 0;
312       }
313     }
314   }
315   p_spu->i_width = i_new_width;
316
317   if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
318   { 
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);
323         p_source++;
324       }
325       printf("\n");
326     }
327   }
328
329 }
330
331 /**
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
335    output scaling.
336    
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.
340
341    We also expand palette entries here, unless we are dealing with a 
342    palettized chroma (e.g. RGB2).
343 */
344
345 void 
346 VCDSubHandleScaling( subpicture_t *p_spu, decoder_t *p_dec )
347 {
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, 
350                                            FIND_CHILD );
351   unsigned int i_aspect_x, i_aspect_y;
352   uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
353
354   if (p_vout) {
355     /* Check for user-configuration override. */
356     unsigned int i_new_aspect;
357     
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.
362        */
363       return;
364     }
365         
366     InlinePalette( p_dest, p_dec->p_sys );
367     i_new_aspect = VCDSubGetAROverride( p_input, p_vout );
368
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.
372       */
373       ;
374     } else {
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.
379         */
380         switch( p_vout->output.i_chroma )
381           {
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'):
389             break;
390             
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'):
397             return;
398             break;
399             
400           default:
401             msg_Err( p_vout, "unknown chroma %x", 
402                      p_vout->output.i_chroma );
403             return;
404             break;
405           }
406         /* We get here only for scaled chromas. */
407         vout_AspectRatio( p_vout->render.i_aspect, &i_aspect_y, 
408                           &i_aspect_x );
409       } else {
410         /* User knows best? */
411         vout_AspectRatio( i_new_aspect, &i_aspect_x, &i_aspect_y );
412       }
413       VCDSubScaleX( p_dec, p_spu, i_aspect_x, i_aspect_y );
414     }
415   }
416 }
417
418
419 /**
420  * DestroySPU: subpicture destructor
421  */
422 void VCDSubDestroySPU( subpicture_t *p_spu )
423 {
424     if( p_spu->p_sys->p_input )
425     {
426         /* Detach from our input thread */
427         vlc_object_release( p_spu->p_sys->p_input );
428     }
429
430     vlc_mutex_destroy( &p_spu->p_sys->lock );
431     free( p_spu->p_sys );
432 }
433
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 )
439 {
440     VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
441
442     return VLC_SUCCESS;
443 }
444
445
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 )
453 {
454     vlc_value_t val;
455
456     p_spu->p_sys->b_crop = val.b_bool;
457     if( !p_spu->p_sys->b_crop )
458     {
459         return;
460     }
461
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;
470
471 }
472
473 /* 
474    Dump an a subtitle image to standard output - for debugging.
475  */
476 void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
477 {
478   uint8_t *p = p_image;
479   unsigned int i_row;    /* scanline row number */
480   unsigned int i_column; /* scanline column number */
481
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);
486     }
487     printf("\n++");
488   }
489   printf("\n-------------------------------------\n");
490 }
491
492 /***************************************************
493    Color conversion from
494     http://www.inforamp.net/~poynton/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
495     http://people.ee.ethz.ch/~buc/brechbuehler/mirror/color/ColorFAQ.html
496  
497     Thanks to Billy Biggs <vektor@dumbterm.net> for the pointer and
498     the following conversion.
499  
500     R' = [ 1.1644         0    1.5960 ]   ([ Y' ]   [  16 ])
501     G' = [ 1.1644   -0.3918   -0.8130 ] * ([ Cb ] - [ 128 ])
502     B' = [ 1.1644    2.0172         0 ]   ([ Cr ]   [ 128 ])
503
504   See also vlc/modules/video_chroma/i420_rgb.h and
505   vlc/modules/video_chroma/i420_rgb_c.h for a way to do this in a way
506   more optimized for integer arithmetic. Would be nice to merge the
507   two routines.
508  
509 ***************************************************/
510
511 #ifdef HAVE_LIBPNG
512
513 #define BYTES_PER_RGB 3
514 #define PALETTE_SIZE  4
515 /* Note the below assumes the above is a power of 2 */
516 #define PALETTE_SIZE_MASK (PALETTE_SIZE-1)
517
518 /* 
519    Dump an a subtitle image to a Portable Network Graphics (PNG) file.
520    All we do here is convert YUV palette entries to RGB, expand
521    the image into a linear RGB pixel array, and call the routine
522    that does the PNG writing.
523  */
524
525 void 
526 VCDSubDumpPNG( uint8_t *p_image, decoder_t *p_dec,
527                uint32_t i_height, uint32_t i_width, const char *filename,
528                png_text *text_ptr, int i_text_count )
529 {
530   decoder_sys_t *p_sys = p_dec->p_sys;
531   uint8_t *p = p_image;
532   uint8_t *image_data = malloc(BYTES_PER_RGB * i_height * i_width );
533   uint8_t *q = image_data;
534   unsigned int i_row;    /* scanline row number */
535   unsigned int i_column; /* scanline column number */
536   uint8_t rgb_palette[PALETTE_SIZE * BYTES_PER_RGB];
537   int i;
538
539   dbg_print( (DECODE_DBG_CALL), "%s", filename);
540   
541   if (NULL == image_data) return;
542
543   /* Convert palette YUV into RGB. */
544   for (i=0; i<PALETTE_SIZE; i++) {
545     ogt_yuvt_t *p_yuv     = &(p_sys->p_palette[i]);
546     uint8_t   *p_rgb_out  = &(rgb_palette[i*BYTES_PER_RGB]);
547     yuv2rgb( p_yuv, p_rgb_out );
548   }
549   
550   /* Convert palette entries into linear RGB array. */
551   for ( i_row=0; i_row < i_height; i_row ++ ) {
552     for ( i_column=0; i_column<i_width; i_column++ ) {
553       uint8_t *p_rgb = &rgb_palette[ ((*p)&PALETTE_SIZE_MASK)*BYTES_PER_RGB ];
554       *q++ = p_rgb[0];
555       *q++ = p_rgb[1];
556       *q++ = p_rgb[2];
557       p++;
558     }
559   }
560   
561   write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
562   free(image_data);
563 }
564 #endif /*HAVE_LIBPNG*/
565
566 \f
567 /* 
568  * Local variables:
569  *  c-file-style: "gnu"
570  *  tab-width: 8
571  *  indent-tabs-mode: nil
572  * End:
573  */