add_savefile: remove callback parameter
[vlc/asuraparaju-public.git] / modules / codec / svcdsub.c
blobc47452e33a2a3aac327d19f90efd513bab713b7e
1 /*****************************************************************************
2 * svcdsub.c : Overlay Graphics Text (SVCD subtitles) decoder
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 the VideoLAN team
5 * $Id$
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 /*****************************************************************************
28 * Preamble
29 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_codec.h>
37 #include <vlc_bits.h>
39 /*****************************************************************************
40 * Module descriptor.
41 *****************************************************************************/
42 static int DecoderOpen ( vlc_object_t * );
43 static int PacketizerOpen( vlc_object_t * );
44 static void DecoderClose ( vlc_object_t * );
46 #define DEBUG_TEXT N_("Enable debug")
48 #define DEBUG_LONGTEXT \
49 N_("This integer when viewed in binary is a debugging mask\n" \
50 "calls 1\n" \
51 "packet assembly info 2\n" )
53 vlc_module_begin ()
54 set_description( N_("Philips OGT (SVCD subtitle) decoder") )
55 set_shortname( N_("SVCD subtitles") )
56 set_category( CAT_INPUT )
57 set_subcategory( SUBCAT_INPUT_SCODEC )
58 set_capability( "decoder", 50 )
59 set_callbacks( DecoderOpen, DecoderClose )
61 add_integer ( MODULE_STRING "-debug", 0, NULL,
62 DEBUG_TEXT, DEBUG_LONGTEXT, true )
64 add_submodule ()
65 set_description( N_("Philips OGT (SVCD subtitle) packetizer") )
66 set_capability( "packetizer", 50 )
67 set_callbacks( PacketizerOpen, DecoderClose )
68 vlc_module_end ()
70 /*****************************************************************************
71 * Local prototypes
72 *****************************************************************************/
73 static subpicture_t *Decode( decoder_t *, block_t ** );
74 static block_t *Packetize ( decoder_t *, block_t ** );
75 static block_t *Reassemble ( decoder_t *, block_t * );
76 static void ParseHeader( decoder_t *, block_t * );
77 static subpicture_t *DecodePacket( decoder_t *, block_t * );
78 static void SVCDSubRenderImage( decoder_t *, block_t *, subpicture_region_t * );
80 #define DECODE_DBG_CALL 1 /* calls */
81 #define DECODE_DBG_PACKET 2 /* packet assembly info */
83 #define GETINT16(p) ( (p[0] << 8) + p[1] ) ; p +=2;
85 #define GETINT32(p) ( (p[0] << 24) + (p[1] << 16) + \
86 (p[2] << 8) + (p[3]) ) ; p += 4;
88 typedef enum {
89 SUBTITLE_BLOCK_EMPTY = 0,
90 SUBTITLE_BLOCK_PARTIAL = 1,
91 SUBTITLE_BLOCK_COMPLETE = 2
92 } packet_state_t;
94 #ifndef DECODE_DEBUG
95 #define DECODE_DEBUG 1
96 #endif
97 #if DECODE_DEBUG
98 #define dbg_print(mask, s, args...) \
99 if (p_sys && p_sys->i_debug & mask) \
100 msg_Dbg(p_dec, "%s: "s, __func__ , ##args)
101 #else
102 #define dbg_print(mask, s, args...)
103 #endif
105 struct decoder_sys_t
107 int i_debug; /* debugging mask */
109 packet_state_t i_state; /* data-gathering state for this subtitle */
111 block_t *p_spu; /* Bytes of the packet. */
113 uint16_t i_image; /* image number in the subtitle stream */
114 uint8_t i_packet; /* packet number for above image number */
116 size_t i_spu_size; /* goal for subtitle_data_pos while gathering,
117 size of used subtitle_data later */
119 uint16_t i_image_offset; /* offset from subtitle_data to compressed
120 image data */
121 size_t i_image_length; /* size of the compressed image data */
122 size_t second_field_offset; /* offset of odd raster lines */
123 size_t metadata_offset; /* offset to data describing the image */
124 size_t metadata_length; /* length of metadata */
126 mtime_t i_duration; /* how long to display the image, 0 stands
127 for "until next subtitle" */
129 uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
130 image when displayed */
131 uint16_t i_width, i_height; /* dimensions in pixels of image */
133 uint8_t p_palette[4][4]; /* Palette of colors used in subtitle */
136 /*****************************************************************************
137 * DecoderOpen: open/initialize the svcdsub decoder.
138 *****************************************************************************/
139 static int DecoderOpen( vlc_object_t *p_this )
141 decoder_t *p_dec = (decoder_t*)p_this;
142 decoder_sys_t *p_sys;
144 if( p_dec->fmt_in.i_codec != VLC_CODEC_OGT )
145 return VLC_EGENERIC;
147 p_dec->p_sys = p_sys = calloc( 1, sizeof( decoder_sys_t ) );
148 if( p_sys == NULL )
149 return VLC_ENOMEM;
151 p_sys->i_debug = var_InheritInteger( p_this, MODULE_STRING "-debug" );
153 p_sys->i_image = -1;
155 p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
156 p_sys->p_spu = NULL;
158 es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_CODEC_OGT );
160 p_dec->pf_decode_sub = Decode;
161 p_dec->pf_packetize = Packetize;
163 dbg_print( (DECODE_DBG_CALL) , "");
164 return VLC_SUCCESS;
167 /*****************************************************************************
168 * PacketizerOpen: open/initialize the svcdsub packetizer.
169 *****************************************************************************/
170 static int PacketizerOpen( vlc_object_t *p_this )
172 if( DecoderOpen( p_this ) != VLC_SUCCESS ) return VLC_EGENERIC;
174 return VLC_SUCCESS;
177 /*****************************************************************************
178 * DecoderClose: closes the svcdsub decoder/packetizer.
179 *****************************************************************************/
180 void DecoderClose( vlc_object_t *p_this )
182 decoder_t *p_dec = (decoder_t*)p_this;
183 decoder_sys_t *p_sys = p_dec->p_sys;
185 if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu );
186 free( p_sys );
189 /*****************************************************************************
190 * Decode:
191 *****************************************************************************/
192 static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
194 block_t *p_block, *p_spu;
195 decoder_sys_t *p_sys = p_dec->p_sys;
197 dbg_print( (DECODE_DBG_CALL) , "");
199 if( pp_block == NULL || *pp_block == NULL ) return NULL;
201 p_block = *pp_block;
202 *pp_block = NULL;
204 if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
206 /* Parse and decode */
207 return DecodePacket( p_dec, p_spu );
210 /*****************************************************************************
211 * Packetize:
212 *****************************************************************************/
213 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
215 block_t *p_block, *p_spu;
217 if( pp_block == NULL || *pp_block == NULL ) return NULL;
219 p_block = *pp_block;
220 *pp_block = NULL;
222 if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
224 p_spu->i_dts = p_spu->i_pts;
225 p_spu->i_length = 0;
227 return p_spu;
230 /*****************************************************************************
231 Reassemble:
233 The data for single screen subtitle may come in one of many
234 non-contiguous packets of a stream. This routine is called when the
235 next packet in the stream comes in. The job of this routine is to
236 parse the header, if this is the beginning, and combine the packets
237 into one complete subtitle unit.
239 If everything is complete, we will return a block. Otherwise return
240 NULL.
243 The format of the beginning of the subtitle packet that is used here.
245 size description
246 -------------------------------------------
247 byte subtitle channel (0..7) in bits 0-3
248 byte subtitle packet number of this subtitle image 0-N,
249 if the subtitle packet is complete, the top bit of the byte is 1.
250 uint16 subtitle image number
252 *****************************************************************************/
253 #define SPU_HEADER_LEN 5
255 static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
257 decoder_sys_t *p_sys = p_dec->p_sys;
258 uint8_t *p_buffer;
259 uint16_t i_expected_image;
260 uint8_t i_packet, i_expected_packet;
262 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
264 block_Release( p_block );
265 return NULL;
268 if( p_block->i_buffer < SPU_HEADER_LEN )
270 msg_Dbg( p_dec, "invalid packet header (size %zu < %u)" ,
271 p_block->i_buffer, SPU_HEADER_LEN );
272 block_Release( p_block );
273 return NULL;
276 p_buffer = p_block->p_buffer;
278 if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY )
280 i_expected_image = p_sys->i_image + 1;
281 i_expected_packet = 0;
283 else
285 i_expected_image = p_sys->i_image;
286 i_expected_packet = p_sys->i_packet + 1;
289 /* The dummy ES that the menu selection uses has an 0x70 at
290 the head which we need to strip off. */
291 p_buffer += 2;
293 if( *p_buffer & 0x80 )
295 p_sys->i_state = SUBTITLE_BLOCK_COMPLETE;
296 i_packet = *p_buffer++ & 0x7F;
298 else
300 p_sys->i_state = SUBTITLE_BLOCK_PARTIAL;
301 i_packet = *p_buffer++;
304 p_sys->i_image = GETINT16(p_buffer);
306 if( p_sys->i_image != i_expected_image )
308 msg_Warn( p_dec, "expected subtitle image %u but found %u",
309 i_expected_image, p_sys->i_image );
312 if( i_packet != i_expected_packet )
314 msg_Warn( p_dec, "expected subtitle image packet %u but found %u",
315 i_expected_packet, i_packet );
318 p_block->p_buffer += SPU_HEADER_LEN;
319 p_block->i_buffer -= SPU_HEADER_LEN;
321 p_sys->i_packet = i_packet;
322 /* First packet in the subtitle block */
323 if( !p_sys->i_packet ) ParseHeader( p_dec, p_block );
325 block_ChainAppend( &p_sys->p_spu, p_block );
327 if( p_sys->i_state == SUBTITLE_BLOCK_COMPLETE )
329 block_t *p_spu = block_ChainGather( p_sys->p_spu );
331 if( p_spu->i_buffer != p_sys->i_spu_size )
333 msg_Warn( p_dec, "subtitle packets size=%zu should be %zu",
334 p_spu->i_buffer, p_sys->i_spu_size );
337 dbg_print( (DECODE_DBG_PACKET),
338 "subtitle packet complete, size=%zu", p_spu->i_buffer );
340 p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
341 p_sys->p_spu = 0;
342 return p_spu;
345 return NULL;
348 /******************************************************************************
349 The format is roughly as follows (everything is big-endian):
351 size description
352 -------------------------------------------
353 byte subtitle channel (0..7) in bits 0-3
354 byte subtitle packet number of this subtitle image 0-N,
355 if the subtitle packet is complete, the top bit of the byte is 1.
356 u_int16 subtitle image number
357 u_int16 length in bytes of the rest
358 byte option flags, unknown meaning except bit 3 (0x08) indicates
359 presence of the duration field
360 byte unknown
361 u_int32 duration in 1/90000ths of a second (optional), start time
362 is as indicated by the PTS in the PES header
363 u_int32 xpos
364 u_int32 ypos
365 u_int32 width (must be even)
366 u_int32 height (must be even)
367 byte[16] palette, 4 palette entries, each contains values for
368 Y, U, V and transparency, 0 standing for transparent
369 byte command,
370 cmd>>6==1 indicates shift
371 (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
372 u_int32 shift duration in 1/90000ths of a second
373 u_int16 offset of odd-numbered scanlines - subtitle images are
374 given in interlace order
375 byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with
376 2-bits per palette number
377 ******************************************************************************/
378 static void ParseHeader( decoder_t *p_dec, block_t *p_block )
380 decoder_sys_t *p_sys = p_dec->p_sys;
381 uint8_t *p = p_block->p_buffer;
382 uint8_t i_options, i_options2, i_cmd, i_cmd_arg;
383 int i;
385 p_sys->i_spu_size = GETINT16(p);
386 i_options = *p++;
387 i_options2 = *p++;
389 if( i_options & 0x08 ) { p_sys->i_duration = GETINT32(p); }
390 else p_sys->i_duration = 0; /* Ephemer subtitle */
391 p_sys->i_duration *= 100 / 9;
393 p_sys->i_x_start = GETINT16(p);
394 p_sys->i_y_start = GETINT16(p);
395 p_sys->i_width = GETINT16(p);
396 p_sys->i_height = GETINT16(p);
398 for( i = 0; i < 4; i++ )
400 p_sys->p_palette[i][0] = *p++; /* Y */
401 p_sys->p_palette[i][2] = *p++; /* Cr / V */
402 p_sys->p_palette[i][1] = *p++; /* Cb / U */
403 p_sys->p_palette[i][3] = *p++; /* T */
406 i_cmd = *p++;
407 /* We do not really know this, FIXME */
408 if( i_cmd ) {i_cmd_arg = GETINT32(p);}
410 /* Actually, this is measured against a different origin, so we have to
411 * adjust it */
412 p_sys->second_field_offset = GETINT16(p);
413 p_sys->i_image_offset = p - p_block->p_buffer;
414 p_sys->i_image_length = p_sys->i_spu_size - p_sys->i_image_offset;
415 p_sys->metadata_length = p_sys->i_image_offset;
417 if( p_sys->i_debug & DECODE_DBG_PACKET )
419 msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
420 "spu size: %zu, duration: %"PRIu64" (d:%zu p:%"PRIu16")",
421 p_sys->i_x_start, p_sys->i_y_start,
422 p_sys->i_width, p_sys->i_height,
423 p_sys->i_spu_size, p_sys->i_duration,
424 p_sys->i_image_length, p_sys->i_image_offset);
426 for( i = 0; i < 4; i++ )
428 msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
429 p_sys->p_palette[i][3], p_sys->p_palette[i][0],
430 p_sys->p_palette[i][1], p_sys->p_palette[i][2] );
435 /*****************************************************************************
436 * DecodePacket: parse and decode an subtitle packet
437 *****************************************************************************
438 * This function parses and decodes an SPU packet and, if valid, returns a
439 * subpicture.
440 *****************************************************************************/
441 static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data )
443 decoder_sys_t *p_sys = p_dec->p_sys;
444 subpicture_t *p_spu;
445 subpicture_region_t *p_region;
446 video_format_t fmt;
447 video_palette_t palette;
448 int i;
450 /* Allocate the subpicture internal data. */
451 p_spu = decoder_NewSubpicture( p_dec, NULL );
452 if( !p_spu ) return NULL;
454 p_spu->i_start = p_data->i_pts;
455 p_spu->i_stop = p_data->i_pts + p_sys->i_duration;
456 p_spu->b_ephemer = true;
458 /* Create new subtitle region */
459 memset( &fmt, 0, sizeof(video_format_t) );
460 fmt.i_chroma = VLC_CODEC_YUVP;
463 The video on which the subtitle sits, is scaled, probably
464 4:3. However subtitle bitmaps assume an 1:1 aspect ratio.
466 FIXME: We should get the video aspect ratio from somewhere.
467 Two candidates are the video and the other possibility would be
468 the access module.
470 fmt.i_sar_num = p_sys->i_height;
471 fmt.i_sar_den = p_sys->i_width;
473 fmt.i_width = fmt.i_visible_width = p_sys->i_width;
474 fmt.i_height = fmt.i_visible_height = p_sys->i_height;
475 fmt.i_x_offset = fmt.i_y_offset = 0;
476 fmt.p_palette = &palette;
477 fmt.p_palette->i_entries = 4;
478 for( i = 0; i < fmt.p_palette->i_entries; i++ )
480 fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0];
481 fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1];
482 fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2];
483 fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3];
486 p_region = subpicture_region_New( &fmt );
487 if( !p_region )
489 msg_Err( p_dec, "cannot allocate SVCD subtitle region" );
490 decoder_DeleteSubpicture( p_dec, p_spu );
491 return NULL;
494 p_spu->p_region = p_region;
495 p_region->i_x = p_sys->i_x_start;
496 p_region->i_y = p_sys->i_y_start;
498 SVCDSubRenderImage( p_dec, p_data, p_region );
500 return p_spu;
503 /*****************************************************************************
504 * SVCDSubRenderImage: reorders bytes of image data in subpicture region.
505 *****************************************************************************
507 The image is encoded using two bits per pixel that select a palette
508 entry except that value 0 starts a limited run-length encoding for
509 color 0. When 0 is seen, the next two bits encode one less than the
510 number of pixels, so we can encode run lengths from 1 to 4. These get
511 filled with the color in palette entry 0.
513 The encoding of each line is padded to a whole number of bytes. The
514 first field is padded to an even byte length and the complete subtitle
515 is padded to a 4-byte multiple that always include one zero byte at
516 the end.
518 However we'll transform this so that that the RLE is expanded and
519 interlacing will also be removed.
520 *****************************************************************************/
521 static void SVCDSubRenderImage( decoder_t *p_dec, block_t *p_data,
522 subpicture_region_t *p_region )
524 decoder_sys_t *p_sys = p_dec->p_sys;
525 uint8_t *p_dest = p_region->p_picture->Y_PIXELS;
526 int i_field; /* The subtitles are interlaced */
527 int i_row, i_column; /* scanline row/column number */
528 uint8_t i_color, i_count;
529 bs_t bs;
531 bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset,
532 p_data->i_buffer - p_sys->i_image_offset );
534 for( i_field = 0; i_field < 2; i_field++ )
536 for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 )
538 for( i_column = 0; i_column < p_sys->i_width; i_column++ )
540 i_color = bs_read( &bs, 2 );
541 if( i_color == 0 && (i_count = bs_read( &bs, 2 )) )
543 i_count = __MIN( i_count, p_sys->i_width - i_column );
544 memset( &p_dest[i_row * p_region->p_picture->Y_PITCH +
545 i_column], 0, i_count + 1 );
546 i_column += i_count;
547 continue;
550 p_dest[i_row * p_region->p_picture->Y_PITCH + i_column] = i_color;
553 bs_align( &bs );
556 /* odd field */
557 bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset +
558 p_sys->second_field_offset,
559 p_data->i_buffer - p_sys->i_image_offset -
560 p_sys->second_field_offset );