da2695eacc7400de5e3e1b78a3a1deb31b100aa0
[vlc.git] / modules / codec / ogt / parse.c
1 /*****************************************************************************
2  * parse.c: Philips OGT (SVCD subtitle) packet parser
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: parse.c,v 1.2 2003/12/27 01:49:59 rocky Exp $
6  *
7  * Authors: Rocky Bernstein 
8  *   based on code from: 
9  *       Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
10  *       Sam 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 "ogt.h"
36
37 /* An image color is a two-bit palette entry: 0..3 */ 
38 typedef uint8_t ogt_color_t;
39
40 /*****************************************************************************
41  * Local prototypes.
42  *****************************************************************************/
43 static int  ParseImage         ( decoder_t *, subpicture_t * );
44
45 static void DestroySPU       ( subpicture_t * );
46
47 static void UpdateSPU        ( subpicture_t *, vlc_object_t * );
48 static int  CropCallback     ( vlc_object_t *, char const *,
49                                vlc_value_t, vlc_value_t, void * );
50
51 /*
52   The format is roughly as follows (everything is big-endian):
53  
54    size     description
55    -------------------------------------------
56    byte     subtitle channel (0..7) in bits 0-3 
57    byte     subtitle packet number of this subtitle image 0-N,
58             if the subtitle packet is complete, the top bit of the byte is 1.
59    u_int16  subtitle image number
60    u_int16  length in bytes of the rest
61    byte     option flags, unknown meaning except bit 3 (0x08) indicates
62             presence of the duration field
63    byte     unknown 
64    u_int32  duration in 1/90000ths of a second (optional), start time
65             is as indicated by the PTS in the PES header
66    u_int32  xpos
67    u_int32  ypos
68    u_int32  width (must be even)
69    u_int32  height (must be even)
70    byte[16] palette, 4 palette entries, each contains values for
71             Y, U, V and transparency, 0 standing for transparent
72    byte     command,
73             cmd>>6==1 indicates shift
74             (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
75    u_int32  shift duration in 1/90000ths of a second
76    u_int16  offset of odd-numbered scanlines - subtitle images are 
77             given in interlace order
78    byte[]   limited RLE image data in interlace order (0,2,4... 1,3,5) with
79             2-bits per palette number
80 */
81
82 /* FIXME: do we really need p_buffer and p? 
83    Can't all of thes _offset's and _lengths's get removed? 
84 */
85 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
86 {
87   decoder_sys_t *p_sys = p_dec->p_sys;
88   u_int8_t *p = p_buffer;
89   int i;
90   
91   p_sys->i_pts    = p_block->i_pts;
92   p_sys->i_spu_size = GETINT16(p);
93   p_sys->i_options  = *p++;
94   p_sys->i_options2 = *p++;
95   
96   if ( p_sys->i_options & 0x08 ) {
97     p_sys->i_duration = GETINT32(p);
98   } else {
99     /* 0 means display until next subtitle comes in. */
100     p_sys->i_duration = 0;
101   }
102   p_sys->i_x_start= GETINT16(p);
103   p_sys->i_y_start= GETINT16(p);
104   p_sys->i_width  = GETINT16(p);
105   p_sys->i_height = GETINT16(p);
106   
107   for (i=0; i<4; i++) {
108     p_sys->pi_palette[i].y = *p++;
109     p_sys->pi_palette[i].u = *p++;
110     p_sys->pi_palette[i].v = *p++;
111     /* We have just 4-bit resolution for alpha, but the value for SVCD
112      * has 8 bits so we scale down the values to the acceptable range */
113         p_sys->pi_palette[i].t = (*p++) >> 4;
114   }
115   p_sys->i_cmd = *p++;
116       /* We do not really know this, FIXME */
117   if ( p_sys->i_cmd ) {
118     p_sys->i_cmd_arg = GETINT32(p);
119   }
120
121   /* Actually, this is measured against a different origin, so we have to
122      adjust it */
123   p_sys->second_field_offset = GETINT16(p);
124   p_sys->comp_image_offset = p - p_buffer;
125   p_sys->comp_image_length = p_sys->i_spu_size - p_sys->comp_image_offset;
126   p_sys->metadata_length   = p_sys->comp_image_offset;
127
128   if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
129     msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
130              "spu size: %d, duration: %u (d:%d p:%d)",
131              p_sys->i_x_start, p_sys->i_y_start, 
132              p_sys->i_width, p_sys->i_height, 
133              p_sys->i_spu_size, p_sys->i_duration,
134              p_sys->comp_image_length, p_sys->comp_image_offset);
135     
136     for (i=0; i<4; i++) {
137       msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
138                p_sys->pi_palette[i].t, p_sys->pi_palette[i].y, 
139                p_sys->pi_palette[i].u, p_sys->pi_palette[i].v );
140     }
141   }
142 }
143
144
145 /*****************************************************************************
146  * ParsePacket: parse an SPU packet and send it to the video output
147  *****************************************************************************
148  * This function parses the SPU packet and, if valid, sends it to the
149  * video output.
150  *****************************************************************************/
151 void 
152 E_(ParsePacket)( decoder_t *p_dec)
153 {
154     decoder_sys_t *p_sys = p_dec->p_sys;
155
156     subpicture_t  *p_spu;
157
158     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
159     
160     /* Allocate the subpicture internal data. */
161     p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
162     if( p_spu == NULL )
163     {
164         return;
165     }
166
167     /* In ParseImage we expand the run-length encoded color 0's; also
168        we expand pixels and remove the color palette. This should
169        facilitate scaling and antialiasing and speed up rendering.
170     */
171     p_spu->p_sys = malloc( sizeof( subpicture_sys_t ) 
172                            + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
173
174     /* Fill the p_spu structure */
175     vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
176
177     p_spu->pf_render = E_(RenderSPU);
178     p_spu->pf_destroy = DestroySPU;
179     p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
180     p_spu->p_sys->b_palette = VLC_FALSE;
181
182     p_spu->p_sys->i_x_end        = p_sys->i_x_start + p_sys->i_width - 1;
183     p_spu->p_sys->i_y_end        = p_sys->i_y_start + p_sys->i_height - 1;
184
185     p_spu->i_x        = p_sys->i_x_start / 2;
186     p_spu->i_y        = p_sys->i_y_start;
187     p_spu->i_width    = p_sys->i_width;
188     p_spu->i_height   = p_sys->i_height;
189
190     p_spu->i_start    = p_sys->i_pts;
191     p_spu->i_stop     = p_sys->i_pts + (p_sys->i_duration * 10);
192     
193     p_spu->p_sys->b_crop = VLC_FALSE;
194
195     /* Get display time now. If we do it later, we may miss the PTS. */
196     p_spu->p_sys->i_pts = p_sys->i_pts;
197
198     /* Attach to our input thread */
199     p_spu->p_sys->p_input = vlc_object_find( p_dec,
200                                              VLC_OBJECT_INPUT, FIND_PARENT );
201
202     /* We try to display it */
203     if( ParseImage( p_dec, p_spu ) )
204     {
205         /* There was a parse error, delete the subpicture */
206         vout_DestroySubPicture( p_sys->p_vout, p_spu );
207         return;
208     }
209
210     /* SPU is finished - we can ask the video output to display it */
211     vout_DisplaySubPicture( p_sys->p_vout, p_spu );
212
213 }
214
215 /* Advance pointer to image pointer, update internal i_remaining counter
216    and check that we haven't goine too far  in the image data. */
217 #define advance_color_pointer_byte                                      \
218   p++;                                                                  \
219   i_remaining=4;                                                        \
220   if (p >= maxp) {                                                      \
221     msg_Warn( p_dec,                                                    \
222               "broken subtitle - tried to access beyond end "           \
223               "in image extraction");                                   \
224     return VLC_EGENERIC;                                                \
225   }                                                                     \
226
227 #define advance_color_pointer                                           \
228   i_remaining--;                                                        \
229   if ( i_remaining == 0 ) {                                             \
230     advance_color_pointer_byte;                                         \
231   }                                                                     
232
233 /* Get the next field - either a palette index or a RLE count for
234    color 0.  To do this we use byte image pointer p, and i_remaining
235    which indicates where we are in the byte.
236 */
237 static inline ogt_color_t 
238 ExtractField(uint8_t *p, unsigned int i_remaining) 
239 {
240   return ( ( *p >> 2*(i_remaining-1) ) & 0x3 );
241 }
242
243 /* Scales down (reduces size) of p_dest in the x direction as 
244    determined through aspect ratio x_scale by y_scale. Scaling
245    is done in place. p_spu->i_width, is updated to new width
246
247    The aspect ratio is assumed to be between 1/2 and 1.
248 */
249 static void
250 ScaleX( decoder_t *p_dec, subpicture_t *p_spu, 
251         unsigned int i_scale_x, unsigned int i_scale_y )
252 {
253   int i_row, i_col;
254
255   decoder_sys_t *p_sys = p_dec->p_sys;
256   uint8_t *p_src1 = p_spu->p_sys->p_data;
257   uint8_t *p_src2 = p_src1 + PIXEL_SIZE;
258   uint8_t *p_dst  = p_src1;
259   unsigned int i_new_width = (p_spu->i_width * i_scale_x) / i_scale_y ;
260   unsigned int used=0;  /* Number of bytes used up in p_src1. */
261
262   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_TRANSFORM) , 
263              "Old width: %d, new width: %d", 
264              p_spu->i_width, i_new_width);
265   
266   for ( i_row=0; i_row <= p_spu->i_height - 1; i_row++ ) {
267
268     if (used != 0) {
269       /* Discard the remaining piece of the colum of the previous line*/
270       used=0;
271       p_src1 = p_src2;
272       p_src2 += PIXEL_SIZE;
273     }
274     
275     for ( i_col=0; i_col <= p_spu->i_width - 2; i_col++ ) {
276       unsigned int i;
277       unsigned int w1= i_scale_x - used;
278       unsigned int w2= i_scale_y - w1;
279
280       used = w2;
281       for (i = 0; i < PIXEL_SIZE; i++ ) {
282         *p_dst = ( (*p_src1 * w1) + (*p_src2 * w2) ) / i_scale_y;
283         p_src1++; p_src2++; p_dst++;
284       }
285
286       if (i_scale_x == used) {
287         /* End of last pixel was end of p_src2. */
288         p_src1 = p_src2;
289         p_src2 += PIXEL_SIZE;
290         i_col++;
291         used = 0;
292       }
293     }
294   }
295   p_spu->i_width = i_new_width;
296
297   if ( p_sys && p_sys->i_debug & DECODE_DBG_TRANSFORM )
298   { 
299     ogt_yuvt_t *p_source = (ogt_yuvt_t *) p_spu->p_sys->p_data;
300     for ( i_row=0; i_row < p_spu->i_height - 1; i_row++ ) {
301       for ( i_col=0; i_col < p_spu->i_width - 1; i_col++ ) {
302         printf("%1x", p_source->t);
303         p_source++;
304       }
305       printf("\n");
306     }
307   }
308
309 }
310
311 /*****************************************************************************
312  * ParseImage: parse the image part of the subtitle
313  *****************************************************************************
314  This part parses the subtitle graphical data and stores it in a more
315  convenient structure for later rendering. 
316
317  The image is encoded using two bits per pixel that select a palette
318  entry except that value 0 starts a limited run-length encoding for
319  color 0.  When 0 is seen, the next two bits encode one less than the
320  number of pixels, so we can encode run lengths from 1 to 4. These get
321  filled with the color in palette entry 0.
322
323  The encoding of each line is padded to a whole number of bytes.  The
324  first field is padded to an even byte length and the complete subtitle
325  is padded to a 4-byte multiple that always include one zero byte at
326  the end.
327
328  However we'll transform this so that that the RLE is expanded and
329  interlacing will also be removed. On output each pixel entry will by 
330  an 8-bit alpha, y, u, and v entry.
331
332  *****************************************************************************/
333 static int 
334 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
335 {
336     decoder_sys_t *p_sys = p_dec->p_sys;
337
338     unsigned int i_field;  /* The subtitles are interlaced, are we on an
339                               even or odd scanline?  */
340
341     unsigned int i_row;    /* scanline row number */
342     unsigned int i_column; /* scanline column number */
343
344     unsigned int i_width  = p_sys->i_width;
345     unsigned int i_height = p_sys->i_height;
346
347     uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
348
349     uint8_t i_remaining;           /* number of 2-bit pixels remaining 
350                                       in byte of *p */
351     uint8_t i_pending_zero = 0;    /* number of pixels to fill with 
352                                       color zero 0..4 */
353     ogt_color_t i_color;           /* current pixel color: 0..3 */
354     uint8_t *p = p_sys->subtitle_data  + p_sys->comp_image_offset;
355     uint8_t *maxp = p + p_sys->comp_image_length;
356
357     dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
358                i_width, i_height);
359
360     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)     
361       printf("\n");
362
363     for ( i_field=0; i_field < 2; i_field++ ) {
364       i_remaining = 4;
365       for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
366         for ( i_column=0; i_column<i_width; i_column++ ) {
367
368           if ( i_pending_zero ) {
369             i_pending_zero--;
370             i_color = 0;
371           } else {
372             i_color = ExtractField( p, i_remaining);
373             advance_color_pointer;
374             if ( i_color == 0 ) {
375               i_pending_zero = ExtractField( p, i_remaining );
376               advance_color_pointer;
377               /* Fall through with i_color == 0 to output the first cell */
378             }
379           }
380
381           /* Color is 0-3. */
382           p_dest[i_row*i_width+i_column] = i_color;
383
384           if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)       
385             printf("%1d", i_color);
386
387         }
388
389         if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) 
390           printf("\n");
391
392         if ( i_remaining != 4 ) {
393           /* Lines are padded to complete bytes, ignore padding */
394           advance_color_pointer_byte;
395         }
396       }
397       p = p_sys->subtitle_data + p_sys->comp_image_offset 
398         + p_sys->second_field_offset;
399     }
400
401     /* Dump out image not interlaced... */
402     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) {
403       uint8_t *p = p_dest;
404       printf("-------------------------------------\n++");
405       for ( i_row=0; i_row < i_height; i_row ++ ) {
406         for ( i_column=0; i_column<i_width; i_column++ ) {
407           printf("%1d", *p++ & 0x03);
408         }
409         printf("\n++");
410       }
411       printf("\n-------------------------------------\n");
412     }
413
414     /* Remove color palette by expanding pixel entries to contain the
415        palette values. We work from the free space at the end to the
416        beginning so we can expand inline.
417     */
418     {
419       int n = (i_height * i_width) - 1;
420       uint8_t    *p_from = p_dest;
421       ogt_yuvt_t *p_to   = (ogt_yuvt_t *) p_dest;
422       
423       for ( ; n >= 0 ; n-- ) {
424         p_to[n] = p_sys->pi_palette[p_from[n]];
425       }
426     }
427
428     /* The video is automatically scaled. However subtitle bitmaps
429        assume a 1:1 aspect ratio. So we need to scale to compensate for
430        or undo the effects of video output scaling. 
431     */
432     /* FIXME do the right scaling depending on vout. It may not be 4:3 */
433     ScaleX( p_dec, p_spu, 3, 4 );
434
435     return VLC_SUCCESS;
436 }
437
438 /*****************************************************************************
439  * DestroySPU: subpicture destructor
440  *****************************************************************************/
441 static void DestroySPU( subpicture_t *p_spu )
442 {
443     if( p_spu->p_sys->p_input )
444     {
445         /* Detach from our input thread */
446         var_DelCallback( p_spu->p_sys->p_input, "highlight",
447                          CropCallback, p_spu );
448         vlc_object_release( p_spu->p_sys->p_input );
449     }
450
451     vlc_mutex_destroy( &p_spu->p_sys->lock );
452     free( p_spu->p_sys );
453 }
454
455 /*****************************************************************************
456  * UpdateSPU: update subpicture settings
457  *****************************************************************************
458  * This function is called from CropCallback and at initialization time, to
459  * retrieve crop information from the input.
460  *****************************************************************************/
461 static void UpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
462 {
463     vlc_value_t val;
464
465     if( var_Get( p_object, "highlight", &val ) )
466     {
467         return;
468     }
469
470     p_spu->p_sys->b_crop = val.b_bool;
471     if( !p_spu->p_sys->b_crop )
472     {
473         return;
474     }
475
476     var_Get( p_object, "x-start", &val );
477     p_spu->p_sys->i_x_start = val.i_int;
478     var_Get( p_object, "y-start", &val );
479     p_spu->p_sys->i_y_start = val.i_int;
480     var_Get( p_object, "x-end", &val );
481     p_spu->p_sys->i_x_end = val.i_int;
482     var_Get( p_object, "y-end", &val );
483     p_spu->p_sys->i_y_end = val.i_int;
484
485 }
486
487 /*****************************************************************************
488  * CropCallback: called when the highlight properties are changed
489  *****************************************************************************
490  * This callback is called from the input thread when we need cropping
491  *****************************************************************************/
492 static int CropCallback( vlc_object_t *p_object, char const *psz_var,
493                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
494 {
495     UpdateSPU( (subpicture_t *)p_data, p_object );
496
497     return VLC_SUCCESS;
498 }
499