1 /*****************************************************************************
2 * svcdsub.c : Overlay Graphics Text (SVCD subtitles) decoder
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
7 * Authors: Rocky Bernstein
8 * Gildas Bazin <gbazin@videolan.org>
9 * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
10 * Laurent Aimar <fenrir@via.ecp.fr>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
33 #include <vlc/decoder.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 static int DecoderOpen ( vlc_object_t * );
41 static int PacketizerOpen( vlc_object_t * );
42 static void DecoderClose ( vlc_object_t * );
45 set_description( _("Philips OGT (SVCD subtitle) decoder") );
46 set_shortname( N_("SVCD subtitles"));
47 set_category( CAT_INPUT );
48 set_subcategory( SUBCAT_INPUT_SCODEC );
49 set_capability( "decoder", 50 );
50 set_callbacks( DecoderOpen, DecoderClose );
53 set_description( _("Philips OGT (SVCD subtitle) packetizer") );
54 set_capability( "packetizer", 50 );
55 set_callbacks( PacketizerOpen, DecoderClose );
58 /*****************************************************************************
60 *****************************************************************************/
61 static subpicture_t *Decode( decoder_t *, block_t ** );
62 static block_t *Packetize ( decoder_t *, block_t ** );
63 static block_t *Reassemble ( decoder_t *, block_t * );
64 static void ParseHeader( decoder_t *, block_t * );
65 static subpicture_t *DecodePacket( decoder_t *, block_t * );
66 static void RenderImage( decoder_t *, block_t *, subpicture_region_t * );
68 #define GETINT16(p) ( (p[0] << 8) + p[1] ) ; p +=2;
70 #define GETINT32(p) ( (p[0] << 24) + (p[1] << 16) + \
71 (p[2] << 8) + (p[3]) ) ; p += 4;
73 #define SUBTITLE_BLOCK_EMPTY 0
74 #define SUBTITLE_BLOCK_PARTIAL 1
75 #define SUBTITLE_BLOCK_COMPLETE 2
81 int i_state; /* data-gathering state for this subtitle */
83 block_t *p_spu; /* Bytes of the packet. */
85 uint16_t i_image; /* image number in the subtitle stream */
86 uint8_t i_packet; /* packet number for above image number */
88 int i_spu_size; /* goal for subtitle_data_pos while gathering,
89 size of used subtitle_data later */
91 uint16_t i_image_offset; /* offset from subtitle_data to compressed
93 int i_image_length; /* size of the compressed image data */
94 int second_field_offset; /* offset of odd raster lines */
95 int metadata_offset; /* offset to data describing the image */
96 int metadata_length; /* length of metadata */
98 mtime_t i_duration; /* how long to display the image, 0 stands
99 for "until next subtitle" */
101 uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
102 image when displayed */
103 uint16_t i_width, i_height; /* dimensions in pixels of image */
105 uint8_t p_palette[4][4]; /* Palette of colors used in subtitle */
108 /*****************************************************************************
109 * DecoderOpen: open/initialize the svcdsub decoder.
110 *****************************************************************************/
111 static int DecoderOpen( vlc_object_t *p_this )
113 decoder_t *p_dec = (decoder_t*)p_this;
114 decoder_sys_t *p_sys;
116 if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'o','g','t',' ' ) )
121 p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
123 p_sys->b_packetizer = VLC_FALSE;
126 p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
129 es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'o','g','t',' ' ) );
131 p_dec->pf_decode_sub = Decode;
132 p_dec->pf_packetize = Packetize;
137 /*****************************************************************************
138 * PacketizerOpen: open/initialize the svcdsub packetizer.
139 *****************************************************************************/
140 static int PacketizerOpen( vlc_object_t *p_this )
142 decoder_t *p_dec = (decoder_t*)p_this;
144 if( DecoderOpen( p_this ) != VLC_SUCCESS ) return VLC_EGENERIC;
146 p_dec->p_sys->b_packetizer = VLC_TRUE;
151 /*****************************************************************************
152 * DecoderClose: closes the svcdsub decoder/packetizer.
153 *****************************************************************************/
154 void DecoderClose( vlc_object_t *p_this )
156 decoder_t *p_dec = (decoder_t*)p_this;
157 decoder_sys_t *p_sys = p_dec->p_sys;
159 if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu );
163 /*****************************************************************************
165 *****************************************************************************/
166 static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
168 block_t *p_block, *p_spu;
170 if( pp_block == NULL || *pp_block == NULL ) return NULL;
175 if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
177 /* Parse and decode */
178 return DecodePacket( p_dec, p_spu );
181 /*****************************************************************************
183 *****************************************************************************/
184 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
186 block_t *p_block, *p_spu;
188 if( pp_block == NULL || *pp_block == NULL ) return NULL;
193 if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
195 p_spu->i_dts = p_spu->i_pts;
201 /*****************************************************************************
204 The data for single screen subtitle may come in one of many
205 non-contiguous packets of a stream. This routine is called when the
206 next packet in the stream comes in. The job of this routine is to
207 parse the header, if this is the beginning, and combine the packets
208 into one complete subtitle unit.
210 If everything is complete, we will return a block. Otherwise return
214 The format of the beginning of the subtitle packet that is used here.
217 -------------------------------------------
218 byte subtitle channel (0..7) in bits 0-3
219 byte subtitle packet number of this subtitle image 0-N,
220 if the subtitle packet is complete, the top bit of the byte is 1.
221 uint16 subtitle image number
223 *****************************************************************************/
224 #define SPU_HEADER_LEN 5
226 static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
228 decoder_sys_t *p_sys = p_dec->p_sys;
230 uint16_t i_expected_image;
231 uint8_t i_packet, i_expected_packet;
233 if( p_block->i_buffer < SPU_HEADER_LEN )
235 msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
236 p_block->i_buffer, SPU_HEADER_LEN );
237 block_Release( p_block );
241 p_buffer = p_block->p_buffer;
243 /* Attach to our input thread and see if subtitle is selected. */
245 vlc_object_t * p_input;
248 p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_PARENT );
250 if( !p_input ) return NULL;
252 if( var_Get( p_input, "spu-channel", &val ) )
254 vlc_object_release( p_input );
258 vlc_object_release( p_input );
259 msg_Dbg( p_dec, "val.i_int %x p_buffer[i] %x", val.i_int, p_buffer[1]);
261 /* The dummy ES that the menu selection uses has an 0x70 at
262 the head which we need to strip off. */
263 if( val.i_int == -1 || (val.i_int & 0x03) != p_buffer[1] )
265 msg_Dbg( p_dec, "subtitle not for us." );
270 if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY )
272 i_expected_image = p_sys->i_image + 1;
273 i_expected_packet = 0;
277 i_expected_image = p_sys->i_image;
278 i_expected_packet = p_sys->i_packet + 1;
283 if( *p_buffer & 0x80 )
285 p_sys->i_state = SUBTITLE_BLOCK_COMPLETE;
286 i_packet = *p_buffer++ & 0x7F;
290 p_sys->i_state = SUBTITLE_BLOCK_PARTIAL;
291 i_packet = *p_buffer++;
294 p_sys->i_image = GETINT16(p_buffer);
296 if( p_sys->i_image != i_expected_image )
298 msg_Warn( p_dec, "expected subtitle image %u but found %u",
299 i_expected_image, p_sys->i_image );
302 if( i_packet != i_expected_packet )
304 msg_Warn( p_dec, "expected subtitle image packet %u but found %u",
305 i_expected_packet, i_packet );
308 p_block->p_buffer += SPU_HEADER_LEN;
309 p_block->i_buffer -= SPU_HEADER_LEN;
311 p_sys->i_packet = i_packet;
312 /* First packet in the subtitle block */
313 if( !p_sys->i_packet ) ParseHeader( p_dec, p_block );
315 block_ChainAppend( &p_sys->p_spu, p_block );
317 if( p_sys->i_state == SUBTITLE_BLOCK_COMPLETE )
319 block_t *p_spu = block_ChainGather( p_sys->p_spu );
321 if( p_spu->i_buffer != p_sys->i_spu_size )
323 msg_Warn( p_dec, "SPU packets size=%d should be %d",
324 p_spu->i_buffer, p_sys->i_spu_size );
327 msg_Dbg( p_dec, "subtitle packet complete, size=%d", p_spu->i_buffer);
329 p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
337 /******************************************************************************
338 The format is roughly as follows (everything is big-endian):
341 -------------------------------------------
342 byte subtitle channel (0..7) in bits 0-3
343 byte subtitle packet number of this subtitle image 0-N,
344 if the subtitle packet is complete, the top bit of the byte is 1.
345 u_int16 subtitle image number
346 u_int16 length in bytes of the rest
347 byte option flags, unknown meaning except bit 3 (0x08) indicates
348 presence of the duration field
350 u_int32 duration in 1/90000ths of a second (optional), start time
351 is as indicated by the PTS in the PES header
354 u_int32 width (must be even)
355 u_int32 height (must be even)
356 byte[16] palette, 4 palette entries, each contains values for
357 Y, U, V and transparency, 0 standing for transparent
359 cmd>>6==1 indicates shift
360 (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
361 u_int32 shift duration in 1/90000ths of a second
362 u_int16 offset of odd-numbered scanlines - subtitle images are
363 given in interlace order
364 byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with
365 2-bits per palette number
366 ******************************************************************************/
367 static void ParseHeader( decoder_t *p_dec, block_t *p_block )
369 decoder_sys_t *p_sys = p_dec->p_sys;
370 uint8_t *p = p_block->p_buffer;
371 uint8_t i_options, i_options2, i_cmd, i_cmd_arg;
374 p_sys->i_spu_size = GETINT16(p);
378 if( i_options & 0x08 ) { p_sys->i_duration = GETINT32(p); }
379 else p_sys->i_duration = 0; /* Ephemer subtitle */
380 p_sys->i_duration *= 100 / 9;
382 p_sys->i_x_start = GETINT16(p);
383 p_sys->i_y_start = GETINT16(p);
384 p_sys->i_width = GETINT16(p);
385 p_sys->i_height = GETINT16(p);
387 for( i = 0; i < 4; i++ )
389 p_sys->p_palette[i][0] = *p++; /* Y */
390 p_sys->p_palette[i][2] = *p++; /* Cr / V */
391 p_sys->p_palette[i][1] = *p++; /* Cb / U */
392 p_sys->p_palette[i][3] = *p++; /* T */
396 /* We do not really know this, FIXME */
397 if( i_cmd ) {i_cmd_arg = GETINT32(p);}
399 /* Actually, this is measured against a different origin, so we have to
401 p_sys->second_field_offset = GETINT16(p);
402 p_sys->i_image_offset = p - p_block->p_buffer;
403 p_sys->i_image_length = p_sys->i_spu_size - p_sys->i_image_offset;
404 p_sys->metadata_length = p_sys->i_image_offset;
407 msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
408 "spu size: %d, duration: %lu (d:%d p:%d)",
409 p_sys->i_x_start, p_sys->i_y_start,
410 p_sys->i_width, p_sys->i_height,
411 p_sys->i_spu_size, (long unsigned int) p_sys->i_duration,
412 p_sys->i_image_length, p_sys->i_image_offset);
414 for( i = 0; i < 4; i++ )
416 msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
417 p_sys->p_palette[i][3], p_sys->p_palette[i][0],
418 p_sys->p_palette[i][1], p_sys->p_palette[i][2] );
423 /*****************************************************************************
424 * DecodePacket: parse and decode an SPU packet
425 *****************************************************************************
426 * This function parses and decodes an SPU packet and, if valid, returns a
428 *****************************************************************************/
429 static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data )
431 decoder_sys_t *p_sys = p_dec->p_sys;
433 subpicture_region_t *p_region;
437 /* Allocate the subpicture internal data. */
438 p_spu = p_dec->pf_spu_buffer_new( p_dec );
439 if( !p_spu ) return NULL;
441 p_spu->i_x = p_sys->i_x_start;
442 p_spu->i_x = p_spu->i_x * 3 / 4; /* FIXME: use aspect ratio for x? */
443 p_spu->i_y = p_sys->i_y_start;
444 p_spu->i_start = p_data->i_pts;
445 p_spu->i_stop = p_data->i_pts + p_sys->i_duration;
446 p_spu->b_ephemer = VLC_TRUE;
448 /* Create new SPU region */
449 memset( &fmt, 0, sizeof(video_format_t) );
450 fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
451 fmt.i_aspect = VOUT_ASPECT_FACTOR;
452 fmt.i_width = fmt.i_visible_width = p_sys->i_width;
453 fmt.i_height = fmt.i_visible_height = p_sys->i_height;
454 fmt.i_x_offset = fmt.i_y_offset = 0;
455 p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
458 msg_Err( p_dec, "cannot allocate SPU region" );
462 p_spu->p_region = p_region;
463 p_region->i_x = p_region->i_y = 0;
466 fmt.p_palette->i_entries = 4;
467 for( i = 0; i < fmt.p_palette->i_entries; i++ )
469 fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0];
470 fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1];
471 fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2];
472 fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3];
475 RenderImage( p_dec, p_data, p_region );
480 /*****************************************************************************
481 * ParseImage: parse the image part of the subtitle
482 *****************************************************************************
483 This part parses the subtitle graphical data and renders it.
485 The image is encoded using two bits per pixel that select a palette
486 entry except that value 0 starts a limited run-length encoding for
487 color 0. When 0 is seen, the next two bits encode one less than the
488 number of pixels, so we can encode run lengths from 1 to 4. These get
489 filled with the color in palette entry 0.
491 The encoding of each line is padded to a whole number of bytes. The
492 first field is padded to an even byte length and the complete subtitle
493 is padded to a 4-byte multiple that always include one zero byte at
496 However we'll transform this so that that the RLE is expanded and
497 interlacing will also be removed.
498 *****************************************************************************/
499 static void RenderImage( decoder_t *p_dec, block_t *p_data,
500 subpicture_region_t *p_region )
502 decoder_sys_t *p_sys = p_dec->p_sys;
503 uint8_t *p_dest = p_region->picture.Y_PIXELS;
504 int i_field; /* The subtitles are interlaced */
505 int i_row, i_column; /* scanline row/column number */
506 uint8_t i_color, i_count;
509 bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset,
510 p_data->i_buffer - p_sys->i_image_offset );
512 for( i_field = 0; i_field < 2; i_field++ )
514 for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 )
516 for( i_column = 0; i_column < p_sys->i_width; i_column++ )
518 i_color = bs_read( &bs, 2 );
519 if( i_color == 0 && (i_count = bs_read( &bs, 2 )) )
521 i_count = __MIN( i_count, p_sys->i_width - i_column );
522 memset( &p_dest[i_row * p_region->picture.Y_PITCH +
523 i_column], 0, i_count + 1 );
528 p_dest[i_row * p_region->picture.Y_PITCH + i_column] = i_color;
535 bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset +
536 p_sys->second_field_offset,
537 p_data->i_buffer - p_sys->i_image_offset -
538 p_sys->second_field_offset );