1 /*****************************************************************************
2 * parse.c: Philips OGT (SVCD subtitle) packet parser
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: parse.c,v 1.1 2003/12/26 01:39:23 rocky Exp $
7 * Authors: Rocky Bernstein
9 * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
10 * Sam Hocevar <sam@zoy.org>
11 * Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
33 #include <vlc/decoder.h>
37 /* An image color is a two-bit palette entry: 0..3 */
38 typedef uint8_t ogt_color_t;
40 /*****************************************************************************
42 *****************************************************************************/
43 static int ParseImage ( decoder_t *, subpicture_t * );
45 static void DestroySPU ( subpicture_t * );
47 static void UpdateSPU ( subpicture_t *, vlc_object_t * );
48 static int CropCallback ( vlc_object_t *, char const *,
49 vlc_value_t, vlc_value_t, void * );
52 The format is roughly as follows (everything is big-endian):
55 -------------------------------------------
56 byte subtitle channel (0..7) in bits 0-3
57 byte subtitle packet number of this subtitle image 0-N,
58 if the subtitle packet is complete, the top bit of the byte is 1.
59 u_int16 subtitle image number
60 u_int16 length in bytes of the rest
61 byte option flags, unknown meaning except bit 3 (0x08) indicates
62 presence of the duration field
64 u_int32 duration in 1/90000ths of a second (optional), start time
65 is as indicated by the PTS in the PES header
68 u_int32 width (must be even)
69 u_int32 height (must be even)
70 byte[16] palette, 4 palette entries, each contains values for
71 Y, U, V and transparency, 0 standing for transparent
73 cmd>>6==1 indicates shift
74 (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
75 u_int32 shift duration in 1/90000ths of a second
76 u_int16 offset of odd-numbered scanlines - subtitle images are
77 given in interlace order
78 byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with
79 2-bits per palette number
82 /* FIXME: do we really need p_buffer and p?
83 Can't all of thes _offset's and _lengths's get removed?
85 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
87 decoder_sys_t *p_sys = p_dec->p_sys;
88 u_int8_t *p = p_buffer;
91 p_sys->i_pts = p_block->i_pts;
92 p_sys->i_spu_size = GETINT16(p);
93 p_sys->i_options = *p++;
94 p_sys->i_options2 = *p++;
96 if ( p_sys->i_options & 0x08 ) {
97 p_sys->i_duration = GETINT32(p);
99 /* 0 means display until next subtitle comes in. */
100 p_sys->i_duration = 0;
102 p_sys->i_x_start= GETINT16(p);
103 p_sys->i_y_start= GETINT16(p);
104 p_sys->i_width = GETINT16(p);
105 p_sys->i_height = GETINT16(p);
107 for (i=0; i<4; i++) {
108 p_sys->pi_palette[i].y = *p++;
109 p_sys->pi_palette[i].u = *p++;
110 p_sys->pi_palette[i].v = *p++;
111 /* We have just 4-bit resolution for alpha, but the value for SVCD
112 * has 8 bits so we scale down the values to the acceptable range */
113 p_sys->pi_palette[i].t = (*p++) >> 4;
116 /* We do not really know this, FIXME */
117 if ( p_sys->i_cmd ) {
118 p_sys->i_cmd_arg = GETINT32(p);
121 /* Actually, this is measured against a different origin, so we have to
123 p_sys->second_field_offset = GETINT16(p);
124 p_sys->comp_image_offset = p - p_buffer;
125 p_sys->comp_image_length = p_sys->i_spu_size - p_sys->comp_image_offset;
126 p_sys->metadata_length = p_sys->comp_image_offset;
128 if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
129 msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
130 "spu size: %d, duration: %u (d:%d p:%d)",
131 p_sys->i_x_start, p_sys->i_y_start,
132 p_sys->i_width, p_sys->i_height,
133 p_sys->i_spu_size, p_sys->i_duration,
134 p_sys->comp_image_length, p_sys->comp_image_offset);
136 for (i=0; i<4; i++) {
137 msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
138 p_sys->pi_palette[i].t, p_sys->pi_palette[i].y,
139 p_sys->pi_palette[i].u, p_sys->pi_palette[i].v );
145 /*****************************************************************************
146 * ParsePacket: parse an SPU packet and send it to the video output
147 *****************************************************************************
148 * This function parses the SPU packet and, if valid, sends it to the
150 *****************************************************************************/
152 E_(ParsePacket)( decoder_t *p_dec)
154 decoder_sys_t *p_sys = p_dec->p_sys;
158 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
160 /* Allocate the subpicture internal data. */
161 p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
167 /* In ParseImage we expand the run-length encoded color 0's; also
168 we expand pixels and remove the color palette. This should
169 facilitate scaling and antialiasing and speed up rendering.
171 p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
172 + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
174 /* Fill the p_spu structure */
175 vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
177 p_spu->pf_render = E_(RenderSPU);
178 p_spu->pf_destroy = DestroySPU;
179 p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
180 p_spu->p_sys->b_palette = VLC_FALSE;
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;
185 p_spu->i_x = p_sys->i_x_start / 2;
186 p_spu->i_y = p_sys->i_y_start;
187 p_spu->i_width = p_sys->i_width;
188 p_spu->i_height = p_sys->i_height;
190 p_spu->i_start = p_sys->i_pts;
191 p_spu->i_stop = p_sys->i_pts + (p_sys->i_duration * 10);
193 p_spu->p_sys->b_crop = VLC_FALSE;
195 /* Get display time now. If we do it later, we may miss the PTS. */
196 p_spu->p_sys->i_pts = p_sys->i_pts;
198 /* Attach to our input thread */
199 p_spu->p_sys->p_input = vlc_object_find( p_dec,
200 VLC_OBJECT_INPUT, FIND_PARENT );
202 /* We try to display it */
203 if( ParseImage( p_dec, p_spu ) )
205 /* There was a parse error, delete the subpicture */
206 vout_DestroySubPicture( p_sys->p_vout, p_spu );
210 /* SPU is finished - we can ask the video output to display it */
211 vout_DisplaySubPicture( p_sys->p_vout, p_spu );
215 /* Advance pointer to image pointer, update internal i_remaining counter
216 and check that we haven't goine too far in the image data. */
217 #define advance_color_pointer_byte \
222 "broken subtitle - tried to access beyond end " \
223 "in image extraction"); \
224 return VLC_EGENERIC; \
227 #define advance_color_pointer \
229 if ( i_remaining == 0 ) { \
230 advance_color_pointer_byte; \
233 /* Get the next field - either a palette index or a RLE count for
234 color 0. To do this we use byte image pointer p, and i_remaining
235 which indicates where we are in the byte.
237 static inline ogt_color_t
238 ExtractField(uint8_t *p, unsigned int i_remaining)
240 return ( ( *p >> 2*(i_remaining-1) ) & 0x3 );
244 /* Scales down (reduces size) of p_dest in the x direction as
245 determined through aspect ratio x_scale by y_scale. Scaling
246 is done in place. i_width, is updated to new ratio.
248 The aspect ratio is assumed to be between 1 and 2.
251 ScaleX( uint8_t *p_dest, /*in out */ u_int16_t *i_width, u_int16_t i_height,
252 unsigned int scale_x, unsigned int scale_y )
255 uint8_t *p1 = p_dest;
256 uint8_t *p2 = p_dest + PIXEL_SIZE;
258 unsigned int used=0; /* Number of bytes used up in p1. */
260 for ( i_row=0; i_row < i_height - 1; i_row++ ) {
261 for ( i_col=0; i_col <= (*i_width)-2; i_col++ ) {
263 unsigned int w1= scale_x - used;
264 unsigned int w2= scale_y - w1;
266 for (i = 0; i < PIXEL_SIZE; i++ ) {
267 *p1 = ( (*p1 * w1) + (*p2 * w2) ) / scale_y;
270 if (scale_x == used) {
277 /* *i_width = ((*i_width) * scale_y) / scale_x; */
281 /*****************************************************************************
282 * ParseImage: parse the image part of the subtitle
283 *****************************************************************************
284 This part parses the subtitle graphical data and stores it in a more
285 convenient structure for later rendering.
287 The image is encoded using two bits per pixel that select a palette
288 entry except that value 0 starts a limited run-length encoding for
289 color 0. When 0 is seen, the next two bits encode one less than the
290 number of pixels, so we can encode run lengths from 1 to 4. These get
291 filled with the color in palette entry 0.
293 The encoding of each line is padded to a whole number of bytes. The
294 first field is padded to an even byte length and the complete subtitle
295 is padded to a 4-byte multiple that always include one zero byte at
298 However we'll transform this so that that the RLE is expanded and
299 interlacing will also be removed. On output each pixel entry will by
300 an 8-bit alpha, y, u, and v entry.
302 *****************************************************************************/
304 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
306 decoder_sys_t *p_sys = p_dec->p_sys;
308 unsigned int i_field; /* The subtitles are interlaced, are we on an
309 even or odd scanline? */
311 unsigned int i_row; /* scanline row number */
312 unsigned int i_column; /* scanline column number */
314 unsigned int i_width = p_sys->i_width;
315 unsigned int i_height = p_sys->i_height;
317 uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
319 uint8_t i_remaining; /* number of 2-bit pixels remaining
321 uint8_t i_pending_zero = 0; /* number of pixels to fill with
323 ogt_color_t i_color; /* current pixel color: 0..3 */
324 uint8_t *p = p_sys->subtitle_data + p_sys->comp_image_offset;
325 uint8_t *maxp = p + p_sys->comp_image_length;
327 dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
330 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
333 for ( i_field=0; i_field < 2; i_field++ ) {
335 for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
336 for ( i_column=0; i_column<i_width; i_column++ ) {
338 if ( i_pending_zero ) {
342 i_color = ExtractField( p, i_remaining);
343 advance_color_pointer;
344 if ( i_color == 0 ) {
345 i_pending_zero = ExtractField( p, i_remaining );
346 advance_color_pointer;
347 /* Fall through with i_color == 0 to output the first cell */
352 p_dest[i_row*i_width+i_column] = i_color;
354 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
355 printf("%1d", i_color);
359 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
362 if ( i_remaining != 4 ) {
363 /* Lines are padded to complete bytes, ignore padding */
364 advance_color_pointer_byte;
367 p = p_sys->subtitle_data + p_sys->comp_image_offset
368 + p_sys->second_field_offset;
371 /* Dump out image not interlaced... */
372 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) {
374 printf("-------------------------------------\n++");
375 for ( i_row=0; i_row < i_height; i_row ++ ) {
376 for ( i_column=0; i_column<i_width; i_column++ ) {
377 printf("%1d", *p++ & 0x03);
381 printf("\n-------------------------------------\n");
384 /* Remove color palette by expanding pixel entries to contain the
385 palette values. We work from the free space at the end to the
386 beginning so we can expand inline.
389 int n = (i_height * i_width) - 1;
390 uint8_t *p_from = p_dest;
391 ogt_yuvt_t *p_to = (ogt_yuvt_t *) p_dest;
393 for ( ; n >= 0 ; n-- ) {
394 p_to[n] = p_sys->pi_palette[p_from[n]];
399 /* The video is automatically scaled. However subtitle bitmaps
400 assume a 1:1 aspect ratio. So we need to scale to compensate for
401 or undo the effects of video output scaling.
403 /* FIXME do the right scaling depending on vout. It may not be 4:3 */
404 ScaleX( p_dest, &(p_sys->i_width), i_height, 3, 4 );
410 /*****************************************************************************
411 * DestroySPU: subpicture destructor
412 *****************************************************************************/
413 static void DestroySPU( subpicture_t *p_spu )
415 if( p_spu->p_sys->p_input )
417 /* Detach from our input thread */
418 var_DelCallback( p_spu->p_sys->p_input, "highlight",
419 CropCallback, p_spu );
420 vlc_object_release( p_spu->p_sys->p_input );
423 vlc_mutex_destroy( &p_spu->p_sys->lock );
424 free( p_spu->p_sys );
427 /*****************************************************************************
428 * UpdateSPU: update subpicture settings
429 *****************************************************************************
430 * This function is called from CropCallback and at initialization time, to
431 * retrieve crop information from the input.
432 *****************************************************************************/
433 static void UpdateSPU( subpicture_t *p_spu, vlc_object_t *p_object )
437 if( var_Get( p_object, "highlight", &val ) )
442 p_spu->p_sys->b_crop = val.b_bool;
443 if( !p_spu->p_sys->b_crop )
448 var_Get( p_object, "x-start", &val );
449 p_spu->p_sys->i_x_start = val.i_int;
450 var_Get( p_object, "y-start", &val );
451 p_spu->p_sys->i_y_start = val.i_int;
452 var_Get( p_object, "x-end", &val );
453 p_spu->p_sys->i_x_end = val.i_int;
454 var_Get( p_object, "y-end", &val );
455 p_spu->p_sys->i_y_end = val.i_int;
459 /*****************************************************************************
460 * CropCallback: called when the highlight properties are changed
461 *****************************************************************************
462 * This callback is called from the input thread when we need cropping
463 *****************************************************************************/
464 static int CropCallback( vlc_object_t *p_object, char const *psz_var,
465 vlc_value_t oldval, vlc_value_t newval, void *p_data )
467 UpdateSPU( (subpicture_t *)p_data, p_object );