]> git.sesse.net Git - vlc/blob - modules/codec/ogt/ogt_parse.c
* src/video_output/vout_subpictures.c : New OSD channels
[vlc] / modules / codec / ogt / ogt_parse.c
1 /*****************************************************************************
2  * Philips OGT (SVCD subtitle) packet parser
3  *****************************************************************************
4  * Copyright (C) 2003, 2004 VideoLAN
5  * $Id$
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, p_sys->i_subpic_channel,
169                                    MEMORY_SUBPICTURE );
170     if( p_spu == NULL )
171     {
172         return;
173     }
174
175     /* In ParseImage we expand the run-length encoded color 0's; also
176        we expand pixels and remove the color palette. This should
177        facilitate scaling and antialiasing and speed up rendering.
178     */
179     p_spu->p_sys = malloc( sizeof( subpicture_sys_t ) 
180                            + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
181
182     /* Fill the p_spu structure */
183     vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
184
185     p_spu->pf_render  = VCDSubBlend;
186     p_spu->pf_destroy = VCDSubDestroySPU;
187     p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
188
189     p_spu->p_sys->i_x_end        = p_sys->i_x_start + p_sys->i_width - 1;
190     p_spu->p_sys->i_y_end        = p_sys->i_y_start + p_sys->i_height - 1;
191
192     p_spu->i_x        = p_sys->i_x_start 
193       + config_GetInt( p_dec, MODULE_STRING "-horizontal-correct" );
194
195     p_spu->p_sys->p_palette[0] = p_sys->p_palette[0];
196     p_spu->p_sys->p_palette[1] = p_sys->p_palette[1];
197     p_spu->p_sys->p_palette[2] = p_sys->p_palette[2];
198     p_spu->p_sys->p_palette[3] = p_sys->p_palette[3];
199
200     /* FIXME: use aspect ratio for x? */
201     p_spu->i_x        = (p_spu->i_x * 3) / 4; 
202     p_spu->i_y        = p_sys->i_y_start 
203       + config_GetInt( p_dec, MODULE_STRING "-vertical-correct" );
204     p_spu->i_width    = p_sys->i_width;
205     p_spu->i_height   = p_sys->i_height;
206
207     p_spu->i_start    = p_sys->i_pts;
208     p_spu->i_stop     = p_sys->i_pts + p_sys->i_duration;
209     
210     p_spu->p_sys->b_crop  = VLC_FALSE;
211     p_spu->p_sys->i_debug = p_sys->i_debug;
212
213     /* Get display time now. If we do it later, we may miss the PTS. */
214     p_spu->p_sys->i_pts = p_sys->i_pts;
215
216     /* Attach to our input thread */
217     p_spu->p_sys->p_input = vlc_object_find( p_dec,
218                                              VLC_OBJECT_INPUT, FIND_PARENT );
219
220     /* We try to display it */
221     if( ParseImage( p_dec, p_spu ) )
222     {
223         /* There was a parse error, delete the subpicture */
224         vout_DestroySubPicture( p_sys->p_vout, p_spu );
225         return;
226     }
227
228     /* SPU is finished - we can ask the video output to display it */
229     vout_DisplaySubPicture( p_sys->p_vout, p_spu );
230
231 }
232
233 /* Advance pointer to image pointer, update internal i_2bit_field counter
234    and check that we haven't goine too far  in the image data. */
235 #define advance_color_pointer_byte                                      \
236   p++;                                                                  \
237   i_2bit_field=4;                                                       \
238   if (p >= maxp) {                                                      \
239     msg_Warn( p_dec,                                                    \
240               "broken subtitle - tried to access beyond end "           \
241               "in image extraction");                                   \
242     return VLC_EGENERIC;                                                \
243   }                                                                     \
244
245 #define advance_color_pointer                                           \
246   i_2bit_field--;                                                       \
247   if ( i_2bit_field == 0 ) {                                            \
248     advance_color_pointer_byte;                                         \
249   }                                                                     
250
251 #define OGT_FIELD_BITS (2)
252 #define OGT_FIELD_MASK  ((1<<OGT_FIELD_BITS) - 1) 
253
254 /* Get the next field - either a palette index or a RLE count for
255    color 0.  To do this we use byte image pointer p, and i_2bit_field
256    which indicates where we are in the byte.
257 */
258 static inline ogt_color_t 
259 ExtractField(uint8_t *p, unsigned int i_2bit_field) 
260 {
261   return ( ( *p >> (OGT_FIELD_BITS*(i_2bit_field-1)) ) & OGT_FIELD_MASK );
262 }
263
264 /*****************************************************************************
265  * ParseImage: parse the image part of the subtitle
266  *****************************************************************************
267  This part parses the subtitle graphical data and stores it in a more
268  convenient structure for later rendering. 
269
270  The image is encoded using two bits per pixel that select a palette
271  entry except that value 0 starts a limited run-length encoding for
272  color 0.  When 0 is seen, the next two bits encode one less than the
273  number of pixels, so we can encode run lengths from 1 to 4. These get
274  filled with the color in palette entry 0.
275
276  The encoding of each line is padded to a whole number of bytes.  The
277  first field is padded to an even byte length and the complete subtitle
278  is padded to a 4-byte multiple that always include one zero byte at
279  the end.
280
281  However we'll transform this so that that the RLE is expanded and
282  interlacing will also be removed. On output each pixel entry will by
283  an 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
284
285  *****************************************************************************/
286 static int 
287 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
288 {
289     decoder_sys_t *p_sys = p_dec->p_sys;
290
291     unsigned int i_field;  /* The subtitles are interlaced, are we on an
292                               even or odd scanline?  */
293
294     unsigned int i_row;    /* scanline row number */
295     unsigned int i_column; /* scanline column number */
296
297     unsigned int i_width  = p_sys->i_width;
298     unsigned int i_height = p_sys->i_height;
299
300     uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
301
302     uint8_t i_2bit_field;           /* The 2-bit field to sue in byte of *p.
303                                        Has value 0..4. */
304     uint8_t i_pending_zero = 0;    /* number of pixels to fill with 
305                                       color zero 0..3 */
306     ogt_color_t i_color;           /* current pixel color: 0..3 */
307     uint8_t *p = p_sys->subtitle_data  + p_sys->i_image_offset;
308     uint8_t *maxp = p + p_sys->i_image_length;
309
310     dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
311                i_width, i_height);
312
313     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)     
314       printf("\n");
315
316     for ( i_field=0; i_field < 2; i_field++ ) {
317       i_2bit_field = 4;
318       for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
319         for ( i_column=0; i_column<i_width; i_column++ ) {
320
321           if ( i_pending_zero ) {
322             /* We are in the middle of a RLE expansion, just decrement and 
323                fall through with current color value */
324             i_pending_zero--;
325             i_color = 0;
326           } else {
327             i_color = ExtractField( p, i_2bit_field );
328             advance_color_pointer;
329             if ( i_color == 0 ) {
330               i_pending_zero = ExtractField( p, i_2bit_field );
331               advance_color_pointer;
332               /* Fall through with i_color == 0 to output the first cell */
333             }
334           }
335
336           /* Color is 0-3. */
337           p_dest[i_row*i_width+i_column] = i_color;
338
339           if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)       
340             printf("%1d", i_color);
341
342         }
343
344         if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE))
345           printf("\n");
346
347         if ( i_2bit_field != 4 ) {
348           /* Lines are padded to complete bytes, ignore padding */
349           advance_color_pointer_byte;
350         }
351       }
352       p = p_sys->subtitle_data + p_sys->i_image_offset 
353         + p_sys->second_field_offset;
354     }
355
356     if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE)) {
357       /* Dump out image not interlaced... */
358       VCDSubDumpImage( p_dest, i_height, i_width );
359     }
360
361 #ifdef HAVE_LIBPNG
362     if (p_sys && (p_sys->i_debug & DECODE_DBG_PNG)) {
363 #define TEXT_COUNT 2
364       /* Dump image to a file in PNG format. */
365       char filename[300];
366       png_text text_ptr[TEXT_COUNT];
367
368       text_ptr[0].key = "Preparer";
369       text_ptr[0].text = "VLC";
370       text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
371       text_ptr[1].key = "Description";
372       text_ptr[1].text = "SVCD Subtitle";
373       text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
374
375       snprintf(filename, 300, "%s%d.png", "/tmp/vlc-svcd-sub", p_sys->i_image);
376       VCDSubDumpPNG( p_dest, p_dec, i_height, i_width, filename,
377                      text_ptr, TEXT_COUNT );
378     }
379 #endif /*HAVE_LIBPNG*/
380     
381     VCDSubHandleScaling( p_spu, p_dec );
382     return VLC_SUCCESS;
383 }
384
385 \f
386 /* 
387  * Local variables:
388  *  c-file-style: "gnu"
389  *  tab-width: 8
390  *  indent-tabs-mode: nil
391  * End:
392  */