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