Add vout_AspectRatio routine to get retrieve a vout's aspect ratio.
[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.4 2004/01/10 13:59:25 rocky Exp $
6  *
7  * Author: Rocky Bernstein
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 "common.h"
37 #ifdef HAVE_LIBPNG
38 #include "write_png.h"
39 #endif
40
41 /*****************************************************************************
42  Free Resources associated with subtitle packet.
43  *****************************************************************************/
44 void VCDSubClose( vlc_object_t *p_this )
45 {
46     decoder_t     *p_dec = (decoder_t*)p_this;
47     decoder_sys_t *p_sys = p_dec->p_sys;
48
49     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
50
51     if( !p_sys->b_packetizer )
52     {
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 )
55         {
56             subpicture_t *  p_subpic;
57             int             i_subpic;
58
59             for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
60             {
61                 p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
62
63                 if( p_subpic != NULL &&
64                     ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
65                       ( p_subpic->i_status == READY_SUBPICTURE ) ) )
66                 {
67                     vout_DestroySubPicture( p_sys->p_vout, p_subpic );
68                 }
69             }
70         }
71     }
72
73     if( p_sys->p_block )
74     {
75         block_ChainRelease( p_sys->p_block );
76     }
77
78     free( p_sys );
79 }
80
81 /*****************************************************************************
82
83 Initialize so the next packet will start off a new one.
84
85  *****************************************************************************/
86 void 
87 VCDSubInitSubtitleBlock( decoder_sys_t * p_sys ) 
88 {
89   p_sys->i_spu_size = 0;
90   p_sys->state      = SUBTITLE_BLOCK_EMPTY;
91   p_sys->i_spu      = 0;
92   p_sys->p_block    = NULL;
93   p_sys->subtitle_data_pos = 0;
94
95 }
96
97 void 
98 VCDSubInitSubtitleData(decoder_sys_t *p_sys)
99 {
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,
103                                     p_sys->i_spu_size);
104       p_sys->subtitle_data_size = p_sys->i_spu_size;
105     }
106   } else {
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 */
110     p_sys->i_image = 0;
111   }
112   p_sys->subtitle_data_pos = 0;
113 }
114
115 void 
116 VCDSubAppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
117 {
118   decoder_sys_t *p_sys = p_dec->p_sys;
119   int chunk_length = buf_len;
120
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 );
124
125     chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
126   }
127
128   if ( chunk_length > 0 ) {
129 #if 0
130     int i;
131     int8_t *b=buffer;
132     for (i=0; i<chunk_length; i++)
133       printf ("%02x", b[i]);
134     printf("\n");
135 #endif
136     
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);
142   }
143 }
144
145
146 /*****************************************************************************
147  * FindVout: Find a vout or wait for one to be created.
148  *****************************************************************************/
149 vout_thread_t *VCDSubFindVout( decoder_t *p_dec )
150 {
151     vout_thread_t *p_vout = NULL;
152
153     /* Find an available video output */
154     do
155     {
156         if( p_dec->b_die || p_dec->b_error )
157         {
158             break;
159         }
160
161         p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
162         if( p_vout )
163         {
164             break;
165         }
166
167         msleep( VOUT_OUTMEM_SLEEP );
168     }
169     while( 1 );
170
171     return p_vout;
172 }
173
174
175
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.
179     */
180 void
181 VCDInlinePalette ( /*inout*/ uint8_t *p_dest, decoder_sys_t *p_sys,
182                    unsigned int i_height, unsigned int i_width ) 
183 {
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;
187   
188   for ( ; n >= 0 ; n-- ) {
189     p_to[n] = p_sys->p_palette[p_from[n]];
190   }
191 }
192
193
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
197
198    The aspect ratio is assumed to be between 1/2 and 1.
199 */
200 void
201 VCDSubScaleX( decoder_t *p_dec, subpicture_t *p_spu, 
202               unsigned int i_scale_x, unsigned int i_scale_y )
203 {
204   int i_row, i_col;
205
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. */
212
213   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) , 
214              "aspect ratio %i:%i, Old width: %d, new width: %d", 
215              i_scale_x, i_scale_y, p_spu->i_width, i_new_width);
216   
217   for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
218
219     if (used != 0) {
220       /* Discard the remaining piece of the column of the previous line*/
221       used=0;
222       p_src1 = p_src2;
223       p_src2 += PIXEL_SIZE;
224     }
225     
226     for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
227       unsigned int i;
228       unsigned int w1= i_scale_x - used;
229       unsigned int w2= i_scale_y - w1;
230
231       used = w2;
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++;
235       }
236
237       if (i_scale_x == used) {
238         /* End of last pixel was end of p_src2. */
239         p_src1 = p_src2;
240         p_src2 += PIXEL_SIZE;
241         i_col++;
242         used = 0;
243       }
244     }
245   }
246   p_spu->i_width = i_new_width;
247
248   if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
249   { 
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);
254         p_source++;
255       }
256       printf("\n");
257     }
258   }
259
260 }
261
262 /*****************************************************************************
263  * DestroySPU: subpicture destructor
264  *****************************************************************************/
265 void VCDSubDestroySPU( subpicture_t *p_spu )
266 {
267     if( p_spu->p_sys->p_input )
268     {
269         /* Detach from our input thread */
270         vlc_object_release( p_spu->p_sys->p_input );
271     }
272
273     vlc_mutex_destroy( &p_spu->p_sys->lock );
274     free( p_spu->p_sys );
275 }
276
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 )
282 {
283     VCDSubUpdateSPU( (subpicture_t *)p_data, p_object );
284
285     return VLC_SUCCESS;
286 }
287
288
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 )
296 {
297     vlc_value_t val;
298
299     p_spu->p_sys->b_crop = val.b_bool;
300     if( !p_spu->p_sys->b_crop )
301     {
302         return;
303     }
304
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;
313
314 }
315
316 /* 
317    Dump an a subtitle image to standard output - for debugging.
318  */
319 void VCDSubDumpImage( uint8_t *p_image, uint32_t i_height, uint32_t i_width )
320 {
321   uint8_t *p = p_image;
322   unsigned int i_row;    /* scanline row number */
323   unsigned int i_column; /* scanline column number */
324
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);
329     }
330     printf("\n++");
331   }
332   printf("\n-------------------------------------\n");
333 }
334
335 /* 
336    FIXME: 
337    MOVE clip_8_bit and uuv2rgb TO A MORE GENERIC PLACE.
338  */
339
340 /* Force v in the range 0.255 */
341 static inline uint8_t 
342 clip_8_bit(int v)
343 {
344   if (v<0)   return 0;
345   if (v>255) return 255;
346   return (uint8_t) v;
347 }
348
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
353  
354     Thanks to Billy Biggs <vektor@dumbterm.net> for the pointer and
355     the following conversion.
356  
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 ])
360
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
364   two routines.
365  
366 ***************************************************/
367
368 static inline void
369 yuv2rgb(ogt_yuvt_t *p_yuv, uint8_t *p_rgb_out )
370 {
371   
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;
375   
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);
379   
380   i_red   = clip_8_bit( i_red );
381   i_green = clip_8_bit( i_green );
382   i_blue  = clip_8_bit( i_blue );
383   
384   *p_rgb_out++ = i_red;
385   *p_rgb_out++ = i_green;
386   *p_rgb_out++ = i_blue;
387   
388 }
389
390 #ifdef HAVE_LIBPNG
391
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)
396
397 /* 
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.
402  */
403
404 void 
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 )
408 {
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];
416   int i;
417
418   dbg_print( (DECODE_DBG_CALL), "%s", filename);
419   
420   if (NULL == image_data) return;
421
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 );
427   }
428   
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 ];
433       *q++ = p_rgb[0];
434       *q++ = p_rgb[1];
435       *q++ = p_rgb[2];
436       p++;
437     }
438   }
439   
440   write_png( filename, i_height, i_width, image_data, text_ptr, i_text_count );
441   free(image_data);
442 }
443 #endif /*HAVE_LIBPNG*/