]> git.sesse.net Git - vlc/blob - modules/codec/ogt/ogt_parse.c
3fcae76dfa57423cba0884f5a169d9906b10ec02
[vlc] / modules / codec / ogt / ogt_parse.c
1 /*****************************************************************************
2  * Philips OGT (SVCD subtitle) packet parser
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: ogt_parse.c,v 1.3 2003/12/29 04:47:44 rocky Exp $
6  *
7  * Author: 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 "subtitle.h"
36 #include "common.h"
37 #include "render.h"
38 #include "ogt.h"
39
40 /* An image color is a two-bit palette entry: 0..3 */ 
41 typedef uint8_t ogt_color_t;
42
43 /*****************************************************************************
44  * Local prototypes.
45  *****************************************************************************/
46 static int  ParseImage         ( decoder_t *, subpicture_t * );
47
48 /*
49   The format is roughly as follows (everything is big-endian):
50  
51    size     description
52    -------------------------------------------
53    byte     subtitle channel (0..7) in bits 0-3 
54    byte     subtitle packet number of this subtitle image 0-N,
55             if the subtitle packet is complete, the top bit of the byte is 1.
56    u_int16  subtitle image number
57    u_int16  length in bytes of the rest
58    byte     option flags, unknown meaning except bit 3 (0x08) indicates
59             presence of the duration field
60    byte     unknown 
61    u_int32  duration in 1/90000ths of a second (optional), start time
62             is as indicated by the PTS in the PES header
63    u_int32  xpos
64    u_int32  ypos
65    u_int32  width (must be even)
66    u_int32  height (must be even)
67    byte[16] palette, 4 palette entries, each contains values for
68             Y, U, V and transparency, 0 standing for transparent
69    byte     command,
70             cmd>>6==1 indicates shift
71             (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
72    u_int32  shift duration in 1/90000ths of a second
73    u_int16  offset of odd-numbered scanlines - subtitle images are 
74             given in interlace order
75    byte[]   limited RLE image data in interlace order (0,2,4... 1,3,5) with
76             2-bits per palette number
77 */
78
79 /* FIXME: do we really need p_buffer and p? 
80    Can't all of thes _offset's and _lengths's get removed? 
81 */
82 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
83 {
84   decoder_sys_t *p_sys = p_dec->p_sys;
85   u_int8_t *p = p_buffer;
86   int i;
87   
88   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
89
90   p_sys->i_pts    = p_block->i_pts;
91   p_sys->i_spu_size = GETINT16(p);
92   p_sys->i_options  = *p++;
93   p_sys->i_options2 = *p++;
94   
95   if ( p_sys->i_options & 0x08 ) {
96     p_sys->i_duration = GETINT32(p);
97   } else {
98     /* 0 means display until next subtitle comes in. */
99     p_sys->i_duration = 0;
100   }
101   p_sys->i_x_start= GETINT16(p);
102   p_sys->i_y_start= GETINT16(p);
103   p_sys->i_width  = GETINT16(p);
104   p_sys->i_height = GETINT16(p);
105   
106   for (i=0; i<4; i++) {
107     p_sys->pi_palette[i].s.y = *p++;
108     p_sys->pi_palette[i].s.u = *p++;
109     p_sys->pi_palette[i].s.v = *p++;
110     /* OGT has 8-bit resolution for alpha, but DVD's and CVDS use 4-bits.
111        Since we want to use the same render routine, rather than scale up
112        CVD (and DVD) subtitles, we'll scale down ours. 
113     */
114     p_sys->pi_palette[i].s.t = (*p++) >> 4;
115   }
116   p_sys->i_cmd = *p++;
117       /* We do not really know this, FIXME */
118   if ( p_sys->i_cmd ) {
119     p_sys->i_cmd_arg = GETINT32(p);
120   }
121
122   /* Actually, this is measured against a different origin, so we have to
123      adjust it */
124   p_sys->second_field_offset = GETINT16(p);
125   p_sys->comp_image_offset = p - p_buffer;
126   p_sys->comp_image_length = p_sys->i_spu_size - p_sys->comp_image_offset;
127   p_sys->metadata_length   = p_sys->comp_image_offset;
128
129   if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
130     msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
131              "spu size: %d, duration: %u (d:%d p:%d)",
132              p_sys->i_x_start, p_sys->i_y_start, 
133              p_sys->i_width, p_sys->i_height, 
134              p_sys->i_spu_size, p_sys->i_duration,
135              p_sys->comp_image_length, p_sys->comp_image_offset);
136     
137     for (i=0; i<4; i++) {
138       msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
139                p_sys->pi_palette[i].s.t, p_sys->pi_palette[i].s.y, 
140                p_sys->pi_palette[i].s.u, p_sys->pi_palette[i].s.v );
141     }
142   }
143 }
144
145
146 /*****************************************************************************
147  * ParsePacket: parse an SPU packet and send it to the video output
148  *****************************************************************************
149  * This function parses the SPU packet and, if valid, sends it to the
150  * video output.
151  *****************************************************************************/
152 void 
153 E_(ParsePacket)( decoder_t *p_dec)
154 {
155     decoder_sys_t *p_sys = p_dec->p_sys;
156
157     subpicture_t  *p_spu;
158
159     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
160     
161     /* Allocate the subpicture internal data. */
162     p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
163     if( p_spu == NULL )
164     {
165         return;
166     }
167
168     /* In ParseImage we expand the run-length encoded color 0's; also
169        we expand pixels and remove the color palette. This should
170        facilitate scaling and antialiasing and speed up rendering.
171     */
172     p_spu->p_sys = malloc( sizeof( subpicture_sys_t ) 
173                            + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
174
175     /* Fill the p_spu structure */
176     vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
177
178     p_spu->pf_render  = VCDSubRender;
179     p_spu->pf_destroy = VCDSubDestroySPU;
180     p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
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     /* FIXME: use aspect ratio for x? */
186     p_spu->i_x        = p_sys->i_x_start * 3 / 4; 
187     p_spu->i_y        = p_sys->i_y_start;
188     p_spu->i_width    = p_sys->i_width;
189     p_spu->i_height   = p_sys->i_height;
190
191     p_spu->i_start    = p_sys->i_pts;
192     p_spu->i_stop     = p_sys->i_pts + (p_sys->i_duration * 10);
193     
194     p_spu->p_sys->b_crop  = VLC_FALSE;
195     p_spu->p_sys->i_debug = p_sys->i_debug;
196
197     /* Get display time now. If we do it later, we may miss the PTS. */
198     p_spu->p_sys->i_pts = p_sys->i_pts;
199
200     /* Attach to our input thread */
201     p_spu->p_sys->p_input = vlc_object_find( p_dec,
202                                              VLC_OBJECT_INPUT, FIND_PARENT );
203
204     /* We try to display it */
205     if( ParseImage( p_dec, p_spu ) )
206     {
207         /* There was a parse error, delete the subpicture */
208         vout_DestroySubPicture( p_sys->p_vout, p_spu );
209         return;
210     }
211
212     /* SPU is finished - we can ask the video output to display it */
213     vout_DisplaySubPicture( p_sys->p_vout, p_spu );
214
215 }
216
217 /* Advance pointer to image pointer, update internal i_remaining counter
218    and check that we haven't goine too far  in the image data. */
219 #define advance_color_pointer_byte                                      \
220   p++;                                                                  \
221   i_remaining=4;                                                        \
222   if (p >= maxp) {                                                      \
223     msg_Warn( p_dec,                                                    \
224               "broken subtitle - tried to access beyond end "           \
225               "in image extraction");                                   \
226     return VLC_EGENERIC;                                                \
227   }                                                                     \
228
229 #define advance_color_pointer                                           \
230   i_remaining--;                                                        \
231   if ( i_remaining == 0 ) {                                             \
232     advance_color_pointer_byte;                                         \
233   }                                                                     
234
235 /* Get the next field - either a palette index or a RLE count for
236    color 0.  To do this we use byte image pointer p, and i_remaining
237    which indicates where we are in the byte.
238 */
239 static inline ogt_color_t 
240 ExtractField(uint8_t *p, unsigned int i_remaining) 
241 {
242   return ( ( *p >> 2*(i_remaining-1) ) & 0x3 );
243 }
244
245 /*****************************************************************************
246  * ParseImage: parse the image part of the subtitle
247  *****************************************************************************
248  This part parses the subtitle graphical data and stores it in a more
249  convenient structure for later rendering. 
250
251  The image is encoded using two bits per pixel that select a palette
252  entry except that value 0 starts a limited run-length encoding for
253  color 0.  When 0 is seen, the next two bits encode one less than the
254  number of pixels, so we can encode run lengths from 1 to 4. These get
255  filled with the color in palette entry 0.
256
257  The encoding of each line is padded to a whole number of bytes.  The
258  first field is padded to an even byte length and the complete subtitle
259  is padded to a 4-byte multiple that always include one zero byte at
260  the end.
261
262  However we'll transform this so that that the RLE is expanded and
263  interlacing will also be removed. On output each pixel entry will by
264  an 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
265
266  *****************************************************************************/
267 static int 
268 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
269 {
270     decoder_sys_t *p_sys = p_dec->p_sys;
271
272     unsigned int i_field;  /* The subtitles are interlaced, are we on an
273                               even or odd scanline?  */
274
275     unsigned int i_row;    /* scanline row number */
276     unsigned int i_column; /* scanline column number */
277
278     unsigned int i_width  = p_sys->i_width;
279     unsigned int i_height = p_sys->i_height;
280
281     uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
282
283     uint8_t i_remaining;           /* number of 2-bit pixels remaining 
284                                       in byte of *p */
285     uint8_t i_pending_zero = 0;    /* number of pixels to fill with 
286                                       color zero 0..3 */
287     ogt_color_t i_color;           /* current pixel color: 0..3 */
288     uint8_t *p = p_sys->subtitle_data  + p_sys->comp_image_offset;
289     uint8_t *maxp = p + p_sys->comp_image_length;
290
291     dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
292                i_width, i_height);
293
294     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)     
295       printf("\n");
296
297     for ( i_field=0; i_field < 2; i_field++ ) {
298       i_remaining = 4;
299       for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
300         for ( i_column=0; i_column<i_width; i_column++ ) {
301
302           if ( i_pending_zero ) {
303             /* We are in the middle of a RLE expansion, just decrement and 
304                fall through with current color value */
305             i_pending_zero--;
306             i_color = 0;
307           } else {
308             i_color = ExtractField( p, i_remaining);
309             advance_color_pointer;
310             if ( i_color == 0 ) {
311               i_pending_zero = ExtractField( p, i_remaining );
312               advance_color_pointer;
313               /* Fall through with i_color == 0 to output the first cell */
314             }
315           }
316
317           /* Color is 0-3. */
318           p_dest[i_row*i_width+i_column] = i_color;
319
320           if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)       
321             printf("%1d", i_color);
322
323         }
324
325         if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) 
326           printf("\n");
327
328         if ( i_remaining != 4 ) {
329           /* Lines are padded to complete bytes, ignore padding */
330           advance_color_pointer_byte;
331         }
332       }
333       p = p_sys->subtitle_data + p_sys->comp_image_offset 
334         + p_sys->second_field_offset;
335     }
336
337     /* Dump out image not interlaced... */
338     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) {
339       uint8_t *p = p_dest;
340       printf("-------------------------------------\n++");
341       for ( i_row=0; i_row < i_height; i_row ++ ) {
342         for ( i_column=0; i_column<i_width; i_column++ ) {
343           printf("%1d", *p++ & 0x03);
344         }
345         printf("\n++");
346       }
347       printf("\n-------------------------------------\n");
348     }
349
350     /* Remove color palette by expanding pixel entries to contain the
351        palette values. We work from the free space at the end to the
352        beginning so we can expand inline.
353     */
354     {
355       int n = (i_height * i_width) - 1;
356       uint8_t    *p_from = p_dest;
357       ogt_yuvt_t *p_to   = (ogt_yuvt_t *) p_dest;
358       
359       for ( ; n >= 0 ; n-- ) {
360         p_to[n] = p_sys->pi_palette[p_from[n]];
361       }
362     }
363
364     /* The video is automatically scaled. However subtitle bitmaps
365        assume a 1:1 aspect ratio. So we need to scale to compensate for
366        or undo the effects of video output scaling. 
367     */
368     /* FIXME do the right scaling depending on vout. It may not be 4:3 */
369     VCDSubScaleX( p_dec, p_spu, 3, 4 );
370
371     return VLC_SUCCESS;
372 }
373