]> git.sesse.net Git - vlc/blob - modules/codec/ogt/cvd_parse.c
common.*: add common routine to eliminate palette from pixmap.
[vlc] / modules / codec / ogt / cvd_parse.c
1 /*****************************************************************************
2  * parse.c: Philips OGT (SVCD subtitle) packet parser
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: cvd_parse.c,v 1.4 2003/12/30 04:43:52 rocky Exp $
6  *
7  * Authors: 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 "render.h"
37 #include "cvd.h"
38 #include "common.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   We do not have information on the subtitle format used on CVD's
50   except the submux sample code and a couple of samples of dubious
51   origin. Thus, this is the result of reading some code whose
52   correctness is not known and some experimentation.
53   
54   CVD subtitles are different in severl ways from SVCD OGT subtitles.
55   First, the image comes first and the metadata is at the end.  So
56   that the metadata can be found easily, the subtitle packet starts
57   with two bytes (everything is big-endian again) that give the total
58   size of the subtitle data and the offset to the metadata - i.e. size
59   of the image data plus the four bytes at the beginning.
60  
61   Image data comes interlaced is run-length encoded.  Each field is a
62   four-bit nibble. Each nibble contains a two-bit repeat count and a
63   two-bit color number so that up to three pixels can be described in
64   four bits.  The function of a 0 repeat count is unknown; it might be
65   used for RLE extension.  However when the full nibble is zero, the
66   rest of the line is filled with the color value in the next nibble.
67   It is unknown what happens if the color value is greater than three.
68   The rest seems to use a 4-entries palette.  It is not impossible
69   that the fill-line complete case above is not as described and the
70   zero repeat count means fill line.  The sample code never produces
71   this, so it may be untested.
72  
73   The metadata section does not follow a fixed pattern, every
74   metadata item consists of a tag byte followed by parameters. In all
75   cases known, the block (including the tag byte) is exactly four
76   bytes in length.  Read the code for the rest.
77 */
78
79 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
80 {
81   decoder_sys_t *p_sys = p_dec->p_sys;
82   u_int8_t *p = p_buffer+1;
83
84   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
85              "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
86              p_buffer[0], p_buffer[1], p_buffer[2], p_buffer[3],
87              p_buffer[4], p_buffer[5],
88              p_block->i_buffer);
89   
90   dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
91
92   p_sys->i_pts    = p_block->i_pts;
93   p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
94
95   /* FIXME: check data sanity */
96   p_sys->metadata_offset = GETINT16(p);
97   p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
98
99   p_sys->comp_image_offset = 4;
100   p_sys->comp_image_length = p_sys->metadata_offset - p_sys->comp_image_offset;
101   
102   dbg_print(DECODE_DBG_PACKET, "total size: %d  image size: %d\n",
103             p_sys->i_spu_size, p_sys->comp_image_length);
104
105 }
106
107
108 /*****************************************************************************
109  * ParsePacket: parse an SPU packet and send it to the video output
110  *****************************************************************************
111  * This function parses the SPU packet and, if valid, sends it to the
112  * video output.
113  *****************************************************************************/
114 void 
115 E_(ParsePacket)( decoder_t *p_dec)
116 {
117     decoder_sys_t *p_sys = p_dec->p_sys;
118
119     subpicture_t  *p_spu;
120
121     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
122
123     /* Allocate the subpicture internal data. */
124     p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
125     if( p_spu == NULL )
126     {
127         return;
128     }
129
130     /* In ParseImage we expand the run-length encoded color 0's; also
131        we expand pixels and remove the color palette. This should
132        facilitate scaling and antialiasing and speed up rendering.
133     */
134     p_spu->p_sys = malloc( sizeof( subpicture_sys_t ) 
135                            + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
136
137     /* Fill the p_spu structure */
138     vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
139
140     p_spu->pf_render  = VCDSubRender;
141     p_spu->pf_destroy = VCDSubDestroySPU;
142     p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
143
144     p_spu->p_sys->i_x_end        = p_sys->i_x_start + p_sys->i_width - 1;
145     p_spu->p_sys->i_y_end        = p_sys->i_y_start + p_sys->i_height - 1;
146
147     /* FIXME: use aspect ratio for x? */
148     p_spu->i_x        = p_sys->i_x_start * 3 / 4; 
149     p_spu->i_y        = p_sys->i_y_start;
150     p_spu->i_width    = p_sys->i_width;
151     p_spu->i_height   = p_sys->i_height;
152
153     p_spu->i_start    = p_sys->i_pts;
154     p_spu->i_stop     = p_sys->i_pts + (p_sys->i_duration * 5);
155     
156     p_spu->p_sys->b_crop  = VLC_FALSE;
157     p_spu->p_sys->i_debug = p_sys->i_debug;
158
159     /* Get display time now. If we do it later, we may miss the PTS. */
160     p_spu->p_sys->i_pts = p_sys->i_pts;
161
162     /* Attach to our input thread */
163     p_spu->p_sys->p_input = vlc_object_find( p_dec,
164                                              VLC_OBJECT_INPUT, FIND_PARENT );
165
166     /* We try to display it */
167     if( ParseImage( p_dec, p_spu ) )
168     {
169         /* There was a parse error, delete the subpicture */
170         vout_DestroySubPicture( p_sys->p_vout, p_spu );
171         return;
172     }
173
174     /* SPU is finished - we can ask the video output to display it */
175     vout_DisplaySubPicture( p_sys->p_vout, p_spu );
176
177 }
178
179 #define advance_color_byte_pointer                                      \
180   p++;                                                                  \
181   i_nibble_field = 2;                                                   \
182   /*                                                                    \
183    * This is wrong, it may exceed maxp if it is the last, check         \
184    * should be moved to use location or the algorithm changed to        \
185    * that in vob2sub                                                    \
186   */                                                                    \
187   if (p >= maxp) {                                                      \
188     msg_Warn( p_dec,                                                    \
189               "broken subtitle - overflow while decoding "              \
190               " padding (%d,%d,%d)\n",                                  \
191               i_field, i_row, i_column );                               \
192     return VLC_EGENERIC;                                                \
193   }                                                                     
194
195 #define CVD_FIELD_BITS (4)
196 #define CVD_FIELD_MASK  ((1<<CVD_FIELD_BITS) - 1) 
197
198 /* Get the next field - a 2-bit palette index and a run count.  To do
199    this we use byte image pointer p, and i_nibble_field which
200    indicates where we are in the byte.
201 */
202 static inline uint8_t
203 ExtractField(uint8_t *p, uint8_t i_nibble_field) 
204 {
205   return ( ( *p >> (CVD_FIELD_BITS*(i_nibble_field-1)) ) & CVD_FIELD_MASK );
206 }
207
208 /*****************************************************************************
209  * ParseImage: parse the image part of the subtitle
210  *****************************************************************************
211  This part parses the subtitle graphical data and stores it in a more
212  convenient structure for later rendering. 
213
214  Image data comes interlaced and is run-length encoded (RLE). Each
215  field is a four-bit nibbles that is further subdivided in a two-bit
216  repeat count and a two-bit color number - up to three pixels can be
217  described in four bits.  What a 0 repeat count means is unknown.  It
218  might be used for RLE extension.  There is a special case of a 0
219  repeat count though.  When the full nibble is zero, the rest of the
220  line is filled with the color value in the next nibble.  It is
221  unknown what happens if the color value is greater than three.  The
222  rest seems to use a 4-entries palette.  It is not impossible that the
223  fill-line complete case above is not as described and the zero repeat
224  count means fill line.  The sample code never produces this, so it
225  may be untested.
226
227  However we'll transform this so that that the RLE is expanded and
228  interlacing will also be removed. On output each pixel entry will by 
229  a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
230
231  *****************************************************************************/
232 static int 
233 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
234 {
235     decoder_sys_t *p_sys = p_dec->p_sys;
236
237     uint8_t i_field;       /* The subtitles are interlaced, are we on an
238                               even or odd scanline?  */
239     unsigned int i_row;    /* scanline row number */
240     unsigned int i_column; /* scanline column number */
241
242     unsigned int i_width  = p_sys->i_width;
243     unsigned int i_height = p_sys->i_height;
244
245     uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
246
247     uint8_t i_nibble_field;    /* The 2-bit pixels remaining in byte of *p.
248                                   Has value 0..2. */
249     vlc_bool_t b_filling;      /* Filling i_color to the of the line. */
250     uint8_t i_pending = 0;     /* number of pixels to fill with 
251                                   color zero 0..3 */
252     ogt_color_t i_color=0;     /* current pixel color: 0..3 */
253     uint8_t *p = p_sys->subtitle_data  + p_sys->comp_image_offset;
254     uint8_t *maxp = p + p_sys->comp_image_length;
255
256     dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d",
257                i_width, i_height);
258
259     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)     
260       printf("\n");
261
262     i_pending = 0;
263
264     for ( i_field=0; i_field < 2; i_field++ ) {
265       i_nibble_field = 2;  /* 4-bit pieces available in *p */
266
267       for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
268         b_filling   = VLC_FALSE;
269         for ( i_column=0; i_column<i_width; i_column++ ) {
270           if ( i_pending ) {
271             /* We are in the middle of a RLE expansion, just decrement and 
272                fall through with current color value */
273             i_pending--;
274           } else if ( b_filling ) {
275             /* We are just filling to the end of line with one color, just
276                reuse current color value */
277           } else {
278             uint8_t i_val = ExtractField(p, i_nibble_field--);
279             if ( i_nibble_field == 0 ) {
280               advance_color_byte_pointer;
281             }
282             if ( i_val == 0 ) {
283               /* fill the rest of the line with next color */
284               i_color = ExtractField( p, i_nibble_field-- );
285               if ( i_nibble_field == 0 ) {
286                 p++;
287                 i_nibble_field=2;
288                 /*
289                   This is wrong, it may exceed maxp if it is the
290                   last, check should be moved to use location or the
291                   algorithm changed to that in vob2sub
292                 */
293                 if (p >= maxp) {
294                   msg_Warn( p_dec, 
295                             "broken subtitle - overflow while decoding "
296                             " filling (%d,%d,%d)", 
297                               i_field, i_row, i_column);
298                   /* return VLC_EGENERIC; */
299                 }
300               }
301               b_filling = VLC_TRUE;
302             } else {
303               /* Normal case: get color and repeat count, 
304                  this iteration will  output the first (or only) 
305                  instance */
306               i_pending = (i_val >> 2);
307               i_color = i_val & 0x3;
308               /* This time counts against the total */
309               i_pending--;
310             }
311           }
312           /* Color is 0-3. */
313           p_dest[i_row*i_width+i_column] = i_color;
314           
315           if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)       
316             printf("%1d", i_color);
317           
318         }
319         
320         if ( i_nibble_field == 1 ) {
321           advance_color_byte_pointer;
322         }
323
324         if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) 
325           printf("\n");
326       }
327     }
328
329     /* Dump out image not interlaced... */
330     if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) {
331       uint8_t *p = p_dest;
332       printf("-------------------------------------\n++");
333       for ( i_row=0; i_row < i_height; i_row ++ ) {
334         for ( i_column=0; i_column<i_width; i_column++ ) {
335           printf("%1d", *p++ & 0x03);
336         }
337         printf("\n++");
338       }
339       printf("\n-------------------------------------\n");
340     }
341
342     VCDInlinePalette( p_dest, p_sys, i_height, i_width );
343
344     /* The video is automatically scaled. However subtitle bitmaps
345        assume a 1:1 aspect ratio. So we need to scale to compensate for
346        or undo the effects of video output scaling. 
347     */
348     /* FIXME do the right scaling depending on vout. It may not be 4:3 */
349     VCDSubScaleX( p_dec, p_spu, 3, 4 );
350
351     /* To be finished...*/
352     return VLC_SUCCESS;
353
354 }
355