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