First cut at CVD subtitle unit assembly and initial parsing.
[vlc.git] / 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.2 2003/12/28 11:26:52 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     /* Note alpha is 8 bits. DVD's use only 4 bits. Our rendering routine
111        will use an 8-bit transparancy.
112     */
113     p_sys->pi_palette[i].s.t = *p++;
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].s.t, p_sys->pi_palette[i].s.y, 
139                p_sys->pi_palette[i].s.u, p_sys->pi_palette[i].s.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  = VCDSubRender;
178     p_spu->pf_destroy = VCDSubDestroySPU;
179     p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
180
181     p_spu->p_sys->i_x_end        = p_sys->i_x_start + p_sys->i_width - 1;
182     p_spu->p_sys->i_y_end        = p_sys->i_y_start + p_sys->i_height - 1;
183
184     /* FIXME: use aspect ratio for x? */
185     p_spu->i_x        = p_sys->i_x_start * 3 / 4; 
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     p_spu->p_sys->i_debug = p_sys->i_debug;
195
196     /* Get display time now. If we do it later, we may miss the PTS. */
197     p_spu->p_sys->i_pts = p_sys->i_pts;
198
199     /* Attach to our input thread */
200     p_spu->p_sys->p_input = vlc_object_find( p_dec,
201                                              VLC_OBJECT_INPUT, FIND_PARENT );
202
203     /* We try to display it */
204     if( ParseImage( p_dec, p_spu ) )
205     {
206         /* There was a parse error, delete the subpicture */
207         vout_DestroySubPicture( p_sys->p_vout, p_spu );
208         return;
209     }
210
211     /* SPU is finished - we can ask the video output to display it */
212     vout_DisplaySubPicture( p_sys->p_vout, p_spu );
213
214 }
215
216 /* Advance pointer to image pointer, update internal i_remaining counter
217    and check that we haven't goine too far  in the image data. */
218 #define advance_color_pointer_byte                                      \
219   p++;                                                                  \
220   i_remaining=4;                                                        \
221   if (p >= maxp) {                                                      \
222     msg_Warn( p_dec,                                                    \
223               "broken subtitle - tried to access beyond end "           \
224               "in image extraction");                                   \
225     return VLC_EGENERIC;                                                \
226   }                                                                     \
227
228 #define advance_color_pointer                                           \
229   i_remaining--;                                                        \
230   if ( i_remaining == 0 ) {                                             \
231     advance_color_pointer_byte;                                         \
232   }                                                                     
233
234 /* Get the next field - either a palette index or a RLE count for
235    color 0.  To do this we use byte image pointer p, and i_remaining
236    which indicates where we are in the byte.
237 */
238 static inline ogt_color_t 
239 ExtractField(uint8_t *p, unsigned int i_remaining) 
240 {
241   return ( ( *p >> 2*(i_remaining-1) ) & 0x3 );
242 }
243
244 /*****************************************************************************
245  * ParseImage: parse the image part of the subtitle
246  *****************************************************************************
247  This part parses the subtitle graphical data and stores it in a more
248  convenient structure for later rendering. 
249
250  The image is encoded using two bits per pixel that select a palette
251  entry except that value 0 starts a limited run-length encoding for
252  color 0.  When 0 is seen, the next two bits encode one less than the
253  number of pixels, so we can encode run lengths from 1 to 4. These get
254  filled with the color in palette entry 0.
255
256  The encoding of each line is padded to a whole number of bytes.  The
257  first field is padded to an even byte length and the complete subtitle
258  is padded to a 4-byte multiple that always include one zero byte at
259  the end.
260
261  However we'll transform this so that that the RLE is expanded and
262  interlacing will also be removed. On output each pixel entry will by 
263  an 8-bit alpha, y, u, and v entry.
264
265  *****************************************************************************/
266 static int 
267 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
268 {
269     decoder_sys_t *p_sys = p_dec->p_sys;
270
271     unsigned int i_field;  /* The subtitles are interlaced, are we on an
272                               even or odd scanline?  */
273
274     unsigned int i_row;    /* scanline row number */
275     unsigned int i_column; /* scanline column number */
276
277     unsigned int i_width  = p_sys->i_width;
278     unsigned int i_height = p_sys->i_height;
279
280     uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
281
282     uint8_t i_remaining;           /* number of 2-bit pixels remaining 
283                                       in byte of *p */
284     uint8_t i_pending_zero = 0;    /* number of pixels to fill with 
285                                       color zero 0..4 */
286     ogt_color_t i_color;           /* current pixel color: 0..3 */
287     uint8_t *p = p_sys->subtitle_data  + p_sys->comp_image_offset;
288     uint8_t *maxp = p + p_sys->comp_image_length;
289
290     dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
291                i_width, i_height);
292
293     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)     
294       printf("\n");
295
296     for ( i_field=0; i_field < 2; i_field++ ) {
297       i_remaining = 4;
298       for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
299         for ( i_column=0; i_column<i_width; i_column++ ) {
300
301           if ( i_pending_zero ) {
302             i_pending_zero--;
303             i_color = 0;
304           } else {
305             i_color = ExtractField( p, i_remaining);
306             advance_color_pointer;
307             if ( i_color == 0 ) {
308               i_pending_zero = ExtractField( p, i_remaining );
309               advance_color_pointer;
310               /* Fall through with i_color == 0 to output the first cell */
311             }
312           }
313
314           /* Color is 0-3. */
315           p_dest[i_row*i_width+i_column] = i_color;
316
317           if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)       
318             printf("%1d", i_color);
319
320         }
321
322         if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) 
323           printf("\n");
324
325         if ( i_remaining != 4 ) {
326           /* Lines are padded to complete bytes, ignore padding */
327           advance_color_pointer_byte;
328         }
329       }
330       p = p_sys->subtitle_data + p_sys->comp_image_offset 
331         + p_sys->second_field_offset;
332     }
333
334     /* Dump out image not interlaced... */
335     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) {
336       uint8_t *p = p_dest;
337       printf("-------------------------------------\n++");
338       for ( i_row=0; i_row < i_height; i_row ++ ) {
339         for ( i_column=0; i_column<i_width; i_column++ ) {
340           printf("%1d", *p++ & 0x03);
341         }
342         printf("\n++");
343       }
344       printf("\n-------------------------------------\n");
345     }
346
347     /* Remove color palette by expanding pixel entries to contain the
348        palette values. We work from the free space at the end to the
349        beginning so we can expand inline.
350     */
351     {
352       int n = (i_height * i_width) - 1;
353       uint8_t    *p_from = p_dest;
354       ogt_yuvt_t *p_to   = (ogt_yuvt_t *) p_dest;
355       
356       for ( ; n >= 0 ; n-- ) {
357         p_to[n] = p_sys->pi_palette[p_from[n]];
358       }
359     }
360
361     /* The video is automatically scaled. However subtitle bitmaps
362        assume a 1:1 aspect ratio. So we need to scale to compensate for
363        or undo the effects of video output scaling. 
364     */
365     /* FIXME do the right scaling depending on vout. It may not be 4:3 */
366     VCDSubScaleX( p_dec, p_spu, 3, 4 );
367
368     return VLC_SUCCESS;
369 }
370