]> git.sesse.net Git - vlc/blob - modules/codec/ogt/ogt_parse.c
* Added "Id" svn:keywords property to all files containing "$Id:".
[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.12 2004/01/22 04:46:19 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 #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     p_sys->i_duration *= config_GetInt( p_dec, MODULE_STRING 
102                                         "-duration-scaling" );
103   } else {
104     /* 0 means display until next subtitle comes in. */
105     p_sys->i_duration = 0;
106   }
107   p_sys->i_x_start= GETINT16(p);
108   p_sys->i_y_start= GETINT16(p);
109   p_sys->i_width  = GETINT16(p);
110   p_sys->i_height = GETINT16(p);
111   
112   for (i=0; i<4; i++) {
113     p_sys->p_palette[i].s.y = *p++;
114     p_sys->p_palette[i].s.u = *p++;
115     p_sys->p_palette[i].s.v = *p++;
116     /* OGT has 8-bit resolution for alpha, but DVD's and CVDS use 4-bits.
117        Since we want to use the same render routine, rather than scale up
118        CVD (and DVD) subtitles, we'll scale down ours. 
119     */
120     p_sys->p_palette[i].s.t = (*p++) >> 4;
121   }
122   p_sys->i_cmd = *p++;
123       /* We do not really know this, FIXME */
124   if ( p_sys->i_cmd ) {
125     p_sys->i_cmd_arg = GETINT32(p);
126   }
127
128   /* Actually, this is measured against a different origin, so we have to
129      adjust it */
130   p_sys->second_field_offset = GETINT16(p);
131   p_sys->i_image_offset  = p - p_buffer;
132   p_sys->i_image_length  = p_sys->i_spu_size - p_sys->i_image_offset;
133   p_sys->metadata_length = p_sys->i_image_offset;
134
135   if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
136     msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
137              "spu size: %d, duration: %lu (d:%d p:%d)",
138              p_sys->i_x_start, p_sys->i_y_start, 
139              p_sys->i_width, p_sys->i_height, 
140              p_sys->i_spu_size, (long unsigned int) p_sys->i_duration,
141              p_sys->i_image_length, p_sys->i_image_offset);
142     
143     for (i=0; i<4; i++) {
144       msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
145                p_sys->p_palette[i].s.t, p_sys->p_palette[i].s.y, 
146                p_sys->p_palette[i].s.u, p_sys->p_palette[i].s.v );
147     }
148   }
149 }
150
151
152 /*****************************************************************************
153  * ParsePacket: parse an SPU packet and send it to the video output
154  *****************************************************************************
155  * This function parses the SPU packet and, if valid, sends it to the
156  * video output.
157  *****************************************************************************/
158 void 
159 E_(ParsePacket)( decoder_t *p_dec)
160 {
161     decoder_sys_t *p_sys = p_dec->p_sys;
162
163     subpicture_t  *p_spu;
164
165     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
166     
167     /* Allocate the subpicture internal data. */
168     p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
169     if( p_spu == NULL )
170     {
171         return;
172     }
173
174     /* In ParseImage we expand the run-length encoded color 0's; also
175        we expand pixels and remove the color palette. This should
176        facilitate scaling and antialiasing and speed up rendering.
177     */
178     p_spu->p_sys = malloc( sizeof( subpicture_sys_t ) 
179                            + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
180
181     /* Fill the p_spu structure */
182     vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
183
184     p_spu->pf_render  = VCDSubBlend;
185     p_spu->pf_destroy = VCDSubDestroySPU;
186     p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
187
188     p_spu->p_sys->i_x_end        = p_sys->i_x_start + p_sys->i_width - 1;
189     p_spu->p_sys->i_y_end        = p_sys->i_y_start + p_sys->i_height - 1;
190
191     p_spu->i_x        = p_sys->i_x_start 
192       + config_GetInt( p_dec, MODULE_STRING "-horizontal-correct" );
193
194     p_spu->p_sys->p_palette[0] = p_sys->p_palette[0];
195     p_spu->p_sys->p_palette[1] = p_sys->p_palette[1];
196     p_spu->p_sys->p_palette[2] = p_sys->p_palette[2];
197     p_spu->p_sys->p_palette[3] = p_sys->p_palette[3];
198
199     /* FIXME: use aspect ratio for x? */
200     p_spu->i_x        = (p_spu->i_x * 3) / 4; 
201     p_spu->i_y        = p_sys->i_y_start 
202       + config_GetInt( p_dec, MODULE_STRING "-vertical-correct" );
203     p_spu->i_width    = p_sys->i_width;
204     p_spu->i_height   = p_sys->i_height;
205
206     p_spu->i_start    = p_sys->i_pts;
207     p_spu->i_stop     = p_sys->i_pts + p_sys->i_duration;
208     
209     p_spu->p_sys->b_crop  = VLC_FALSE;
210     p_spu->p_sys->i_debug = p_sys->i_debug;
211
212     /* Get display time now. If we do it later, we may miss the PTS. */
213     p_spu->p_sys->i_pts = p_sys->i_pts;
214
215     /* Attach to our input thread */
216     p_spu->p_sys->p_input = vlc_object_find( p_dec,
217                                              VLC_OBJECT_INPUT, FIND_PARENT );
218
219     /* We try to display it */
220     if( ParseImage( p_dec, p_spu ) )
221     {
222         /* There was a parse error, delete the subpicture */
223         vout_DestroySubPicture( p_sys->p_vout, p_spu );
224         return;
225     }
226
227     /* SPU is finished - we can ask the video output to display it */
228     vout_DisplaySubPicture( p_sys->p_vout, p_spu );
229
230 }
231
232 /* Advance pointer to image pointer, update internal i_2bit_field counter
233    and check that we haven't goine too far  in the image data. */
234 #define advance_color_pointer_byte                                      \
235   p++;                                                                  \
236   i_2bit_field=4;                                                       \
237   if (p >= maxp) {                                                      \
238     msg_Warn( p_dec,                                                    \
239               "broken subtitle - tried to access beyond end "           \
240               "in image extraction");                                   \
241     return VLC_EGENERIC;                                                \
242   }                                                                     \
243
244 #define advance_color_pointer                                           \
245   i_2bit_field--;                                                       \
246   if ( i_2bit_field == 0 ) {                                            \
247     advance_color_pointer_byte;                                         \
248   }                                                                     
249
250 #define OGT_FIELD_BITS (2)
251 #define OGT_FIELD_MASK  ((1<<OGT_FIELD_BITS) - 1) 
252
253 /* Get the next field - either a palette index or a RLE count for
254    color 0.  To do this we use byte image pointer p, and i_2bit_field
255    which indicates where we are in the byte.
256 */
257 static inline ogt_color_t 
258 ExtractField(uint8_t *p, unsigned int i_2bit_field) 
259 {
260   return ( ( *p >> (OGT_FIELD_BITS*(i_2bit_field-1)) ) & OGT_FIELD_MASK );
261 }
262
263 /*****************************************************************************
264  * ParseImage: parse the image part of the subtitle
265  *****************************************************************************
266  This part parses the subtitle graphical data and stores it in a more
267  convenient structure for later rendering. 
268
269  The image is encoded using two bits per pixel that select a palette
270  entry except that value 0 starts a limited run-length encoding for
271  color 0.  When 0 is seen, the next two bits encode one less than the
272  number of pixels, so we can encode run lengths from 1 to 4. These get
273  filled with the color in palette entry 0.
274
275  The encoding of each line is padded to a whole number of bytes.  The
276  first field is padded to an even byte length and the complete subtitle
277  is padded to a 4-byte multiple that always include one zero byte at
278  the end.
279
280  However we'll transform this so that that the RLE is expanded and
281  interlacing will also be removed. On output each pixel entry will by
282  an 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
283
284  *****************************************************************************/
285 static int 
286 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
287 {
288     decoder_sys_t *p_sys = p_dec->p_sys;
289
290     unsigned int i_field;  /* The subtitles are interlaced, are we on an
291                               even or odd scanline?  */
292
293     unsigned int i_row;    /* scanline row number */
294     unsigned int i_column; /* scanline column number */
295
296     unsigned int i_width  = p_sys->i_width;
297     unsigned int i_height = p_sys->i_height;
298
299     uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
300
301     uint8_t i_2bit_field;           /* The 2-bit field to sue in byte of *p.
302                                        Has value 0..4. */
303     uint8_t i_pending_zero = 0;    /* number of pixels to fill with 
304                                       color zero 0..3 */
305     ogt_color_t i_color;           /* current pixel color: 0..3 */
306     uint8_t *p = p_sys->subtitle_data  + p_sys->i_image_offset;
307     uint8_t *maxp = p + p_sys->i_image_length;
308
309     dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
310                i_width, i_height);
311
312     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)     
313       printf("\n");
314
315     for ( i_field=0; i_field < 2; i_field++ ) {
316       i_2bit_field = 4;
317       for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
318         for ( i_column=0; i_column<i_width; i_column++ ) {
319
320           if ( i_pending_zero ) {
321             /* We are in the middle of a RLE expansion, just decrement and 
322                fall through with current color value */
323             i_pending_zero--;
324             i_color = 0;
325           } else {
326             i_color = ExtractField( p, i_2bit_field );
327             advance_color_pointer;
328             if ( i_color == 0 ) {
329               i_pending_zero = ExtractField( p, i_2bit_field );
330               advance_color_pointer;
331               /* Fall through with i_color == 0 to output the first cell */
332             }
333           }
334
335           /* Color is 0-3. */
336           p_dest[i_row*i_width+i_column] = i_color;
337
338           if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)       
339             printf("%1d", i_color);
340
341         }
342
343         if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE))
344           printf("\n");
345
346         if ( i_2bit_field != 4 ) {
347           /* Lines are padded to complete bytes, ignore padding */
348           advance_color_pointer_byte;
349         }
350       }
351       p = p_sys->subtitle_data + p_sys->i_image_offset 
352         + p_sys->second_field_offset;
353     }
354
355     if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE)) {
356       /* Dump out image not interlaced... */
357       VCDSubDumpImage( p_dest, i_height, i_width );
358     }
359
360 #ifdef HAVE_LIBPNG
361     if (p_sys && (p_sys->i_debug & DECODE_DBG_PNG)) {
362 #define TEXT_COUNT 2
363       /* Dump image to a file in PNG format. */
364       char filename[300];
365       png_text text_ptr[TEXT_COUNT];
366
367       text_ptr[0].key = "Preparer";
368       text_ptr[0].text = "VLC";
369       text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
370       text_ptr[1].key = "Description";
371       text_ptr[1].text = "SVCD Subtitle";
372       text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
373
374       snprintf(filename, 300, "%s%d.png", "/tmp/vlc-svcd-sub", p_sys->i_image);
375       VCDSubDumpPNG( p_dest, p_dec, i_height, i_width, filename,
376                      text_ptr, TEXT_COUNT );
377     }
378 #endif /*HAVE_LIBPNG*/
379     
380     VCDSubHandleScaling( p_spu, p_dec );
381     return VLC_SUCCESS;
382 }
383
384 \f
385 /* 
386  * Local variables:
387  *  c-file-style: "gnu"
388  *  tab-width: 8
389  *  indent-tabs-mode: nil
390  * End:
391  */