1 /*****************************************************************************
2 * parse.c: Philips OGT (SVCD subtitle) packet parser
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
5 * $Id: cvd_parse.c,v 1.6 2004/01/04 04:56:21 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>
44 /* An image color is a two-bit palette entry: 0..3 */
45 typedef uint8_t ogt_color_t;
47 /*****************************************************************************
49 *****************************************************************************/
50 static int ParseImage ( decoder_t *, subpicture_t * );
53 We do not have information on the subtitle format used on CVD's
54 except the submux sample code and a couple of samples of dubious
55 origin. Thus, this is the result of reading some code whose
56 correctness is not known and some experimentation.
58 CVD subtitles are different in severl ways from SVCD OGT subtitles.
59 First, the image comes first and the metadata is at the end. So
60 that the metadata can be found easily, the subtitle packet starts
61 with two bytes (everything is big-endian again) that give the total
62 size of the subtitle data and the offset to the metadata - i.e. size
63 of the image data plus the four bytes at the beginning.
65 Image data comes interlaced is run-length encoded. Each field is a
66 four-bit nibble. Each nibble contains a two-bit repeat count and a
67 two-bit color number so that up to three pixels can be described in
68 four bits. The function of a 0 repeat count is unknown; it might be
69 used for RLE extension. However when the full nibble is zero, the
70 rest of the line is filled with the color value in the next nibble.
71 It is unknown what happens if the color value is greater than three.
72 The rest seems to use a 4-entries palette. It is not impossible
73 that the fill-line complete case above is not as described and the
74 zero repeat count means fill line. The sample code never produces
75 this, so it may be untested.
77 The metadata section does not follow a fixed pattern, every
78 metadata item consists of a tag byte followed by parameters. In all
79 cases known, the block (including the tag byte) is exactly four
80 bytes in length. Read the code for the rest.
83 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
85 decoder_sys_t *p_sys = p_dec->p_sys;
86 u_int8_t *p = p_buffer+1;
88 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET),
89 "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
90 p_buffer[0], p_buffer[1], p_buffer[2], p_buffer[3],
91 p_buffer[4], p_buffer[5],
94 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
96 p_sys->i_pts = p_block->i_pts;
97 p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
99 /* FIXME: check data sanity */
100 p_sys->metadata_offset = GETINT16(p);
101 p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
103 p_sys->comp_image_offset = 4;
104 p_sys->comp_image_length = p_sys->metadata_offset - p_sys->comp_image_offset;
106 dbg_print(DECODE_DBG_PACKET, "total size: %d image size: %d\n",
107 p_sys->i_spu_size, p_sys->comp_image_length);
111 void E_(ParseMetaInfo)( decoder_t *p_dec )
113 /* last packet in subtitle block. */
115 decoder_sys_t *p_sys = p_dec->p_sys;
116 uint8_t *p = p_sys->subtitle_data + p_sys->metadata_offset;
117 uint8_t *p_end = p + p_sys->metadata_length;
119 dbg_print( (DECODE_DBG_PACKET),
120 "subtitle packet complete, size=%d", p_sys->i_spu );
122 p_sys->state = SUBTITLE_BLOCK_COMPLETE;
125 for ( ; p < p_end; p += 4 ) {
129 case 0x04: /* Display duration in 1/90000ths of a second */
131 p_sys->i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
133 dbg_print( DECODE_DBG_PACKET,
134 "subtitle display duration %u", p_sys->i_duration);
137 case 0x0c: /* Unknown */
138 dbg_print( DECODE_DBG_PACKET,
139 "subtitle command unknown 0x%0x 0x%0x 0x%0x 0x%0x\n",
140 p[0], p[1], p[2], p[3]);
143 case 0x17: /* Position */
144 p_sys->i_x_start = ((p[1]&0x0f)<<6) + (p[2]>>2);
145 p_sys->i_y_start = ((p[2]&0x03)<<8) + p[3];
146 dbg_print( DECODE_DBG_PACKET,
147 "start position (%d,%d): %.2x %.2x %.2x",
148 p_sys->i_x_start, p_sys->i_y_start,
152 case 0x1f: /* Coordinates of the image bottom right */
154 int lastx = ((p[1]&0x0f)<<6) + (p[2]>>2);
155 int lasty = ((p[2]&0x03)<<8) + p[3];
156 p_sys->i_width = lastx - p_sys->i_x_start + 1;
157 p_sys->i_height = lasty - p_sys->i_y_start + 1;
158 dbg_print( DECODE_DBG_PACKET,
159 "end position: (%d,%d): %.2x %.2x %.2x, w x h: %dx%d",
160 lastx, lasty, p[1], p[2], p[3],
161 p_sys->i_width, p_sys->i_height );
171 uint8_t v = p[0]-0x24;
173 /* Primary Palette */
174 dbg_print( DECODE_DBG_PACKET,
175 "primary palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
176 v, p[1], p[2], p[3]);
178 p_sys->p_palette[v].s.y = p[1];
179 p_sys->p_palette[v].s.u = p[2];
180 p_sys->p_palette[v].s.v = p[3];
190 uint8_t v = p[0]-0x2c;
192 dbg_print( DECODE_DBG_PACKET,
193 "highlight palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
194 v, p[1], p[2], p[3]);
196 /* Highlight Palette */
197 p_sys->p_palette_highlight[v].s.y = p[1];
198 p_sys->p_palette_highlight[v].s.u = p[2];
199 p_sys->p_palette_highlight[v].s.v = p[3];
204 /* transparency for primary palette */
205 p_sys->p_palette[0].s.t = p[3] & 0x0f;
206 p_sys->p_palette[1].s.t = p[3] >> 4;
207 p_sys->p_palette[2].s.t = p[2] & 0x0f;
208 p_sys->p_palette[3].s.t = p[2] >> 4;
210 dbg_print( DECODE_DBG_PACKET,
211 "transparancy for primary palette 0..3: "
212 "0x%0x 0x%0x 0x%0x 0x%0x",
213 p_sys->p_palette[0].s.t,
214 p_sys->p_palette[1].s.t,
215 p_sys->p_palette[2].s.t,
216 p_sys->p_palette[3].s.t );
221 /* transparency for highlight palette */
222 p_sys->p_palette_highlight[0].s.t = p[2] & 0x0f;
223 p_sys->p_palette_highlight[1].s.t = p[2] >> 4;
224 p_sys->p_palette_highlight[2].s.t = p[1] & 0x0f;
225 p_sys->p_palette_highlight[3].s.t = p[1] >> 4;
227 dbg_print( DECODE_DBG_PACKET,
228 "transparancy for primary palette 0..3: "
229 "0x%0x 0x%0x 0x%0x 0x%0x",
230 p_sys->p_palette_highlight[0].s.t,
231 p_sys->p_palette_highlight[1].s.t,
232 p_sys->p_palette_highlight[2].s.t,
233 p_sys->p_palette_highlight[3].s.t );
238 /* offset to first field data, we correct to make it relative
239 to comp_image_offset (usually 4) */
240 p_sys->first_field_offset =
241 (p[2] << 8) + p[3] - p_sys->comp_image_offset;
242 dbg_print( DECODE_DBG_PACKET,
243 "first_field_offset %d", p_sys->first_field_offset);
247 /* offset to second field data, we correct to make it relative to
248 comp_image_offset (usually 4) */
249 p_sys->second_field_offset =
250 (p[2] << 8) + p[3] - p_sys->comp_image_offset;
251 dbg_print( DECODE_DBG_PACKET,
252 "second_field_offset %d", p_sys->second_field_offset);
257 "unknown sequence in control header "
258 "0x%0x 0x%0x 0x%0x 0x%0x",
259 p[0], p[1], p[2], p[3]);
261 p_sys->subtitle_data_pos = 0;
266 /*****************************************************************************
267 * ParsePacket: parse an SPU packet and send it to the video output
268 *****************************************************************************
269 * This function parses the SPU packet and, if valid, sends it to the
271 *****************************************************************************/
273 E_(ParsePacket)( decoder_t *p_dec)
275 decoder_sys_t *p_sys = p_dec->p_sys;
279 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
281 /* Allocate the subpicture internal data. */
282 p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
288 /* In ParseImage we expand the run-length encoded color 0's; also
289 we expand pixels and remove the color palette. This should
290 facilitate scaling and antialiasing and speed up rendering.
292 p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
293 + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
295 /* Fill the p_spu structure */
296 vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
298 p_spu->pf_render = VCDSubRender;
299 p_spu->pf_destroy = VCDSubDestroySPU;
300 p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
302 p_spu->p_sys->i_x_end = p_sys->i_x_start + p_sys->i_width - 1;
303 p_spu->p_sys->i_y_end = p_sys->i_y_start + p_sys->i_height - 1;
305 /* FIXME: use aspect ratio for x? */
306 p_spu->i_x = p_sys->i_x_start * 3 / 4;
307 p_spu->i_y = p_sys->i_y_start;
308 p_spu->i_width = p_sys->i_width;
309 p_spu->i_height = p_sys->i_height;
311 p_spu->i_start = p_sys->i_pts;
312 p_spu->i_stop = p_sys->i_pts + (p_sys->i_duration * 5);
314 p_spu->p_sys->b_crop = VLC_FALSE;
315 p_spu->p_sys->i_debug = p_sys->i_debug;
317 /* Get display time now. If we do it later, we may miss the PTS. */
318 p_spu->p_sys->i_pts = p_sys->i_pts;
320 /* Attach to our input thread */
321 p_spu->p_sys->p_input = vlc_object_find( p_dec,
322 VLC_OBJECT_INPUT, FIND_PARENT );
324 /* We try to display it */
325 if( ParseImage( p_dec, p_spu ) )
327 /* There was a parse error, delete the subpicture */
328 vout_DestroySubPicture( p_sys->p_vout, p_spu );
332 /* SPU is finished - we can ask the video output to display it */
333 vout_DisplaySubPicture( p_sys->p_vout, p_spu );
337 #define advance_color_byte_pointer \
339 i_nibble_field = 2; \
341 * This is wrong, it may exceed maxp if it is the last, check \
342 * should be moved to use location or the algorithm changed to \
347 "broken subtitle - overflow while decoding " \
348 " padding (%d,%d,%d)\n", \
349 i_field, i_row, i_column ); \
350 return VLC_EGENERIC; \
353 #define CVD_FIELD_BITS (4)
354 #define CVD_FIELD_MASK ((1<<CVD_FIELD_BITS) - 1)
356 /* Get the next field - a 2-bit palette index and a run count. To do
357 this we use byte image pointer p, and i_nibble_field which
358 indicates where we are in the byte.
360 static inline uint8_t
361 ExtractField(uint8_t *p, uint8_t i_nibble_field)
363 return ( ( *p >> (CVD_FIELD_BITS*(i_nibble_field-1)) ) & CVD_FIELD_MASK );
366 /*****************************************************************************
367 * ParseImage: parse the image part of the subtitle
368 *****************************************************************************
369 This part parses the subtitle graphical data and stores it in a more
370 convenient structure for later rendering.
372 Image data comes interlaced and is run-length encoded (RLE). Each
373 field is a four-bit nibbles that is further subdivided in a two-bit
374 repeat count and a two-bit color number - up to three pixels can be
375 described in four bits. What a 0 repeat count means is unknown. It
376 might be used for RLE extension. There is a special case of a 0
377 repeat count though. When the full nibble is zero, the rest of the
378 line is filled with the color value in the next nibble. It is
379 unknown what happens if the color value is greater than three. The
380 rest seems to use a 4-entries palette. It is not impossible that the
381 fill-line complete case above is not as described and the zero repeat
382 count means fill line. The sample code never produces this, so it
385 However we'll transform this so that that the RLE is expanded and
386 interlacing will also be removed. On output each pixel entry will by
387 a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
389 *****************************************************************************/
391 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
393 decoder_sys_t *p_sys = p_dec->p_sys;
395 uint8_t i_field; /* The subtitles are interlaced, are we on an
396 even or odd scanline? */
397 unsigned int i_row; /* scanline row number */
398 unsigned int i_column; /* scanline column number */
400 unsigned int i_width = p_sys->i_width;
401 unsigned int i_height = p_sys->i_height;
403 uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
405 uint8_t i_nibble_field; /* The 2-bit pixels remaining in byte of *p.
407 vlc_bool_t b_filling; /* Filling i_color to the of the line. */
408 uint8_t i_pending = 0; /* number of pixels to fill with
410 ogt_color_t i_color=0; /* current pixel color: 0..3 */
411 uint8_t *p = p_sys->subtitle_data + p_sys->comp_image_offset;
412 uint8_t *maxp = p + p_sys->comp_image_length;
414 dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d",
417 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
422 for ( i_field=0; i_field < 2; i_field++ ) {
423 i_nibble_field = 2; /* 4-bit pieces available in *p */
428 for (i=0; i< i_width * i_height; i++)
429 printf ("%02x", b[i]);
433 for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
434 b_filling = VLC_FALSE;
435 for ( i_column=0; i_column<i_width; i_column++ ) {
437 /* We are in the middle of a RLE expansion, just decrement and
438 fall through with current color value */
440 } else if ( b_filling ) {
441 /* We are just filling to the end of line with one color, just
442 reuse current color value */
444 uint8_t i_val = ExtractField(p, i_nibble_field--);
445 if ( i_nibble_field == 0 ) {
446 advance_color_byte_pointer;
449 /* fill the rest of the line with next color */
450 i_color = ExtractField( p, i_nibble_field-- );
451 if ( i_nibble_field == 0 ) {
455 This is wrong, it may exceed maxp if it is the
456 last, check should be moved to use location or the
457 algorithm changed to that in vob2sub
461 "broken subtitle - overflow while decoding "
462 " filling (%d,%d,%d)",
463 i_field, i_row, i_column);
464 /* return VLC_EGENERIC; */
467 b_filling = VLC_TRUE;
469 /* Normal case: get color and repeat count,
470 this iteration will output the first (or only)
472 i_pending = (i_val >> 2);
473 i_color = i_val & 0x3;
474 /* This time counts against the total */
479 p_dest[i_row*i_width+i_column] = i_color;
481 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
482 printf("%1d", i_color);
486 if ( i_nibble_field == 1 ) {
487 advance_color_byte_pointer;
490 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
495 if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE)) {
496 /* Dump out image not interlaced... */
497 VCDSubDumpImage( p_dest, i_height, i_width );
501 if (p_sys && (p_sys->i_debug & DECODE_DBG_PNG)) {
503 /* Dump image to a file in PNG format. */
505 png_text text_ptr[TEXT_COUNT];
507 text_ptr[0].key = "Preparer";
508 text_ptr[0].text = "VLC";
509 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
510 text_ptr[1].key = "Description";
511 text_ptr[1].text = "CVD Subtitle";
512 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
514 snprintf(filename, 300, "%s%d.png", "/tmp/vlc-cvd-sub", p_sys->i_image);
515 VCDSubDumpPNG( p_dest, p_dec, i_height, i_width, filename,
516 text_ptr, TEXT_COUNT );
518 #endif /*HAVE_LIBPNG*/
521 VCDInlinePalette( p_dest, p_sys, i_height, i_width );
523 /* The video is automatically scaled. However subtitle bitmaps
524 assume a 1:1 aspect ratio. So we need to scale to compensate for
525 or undo the effects of video output scaling.
527 /* FIXME do the right scaling depending on vout. It may not be 4:3 */
528 VCDSubScaleX( p_dec, p_spu, 3, 4 );
530 /* To be finished...*/