]> git.sesse.net Git - vlc/blob - modules/codec/ogt/parse.c
Check in a stable copy for reference against future changes. Should
[vlc] / 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.1 2003/12/26 01:39:23 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 #ifdef FINISHED
244 /* Scales down (reduces size) of p_dest in the x direction as 
245    determined through aspect ratio x_scale by y_scale. Scaling
246    is done in place. i_width, is updated to new ratio.
247
248    The aspect ratio is assumed to be between 1 and 2.
249 */
250 static void
251 ScaleX( uint8_t *p_dest, /*in out */ u_int16_t *i_width, u_int16_t i_height,
252         unsigned int scale_x, unsigned int scale_y )
253 {
254   int i_row, i_col;
255   uint8_t *p1 = p_dest;
256   uint8_t *p2 = p_dest + PIXEL_SIZE;
257   
258   unsigned int used=0;  /* Number of bytes used up in p1. */
259
260   for ( i_row=0; i_row < i_height - 1; i_row++ ) {
261     for ( i_col=0; i_col <= (*i_width)-2; i_col++ ) {
262       unsigned int i;
263       unsigned int w1= scale_x - used;
264       unsigned int w2= scale_y - w1;
265       used = w2;
266       for (i = 0; i < PIXEL_SIZE; i++ ) {
267         *p1 = ( (*p1 * w1) + (*p2 * w2) ) / scale_y;
268         p1++; p2++;
269       }
270       if (scale_x == used) {
271         p1 = p2;
272         p2 += PIXEL_SIZE;
273         used = 0;
274       }
275     }
276   }
277   /* *i_width = ((*i_width) * scale_y)  / scale_x; */
278 }
279 #endif
280
281 /*****************************************************************************
282  * ParseImage: parse the image part of the subtitle
283  *****************************************************************************
284  This part parses the subtitle graphical data and stores it in a more
285  convenient structure for later rendering. 
286
287  The image is encoded using two bits per pixel that select a palette
288  entry except that value 0 starts a limited run-length encoding for
289  color 0.  When 0 is seen, the next two bits encode one less than the
290  number of pixels, so we can encode run lengths from 1 to 4. These get
291  filled with the color in palette entry 0.
292
293  The encoding of each line is padded to a whole number of bytes.  The
294  first field is padded to an even byte length and the complete subtitle
295  is padded to a 4-byte multiple that always include one zero byte at
296  the end.
297
298  However we'll transform this so that that the RLE is expanded and
299  interlacing will also be removed. On output each pixel entry will by 
300  an 8-bit alpha, y, u, and v entry.
301
302  *****************************************************************************/
303 static int 
304 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
305 {
306     decoder_sys_t *p_sys = p_dec->p_sys;
307
308     unsigned int i_field;  /* The subtitles are interlaced, are we on an
309                               even or odd scanline?  */
310
311     unsigned int i_row;    /* scanline row number */
312     unsigned int i_column; /* scanline column number */
313
314     unsigned int i_width  = p_sys->i_width;
315     unsigned int i_height = p_sys->i_height;
316
317     uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
318
319     uint8_t i_remaining;           /* number of 2-bit pixels remaining 
320                                       in byte of *p */
321     uint8_t i_pending_zero = 0;    /* number of pixels to fill with 
322                                       color zero 0..4 */
323     ogt_color_t i_color;           /* current pixel color: 0..3 */
324     uint8_t *p = p_sys->subtitle_data  + p_sys->comp_image_offset;
325     uint8_t *maxp = p + p_sys->comp_image_length;
326
327     dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
328                i_width, i_height);
329
330     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)     
331       printf("\n");
332
333     for ( i_field=0; i_field < 2; i_field++ ) {
334       i_remaining = 4;
335       for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
336         for ( i_column=0; i_column<i_width; i_column++ ) {
337
338           if ( i_pending_zero ) {
339             i_pending_zero--;
340             i_color = 0;
341           } else {
342             i_color = ExtractField( p, i_remaining);
343             advance_color_pointer;
344             if ( i_color == 0 ) {
345               i_pending_zero = ExtractField( p, i_remaining );
346               advance_color_pointer;
347               /* Fall through with i_color == 0 to output the first cell */
348             }
349           }
350
351           /* Color is 0-3. */
352           p_dest[i_row*i_width+i_column] = i_color;
353
354           if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)       
355             printf("%1d", i_color);
356
357         }
358
359         if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) 
360           printf("\n");
361
362         if ( i_remaining != 4 ) {
363           /* Lines are padded to complete bytes, ignore padding */
364           advance_color_pointer_byte;
365         }
366       }
367       p = p_sys->subtitle_data + p_sys->comp_image_offset 
368         + p_sys->second_field_offset;
369     }
370
371     /* Dump out image not interlaced... */
372     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) {
373       uint8_t *p = p_dest;
374       printf("-------------------------------------\n++");
375       for ( i_row=0; i_row < i_height; i_row ++ ) {
376         for ( i_column=0; i_column<i_width; i_column++ ) {
377           printf("%1d", *p++ & 0x03);
378         }
379         printf("\n++");
380       }
381       printf("\n-------------------------------------\n");
382     }
383
384     /* Remove color palette by expanding pixel entries to contain the
385        palette values. We work from the free space at the end to the
386        beginning so we can expand inline.
387     */
388     {
389       int n = (i_height * i_width) - 1;
390       uint8_t    *p_from = p_dest;
391       ogt_yuvt_t *p_to   = (ogt_yuvt_t *) p_dest;
392       
393       for ( ; n >= 0 ; n-- ) {
394         p_to[n] = p_sys->pi_palette[p_from[n]];
395       }
396     }
397
398 #ifdef FINISHED
399     /* The video is automatically scaled. However subtitle bitmaps
400        assume a 1:1 aspect ratio. So we need to scale to compensate for
401        or undo the effects of video output scaling. 
402     */
403     /* FIXME do the right scaling depending on vout. It may not be 4:3 */
404     ScaleX( p_dest, &(p_sys->i_width), i_height, 3, 4 );
405 #endif
406
407     return VLC_SUCCESS;
408 }
409
410 /*****************************************************************************
411  * DestroySPU: subpicture destructor
412  *****************************************************************************/
413 static void DestroySPU( subpicture_t *p_spu )
414 {
415     if( p_spu->p_sys->p_input )
416     {
417         /* Detach from our input thread */
418         var_DelCallback( p_spu->p_sys->p_input, "highlight",
419                          CropCallback, p_spu );
420         vlc_object_release( p_spu->p_sys->p_input );
421     }
422
423     vlc_mutex_destroy( &p_spu->p_sys->lock );
424     free( p_spu->p_sys );
425 }
426
427 /*****************************************************************************
428  * UpdateSPU: update subpicture settings
429  *****************************************************************************
430  * This function is called from CropCallback and at initialization time, to
431  * retrieve crop information from the input.
432  *****************************************************************************/
433 static void UpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
434 {
435     vlc_value_t val;
436
437     if( var_Get( p_object, "highlight", &val ) )
438     {
439         return;
440     }
441
442     p_spu->p_sys->b_crop = val.b_bool;
443     if( !p_spu->p_sys->b_crop )
444     {
445         return;
446     }
447
448     var_Get( p_object, "x-start", &val );
449     p_spu->p_sys->i_x_start = val.i_int;
450     var_Get( p_object, "y-start", &val );
451     p_spu->p_sys->i_y_start = val.i_int;
452     var_Get( p_object, "x-end", &val );
453     p_spu->p_sys->i_x_end = val.i_int;
454     var_Get( p_object, "y-end", &val );
455     p_spu->p_sys->i_y_end = val.i_int;
456
457 }
458
459 /*****************************************************************************
460  * CropCallback: called when the highlight properties are changed
461  *****************************************************************************
462  * This callback is called from the input thread when we need cropping
463  *****************************************************************************/
464 static int CropCallback( vlc_object_t *p_object, char const *psz_var,
465                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
466 {
467     UpdateSPU( (subpicture_t *)p_data, p_object );
468
469     return VLC_SUCCESS;
470 }
471