1 /*****************************************************************************
2 * svcdsub.c : Overlay Graphics Text (SVCD subtitles) decoder
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_codec.h>
39 /*****************************************************************************
41 *****************************************************************************/
42 static int DecoderOpen ( vlc_object_t * );
43 static int PacketizerOpen( vlc_object_t * );
44 static void DecoderClose ( vlc_object_t * );
47 set_description( N_("Philips OGT (SVCD subtitle) decoder") )
48 set_shortname( N_("SVCD subtitles") )
49 set_category( CAT_INPUT )
50 set_subcategory( SUBCAT_INPUT_SCODEC )
51 set_capability( "decoder", 50 )
52 set_callbacks( DecoderOpen, DecoderClose )
54 add_obsolete_integer ( MODULE_STRING "-debug" )
57 set_description( N_("Philips OGT (SVCD subtitle) packetizer") )
58 set_capability( "packetizer", 50 )
59 set_callbacks( PacketizerOpen, DecoderClose )
62 /*****************************************************************************
64 *****************************************************************************/
65 static subpicture_t *Decode( decoder_t *, block_t ** );
66 static block_t *Packetize ( decoder_t *, block_t ** );
67 static block_t *Reassemble ( decoder_t *, block_t * );
68 static void ParseHeader( decoder_t *, block_t * );
69 static subpicture_t *DecodePacket( decoder_t *, block_t * );
70 static void SVCDSubRenderImage( decoder_t *, block_t *, subpicture_region_t * );
72 #define GETINT16(p) ( (p[0] << 8) + p[1] ) ; p +=2;
74 #define GETINT32(p) ( (p[0] << 24) + (p[1] << 16) + \
75 (p[2] << 8) + (p[3]) ) ; p += 4;
78 SUBTITLE_BLOCK_EMPTY = 0,
79 SUBTITLE_BLOCK_PARTIAL = 1,
80 SUBTITLE_BLOCK_COMPLETE = 2
84 # define dbg_print( s, args...) \
85 msg_Dbg(p_dec, "%s: "s, __func__ , ##args)
87 # define dbg_print( s, args...)
92 packet_state_t i_state; /* data-gathering state for this subtitle */
94 block_t *p_spu; /* Bytes of the packet. */
96 uint16_t i_image; /* image number in the subtitle stream */
97 uint8_t i_packet; /* packet number for above image number */
99 size_t i_spu_size; /* goal for subtitle_data_pos while gathering,
100 size of used subtitle_data later */
102 uint16_t i_image_offset; /* offset from subtitle_data to compressed
104 size_t i_image_length; /* size of the compressed image data */
105 size_t second_field_offset; /* offset of odd raster lines */
106 size_t metadata_offset; /* offset to data describing the image */
107 size_t metadata_length; /* length of metadata */
109 mtime_t i_duration; /* how long to display the image, 0 stands
110 for "until next subtitle" */
112 uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
113 image when displayed */
114 uint16_t i_width, i_height; /* dimensions in pixels of image */
116 uint8_t p_palette[4][4]; /* Palette of colors used in subtitle */
119 /*****************************************************************************
120 * DecoderOpen: open/initialize the svcdsub decoder.
121 *****************************************************************************/
122 static int DecoderOpen( vlc_object_t *p_this )
124 decoder_t *p_dec = (decoder_t*)p_this;
125 decoder_sys_t *p_sys;
127 if( p_dec->fmt_in.i_codec != VLC_CODEC_OGT )
130 p_dec->p_sys = p_sys = calloc( 1, sizeof( decoder_sys_t ) );
137 p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
140 es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_CODEC_OGT );
142 p_dec->pf_decode_sub = Decode;
143 p_dec->pf_packetize = Packetize;
148 /*****************************************************************************
149 * PacketizerOpen: open/initialize the svcdsub packetizer.
150 *****************************************************************************/
151 static int PacketizerOpen( vlc_object_t *p_this )
153 if( DecoderOpen( p_this ) != VLC_SUCCESS ) return VLC_EGENERIC;
158 /*****************************************************************************
159 * DecoderClose: closes the svcdsub decoder/packetizer.
160 *****************************************************************************/
161 void DecoderClose( vlc_object_t *p_this )
163 decoder_t *p_dec = (decoder_t*)p_this;
164 decoder_sys_t *p_sys = p_dec->p_sys;
166 if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu );
170 /*****************************************************************************
172 *****************************************************************************/
173 static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
175 block_t *p_block, *p_spu;
179 if( pp_block == NULL || *pp_block == NULL ) return NULL;
184 if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
186 /* Parse and decode */
187 return DecodePacket( p_dec, p_spu );
190 /*****************************************************************************
192 *****************************************************************************/
193 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
195 block_t *p_block, *p_spu;
197 if( pp_block == NULL || *pp_block == NULL ) return NULL;
202 if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
204 p_spu->i_dts = p_spu->i_pts;
210 /*****************************************************************************
213 The data for single screen subtitle may come in one of many
214 non-contiguous packets of a stream. This routine is called when the
215 next packet in the stream comes in. The job of this routine is to
216 parse the header, if this is the beginning, and combine the packets
217 into one complete subtitle unit.
219 If everything is complete, we will return a block. Otherwise return
223 The format of the beginning of the subtitle packet that is used here.
226 -------------------------------------------
227 byte subtitle channel (0..7) in bits 0-3
228 byte subtitle packet number of this subtitle image 0-N,
229 if the subtitle packet is complete, the top bit of the byte is 1.
230 uint16 subtitle image number
232 *****************************************************************************/
233 #define SPU_HEADER_LEN 5
235 static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
237 decoder_sys_t *p_sys = p_dec->p_sys;
239 uint16_t i_expected_image;
240 uint8_t i_packet, i_expected_packet;
242 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
244 block_Release( p_block );
248 if( p_block->i_buffer < SPU_HEADER_LEN )
250 msg_Dbg( p_dec, "invalid packet header (size %zu < %u)" ,
251 p_block->i_buffer, SPU_HEADER_LEN );
252 block_Release( p_block );
256 p_buffer = p_block->p_buffer;
258 if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY )
260 i_expected_image = p_sys->i_image + 1;
261 i_expected_packet = 0;
265 i_expected_image = p_sys->i_image;
266 i_expected_packet = p_sys->i_packet + 1;
269 /* The dummy ES that the menu selection uses has an 0x70 at
270 the head which we need to strip off. */
273 if( *p_buffer & 0x80 )
275 p_sys->i_state = SUBTITLE_BLOCK_COMPLETE;
276 i_packet = *p_buffer++ & 0x7F;
280 p_sys->i_state = SUBTITLE_BLOCK_PARTIAL;
281 i_packet = *p_buffer++;
284 p_sys->i_image = GETINT16(p_buffer);
286 if( p_sys->i_image != i_expected_image )
288 msg_Warn( p_dec, "expected subtitle image %u but found %u",
289 i_expected_image, p_sys->i_image );
292 if( i_packet != i_expected_packet )
294 msg_Warn( p_dec, "expected subtitle image packet %u but found %u",
295 i_expected_packet, i_packet );
298 p_block->p_buffer += SPU_HEADER_LEN;
299 p_block->i_buffer -= SPU_HEADER_LEN;
301 p_sys->i_packet = i_packet;
302 /* First packet in the subtitle block */
303 if( !p_sys->i_packet ) ParseHeader( p_dec, p_block );
305 block_ChainAppend( &p_sys->p_spu, p_block );
307 if( p_sys->i_state == SUBTITLE_BLOCK_COMPLETE )
309 block_t *p_spu = block_ChainGather( p_sys->p_spu );
311 if( p_spu->i_buffer != p_sys->i_spu_size )
313 msg_Warn( p_dec, "subtitle packets size=%zu should be %zu",
314 p_spu->i_buffer, p_sys->i_spu_size );
317 dbg_print( "subtitle packet complete, size=%zu", p_spu->i_buffer );
319 p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
327 /******************************************************************************
328 The format is roughly as follows (everything is big-endian):
331 -------------------------------------------
332 byte subtitle channel (0..7) in bits 0-3
333 byte subtitle packet number of this subtitle image 0-N,
334 if the subtitle packet is complete, the top bit of the byte is 1.
335 u_int16 subtitle image number
336 u_int16 length in bytes of the rest
337 byte option flags, unknown meaning except bit 3 (0x08) indicates
338 presence of the duration field
340 u_int32 duration in 1/90000ths of a second (optional), start time
341 is as indicated by the PTS in the PES header
344 u_int32 width (must be even)
345 u_int32 height (must be even)
346 byte[16] palette, 4 palette entries, each contains values for
347 Y, U, V and transparency, 0 standing for transparent
349 cmd>>6==1 indicates shift
350 (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
351 u_int32 shift duration in 1/90000ths of a second
352 u_int16 offset of odd-numbered scanlines - subtitle images are
353 given in interlace order
354 byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with
355 2-bits per palette number
356 ******************************************************************************/
357 static void ParseHeader( decoder_t *p_dec, block_t *p_block )
359 decoder_sys_t *p_sys = p_dec->p_sys;
360 uint8_t *p = p_block->p_buffer;
361 uint8_t i_options, i_options2, i_cmd, i_cmd_arg;
364 p_sys->i_spu_size = GETINT16(p);
368 if( i_options & 0x08 ) { p_sys->i_duration = GETINT32(p); }
369 else p_sys->i_duration = 0; /* Ephemer subtitle */
370 p_sys->i_duration *= 100 / 9;
372 p_sys->i_x_start = GETINT16(p);
373 p_sys->i_y_start = GETINT16(p);
374 p_sys->i_width = GETINT16(p);
375 p_sys->i_height = GETINT16(p);
377 for( i = 0; i < 4; i++ )
379 p_sys->p_palette[i][0] = *p++; /* Y */
380 p_sys->p_palette[i][2] = *p++; /* Cr / V */
381 p_sys->p_palette[i][1] = *p++; /* Cb / U */
382 p_sys->p_palette[i][3] = *p++; /* T */
386 /* We do not really know this, FIXME */
387 if( i_cmd ) {i_cmd_arg = GETINT32(p);}
389 /* Actually, this is measured against a different origin, so we have to
391 p_sys->second_field_offset = GETINT16(p);
392 p_sys->i_image_offset = p - p_block->p_buffer;
393 p_sys->i_image_length = p_sys->i_spu_size - p_sys->i_image_offset;
394 p_sys->metadata_length = p_sys->i_image_offset;
398 msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
399 "spu size: %zu, duration: %"PRIu64" (d:%zu p:%"PRIu16")",
400 p_sys->i_x_start, p_sys->i_y_start,
401 p_sys->i_width, p_sys->i_height,
402 p_sys->i_spu_size, p_sys->i_duration,
403 p_sys->i_image_length, p_sys->i_image_offset);
405 for( i = 0; i < 4; i++ )
407 msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
408 p_sys->p_palette[i][3], p_sys->p_palette[i][0],
409 p_sys->p_palette[i][1], p_sys->p_palette[i][2] );
415 /*****************************************************************************
416 * DecodePacket: parse and decode an subtitle packet
417 *****************************************************************************
418 * This function parses and decodes an SPU packet and, if valid, returns a
420 *****************************************************************************/
421 static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data )
423 decoder_sys_t *p_sys = p_dec->p_sys;
425 subpicture_region_t *p_region;
427 video_palette_t palette;
430 /* Allocate the subpicture internal data. */
431 p_spu = decoder_NewSubpicture( p_dec, NULL );
432 if( !p_spu ) return NULL;
434 p_spu->i_start = p_data->i_pts;
435 p_spu->i_stop = p_data->i_pts + p_sys->i_duration;
436 p_spu->b_ephemer = true;
438 /* Create new subtitle region */
439 memset( &fmt, 0, sizeof(video_format_t) );
440 fmt.i_chroma = VLC_CODEC_YUVP;
443 The video on which the subtitle sits, is scaled, probably
444 4:3. However subtitle bitmaps assume an 1:1 aspect ratio.
446 FIXME: We should get the video aspect ratio from somewhere.
447 Two candidates are the video and the other possibility would be
450 fmt.i_sar_num = p_sys->i_height;
451 fmt.i_sar_den = p_sys->i_width;
453 fmt.i_width = fmt.i_visible_width = p_sys->i_width;
454 fmt.i_height = fmt.i_visible_height = p_sys->i_height;
455 fmt.i_x_offset = fmt.i_y_offset = 0;
456 fmt.p_palette = &palette;
457 fmt.p_palette->i_entries = 4;
458 for( i = 0; i < fmt.p_palette->i_entries; i++ )
460 fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0];
461 fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1];
462 fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2];
463 fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3];
466 p_region = subpicture_region_New( &fmt );
469 msg_Err( p_dec, "cannot allocate SVCD subtitle region" );
470 decoder_DeleteSubpicture( p_dec, p_spu );
474 p_spu->p_region = p_region;
475 p_region->i_x = p_sys->i_x_start;
476 p_region->i_y = p_sys->i_y_start;
478 SVCDSubRenderImage( p_dec, p_data, p_region );
483 /*****************************************************************************
484 * SVCDSubRenderImage: reorders bytes of image data in subpicture region.
485 *****************************************************************************
487 The image is encoded using two bits per pixel that select a palette
488 entry except that value 0 starts a limited run-length encoding for
489 color 0. When 0 is seen, the next two bits encode one less than the
490 number of pixels, so we can encode run lengths from 1 to 4. These get
491 filled with the color in palette entry 0.
493 The encoding of each line is padded to a whole number of bytes. The
494 first field is padded to an even byte length and the complete subtitle
495 is padded to a 4-byte multiple that always include one zero byte at
498 However we'll transform this so that that the RLE is expanded and
499 interlacing will also be removed.
500 *****************************************************************************/
501 static void SVCDSubRenderImage( decoder_t *p_dec, block_t *p_data,
502 subpicture_region_t *p_region )
504 decoder_sys_t *p_sys = p_dec->p_sys;
505 uint8_t *p_dest = p_region->p_picture->Y_PIXELS;
506 int i_field; /* The subtitles are interlaced */
507 int i_row, i_column; /* scanline row/column number */
508 uint8_t i_color, i_count;
511 bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset,
512 p_data->i_buffer - p_sys->i_image_offset );
514 for( i_field = 0; i_field < 2; i_field++ )
516 for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 )
518 for( i_column = 0; i_column < p_sys->i_width; i_column++ )
520 i_color = bs_read( &bs, 2 );
521 if( i_color == 0 && (i_count = bs_read( &bs, 2 )) )
523 i_count = __MIN( i_count, p_sys->i_width - i_column );
524 memset( &p_dest[i_row * p_region->p_picture->Y_PITCH +
525 i_column], 0, i_count + 1 );
530 p_dest[i_row * p_region->p_picture->Y_PITCH + i_column] = i_color;
537 bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset +
538 p_sys->second_field_offset,
539 p_data->i_buffer - p_sys->i_image_offset -
540 p_sys->second_field_offset );