1 /*****************************************************************************
2 * Philips OGT (SVCD subtitle) packet parser
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
5 * $Id: ogt_parse.c,v 1.6 2004/01/04 22:22:10 gbazin Exp $
7 * Author: 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 The format is roughly as follows (everything is big-endian):
56 -------------------------------------------
57 byte subtitle channel (0..7) in bits 0-3
58 byte subtitle packet number of this subtitle image 0-N,
59 if the subtitle packet is complete, the top bit of the byte is 1.
60 u_int16 subtitle image number
61 u_int16 length in bytes of the rest
62 byte option flags, unknown meaning except bit 3 (0x08) indicates
63 presence of the duration field
65 u_int32 duration in 1/90000ths of a second (optional), start time
66 is as indicated by the PTS in the PES header
69 u_int32 width (must be even)
70 u_int32 height (must be even)
71 byte[16] palette, 4 palette entries, each contains values for
72 Y, U, V and transparency, 0 standing for transparent
74 cmd>>6==1 indicates shift
75 (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
76 u_int32 shift duration in 1/90000ths of a second
77 u_int16 offset of odd-numbered scanlines - subtitle images are
78 given in interlace order
79 byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with
80 2-bits per palette number
83 /* FIXME: do we really need p_buffer and p?
84 Can't all of thes _offset's and _lengths's get removed?
86 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
88 decoder_sys_t *p_sys = p_dec->p_sys;
89 uint8_t *p = p_buffer;
92 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
94 p_sys->i_pts = p_block->i_pts;
95 p_sys->i_spu_size = GETINT16(p);
96 p_sys->i_options = *p++;
97 p_sys->i_options2 = *p++;
99 if ( p_sys->i_options & 0x08 ) {
100 p_sys->i_duration = GETINT32(p);
102 /* 0 means display until next subtitle comes in. */
103 p_sys->i_duration = 0;
105 p_sys->i_x_start= GETINT16(p);
106 p_sys->i_y_start= GETINT16(p);
107 p_sys->i_width = GETINT16(p);
108 p_sys->i_height = GETINT16(p);
110 for (i=0; i<4; i++) {
111 p_sys->p_palette[i].s.y = *p++;
112 p_sys->p_palette[i].s.u = *p++;
113 p_sys->p_palette[i].s.v = *p++;
114 /* OGT has 8-bit resolution for alpha, but DVD's and CVDS use 4-bits.
115 Since we want to use the same render routine, rather than scale up
116 CVD (and DVD) subtitles, we'll scale down ours.
118 p_sys->p_palette[i].s.t = (*p++) >> 4;
121 /* We do not really know this, FIXME */
122 if ( p_sys->i_cmd ) {
123 p_sys->i_cmd_arg = GETINT32(p);
126 /* Actually, this is measured against a different origin, so we have to
128 p_sys->second_field_offset = GETINT16(p);
129 p_sys->comp_image_offset = p - p_buffer;
130 p_sys->comp_image_length = p_sys->i_spu_size - p_sys->comp_image_offset;
131 p_sys->metadata_length = p_sys->comp_image_offset;
133 if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
134 msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
135 "spu size: %d, duration: %u (d:%d p:%d)",
136 p_sys->i_x_start, p_sys->i_y_start,
137 p_sys->i_width, p_sys->i_height,
138 p_sys->i_spu_size, p_sys->i_duration,
139 p_sys->comp_image_length, p_sys->comp_image_offset);
141 for (i=0; i<4; i++) {
142 msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
143 p_sys->p_palette[i].s.t, p_sys->p_palette[i].s.y,
144 p_sys->p_palette[i].s.u, p_sys->p_palette[i].s.v );
150 /*****************************************************************************
151 * ParsePacket: parse an SPU packet and send it to the video output
152 *****************************************************************************
153 * This function parses the SPU packet and, if valid, sends it to the
155 *****************************************************************************/
157 E_(ParsePacket)( decoder_t *p_dec)
159 decoder_sys_t *p_sys = p_dec->p_sys;
163 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
165 /* Allocate the subpicture internal data. */
166 p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
172 /* In ParseImage we expand the run-length encoded color 0's; also
173 we expand pixels and remove the color palette. This should
174 facilitate scaling and antialiasing and speed up rendering.
176 p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
177 + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
179 /* Fill the p_spu structure */
180 vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
182 p_spu->pf_render = VCDSubRender;
183 p_spu->pf_destroy = VCDSubDestroySPU;
184 p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
186 p_spu->p_sys->i_x_end = p_sys->i_x_start + p_sys->i_width - 1;
187 p_spu->p_sys->i_y_end = p_sys->i_y_start + p_sys->i_height - 1;
189 /* FIXME: use aspect ratio for x? */
190 p_spu->i_x = p_sys->i_x_start * 3 / 4;
191 p_spu->i_y = p_sys->i_y_start;
192 p_spu->i_width = p_sys->i_width;
193 p_spu->i_height = p_sys->i_height;
195 p_spu->i_start = p_sys->i_pts;
196 p_spu->i_stop = p_sys->i_pts + (p_sys->i_duration * 10);
198 p_spu->p_sys->b_crop = VLC_FALSE;
199 p_spu->p_sys->i_debug = p_sys->i_debug;
201 /* Get display time now. If we do it later, we may miss the PTS. */
202 p_spu->p_sys->i_pts = p_sys->i_pts;
204 /* Attach to our input thread */
205 p_spu->p_sys->p_input = vlc_object_find( p_dec,
206 VLC_OBJECT_INPUT, FIND_PARENT );
208 /* We try to display it */
209 if( ParseImage( p_dec, p_spu ) )
211 /* There was a parse error, delete the subpicture */
212 vout_DestroySubPicture( p_sys->p_vout, p_spu );
216 /* SPU is finished - we can ask the video output to display it */
217 vout_DisplaySubPicture( p_sys->p_vout, p_spu );
221 /* Advance pointer to image pointer, update internal i_2bit_field counter
222 and check that we haven't goine too far in the image data. */
223 #define advance_color_pointer_byte \
228 "broken subtitle - tried to access beyond end " \
229 "in image extraction"); \
230 return VLC_EGENERIC; \
233 #define advance_color_pointer \
235 if ( i_2bit_field == 0 ) { \
236 advance_color_pointer_byte; \
239 #define OGT_FIELD_BITS (2)
240 #define OGT_FIELD_MASK ((1<<OGT_FIELD_BITS) - 1)
242 /* Get the next field - either a palette index or a RLE count for
243 color 0. To do this we use byte image pointer p, and i_2bit_field
244 which indicates where we are in the byte.
246 static inline ogt_color_t
247 ExtractField(uint8_t *p, unsigned int i_2bit_field)
249 return ( ( *p >> (OGT_FIELD_BITS*(i_2bit_field-1)) ) & OGT_FIELD_MASK );
252 /*****************************************************************************
253 * ParseImage: parse the image part of the subtitle
254 *****************************************************************************
255 This part parses the subtitle graphical data and stores it in a more
256 convenient structure for later rendering.
258 The image is encoded using two bits per pixel that select a palette
259 entry except that value 0 starts a limited run-length encoding for
260 color 0. When 0 is seen, the next two bits encode one less than the
261 number of pixels, so we can encode run lengths from 1 to 4. These get
262 filled with the color in palette entry 0.
264 The encoding of each line is padded to a whole number of bytes. The
265 first field is padded to an even byte length and the complete subtitle
266 is padded to a 4-byte multiple that always include one zero byte at
269 However we'll transform this so that that the RLE is expanded and
270 interlacing will also be removed. On output each pixel entry will by
271 an 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
273 *****************************************************************************/
275 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
277 decoder_sys_t *p_sys = p_dec->p_sys;
279 unsigned int i_field; /* The subtitles are interlaced, are we on an
280 even or odd scanline? */
282 unsigned int i_row; /* scanline row number */
283 unsigned int i_column; /* scanline column number */
285 unsigned int i_width = p_sys->i_width;
286 unsigned int i_height = p_sys->i_height;
288 uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
290 uint8_t i_2bit_field; /* The 2-bit field to sue in byte of *p.
292 uint8_t i_pending_zero = 0; /* number of pixels to fill with
294 ogt_color_t i_color; /* current pixel color: 0..3 */
295 uint8_t *p = p_sys->subtitle_data + p_sys->comp_image_offset;
296 uint8_t *maxp = p + p_sys->comp_image_length;
298 dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
301 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
304 for ( i_field=0; i_field < 2; i_field++ ) {
306 for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
307 for ( i_column=0; i_column<i_width; i_column++ ) {
309 if ( i_pending_zero ) {
310 /* We are in the middle of a RLE expansion, just decrement and
311 fall through with current color value */
315 i_color = ExtractField( p, i_2bit_field );
316 advance_color_pointer;
317 if ( i_color == 0 ) {
318 i_pending_zero = ExtractField( p, i_2bit_field );
319 advance_color_pointer;
320 /* Fall through with i_color == 0 to output the first cell */
325 p_dest[i_row*i_width+i_column] = i_color;
327 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
328 printf("%1d", i_color);
332 if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE))
335 if ( i_2bit_field != 4 ) {
336 /* Lines are padded to complete bytes, ignore padding */
337 advance_color_pointer_byte;
340 p = p_sys->subtitle_data + p_sys->comp_image_offset
341 + p_sys->second_field_offset;
344 if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE)) {
345 /* Dump out image not interlaced... */
346 VCDSubDumpImage( p_dest, i_height, i_width );
350 if (p_sys && (p_sys->i_debug & DECODE_DBG_PNG)) {
352 /* Dump image to a file in PNG format. */
354 png_text text_ptr[TEXT_COUNT];
356 text_ptr[0].key = "Preparer";
357 text_ptr[0].text = "VLC";
358 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
359 text_ptr[1].key = "Description";
360 text_ptr[1].text = "SVCD Subtitle";
361 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
363 snprintf(filename, 300, "%s%d.png", "/tmp/vlc-svcd-sub", p_sys->i_image);
364 VCDSubDumpPNG( p_dest, p_dec, i_height, i_width, filename,
365 text_ptr, TEXT_COUNT );
367 #endif /*HAVE_LIBPNG*/
369 VCDInlinePalette( p_dest, p_sys, i_height, i_width );
372 /* The video is automatically scaled. However subtitle bitmaps
373 assume a 1:1 aspect ratio. So we need to scale to compensate for
374 or undo the effects of video output scaling.
376 /* FIXME do the right scaling depending on vout. It may not be 4:3 */
377 VCDSubScaleX( p_dec, p_spu, 3, 4 );