1 /*****************************************************************************
2 * Philips OGT (SVCD subtitle) packet parser
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
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);
101 p_sys->i_duration *= config_GetInt( p_dec, MODULE_STRING
102 "-duration-scaling" );
104 /* 0 means display until next subtitle comes in. */
105 p_sys->i_duration = 0;
107 p_sys->i_x_start= GETINT16(p);
108 p_sys->i_y_start= GETINT16(p);
109 p_sys->i_width = GETINT16(p);
110 p_sys->i_height = GETINT16(p);
112 for (i=0; i<4; i++) {
113 p_sys->p_palette[i].s.y = *p++;
114 p_sys->p_palette[i].s.u = *p++;
115 p_sys->p_palette[i].s.v = *p++;
116 /* OGT has 8-bit resolution for alpha, but DVD's and CVDS use 4-bits.
117 Since we want to use the same render routine, rather than scale up
118 CVD (and DVD) subtitles, we'll scale down ours.
120 p_sys->p_palette[i].s.t = (*p++) >> 4;
123 /* We do not really know this, FIXME */
124 if ( p_sys->i_cmd ) {
125 p_sys->i_cmd_arg = GETINT32(p);
128 /* Actually, this is measured against a different origin, so we have to
130 p_sys->second_field_offset = GETINT16(p);
131 p_sys->i_image_offset = p - p_buffer;
132 p_sys->i_image_length = p_sys->i_spu_size - p_sys->i_image_offset;
133 p_sys->metadata_length = p_sys->i_image_offset;
135 if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
136 msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
137 "spu size: %d, duration: %lu (d:%d p:%d)",
138 p_sys->i_x_start, p_sys->i_y_start,
139 p_sys->i_width, p_sys->i_height,
140 p_sys->i_spu_size, (long unsigned int) p_sys->i_duration,
141 p_sys->i_image_length, p_sys->i_image_offset);
143 for (i=0; i<4; i++) {
144 msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
145 p_sys->p_palette[i].s.t, p_sys->p_palette[i].s.y,
146 p_sys->p_palette[i].s.u, p_sys->p_palette[i].s.v );
152 /*****************************************************************************
153 * ParsePacket: parse an SPU packet and send it to the video output
154 *****************************************************************************
155 * This function parses the SPU packet and, if valid, sends it to the
157 *****************************************************************************/
159 E_(ParsePacket)( decoder_t *p_dec)
161 decoder_sys_t *p_sys = p_dec->p_sys;
165 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
167 /* Allocate the subpicture internal data. */
168 p_spu = vout_CreateSubPicture( p_sys->p_vout, SUBT1_CHAN, TEXT_CONTENT,
175 /* In ParseImage we expand the run-length encoded color 0's; also
176 we expand pixels and remove the color palette. This should
177 facilitate scaling and antialiasing and speed up rendering.
179 p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
180 + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
182 /* Fill the p_spu structure */
183 vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
185 p_spu->pf_render = VCDSubBlend;
186 p_spu->pf_destroy = VCDSubDestroySPU;
187 p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
189 p_spu->p_sys->i_x_end = p_sys->i_x_start + p_sys->i_width - 1;
190 p_spu->p_sys->i_y_end = p_sys->i_y_start + p_sys->i_height - 1;
192 p_spu->i_x = p_sys->i_x_start
193 + config_GetInt( p_dec, MODULE_STRING "-horizontal-correct" );
195 p_spu->p_sys->p_palette[0] = p_sys->p_palette[0];
196 p_spu->p_sys->p_palette[1] = p_sys->p_palette[1];
197 p_spu->p_sys->p_palette[2] = p_sys->p_palette[2];
198 p_spu->p_sys->p_palette[3] = p_sys->p_palette[3];
200 /* FIXME: use aspect ratio for x? */
201 p_spu->i_x = (p_spu->i_x * 3) / 4;
202 p_spu->i_y = p_sys->i_y_start
203 + config_GetInt( p_dec, MODULE_STRING "-vertical-correct" );
204 p_spu->i_width = p_sys->i_width;
205 p_spu->i_height = p_sys->i_height;
207 p_spu->i_start = p_sys->i_pts;
208 p_spu->i_stop = p_sys->i_pts + p_sys->i_duration;
210 p_spu->p_sys->b_crop = VLC_FALSE;
211 p_spu->p_sys->i_debug = p_sys->i_debug;
213 /* Get display time now. If we do it later, we may miss the PTS. */
214 p_spu->p_sys->i_pts = p_sys->i_pts;
216 /* Attach to our input thread */
217 p_spu->p_sys->p_input = vlc_object_find( p_dec,
218 VLC_OBJECT_INPUT, FIND_PARENT );
220 /* We try to display it */
221 if( ParseImage( p_dec, p_spu ) )
223 /* There was a parse error, delete the subpicture */
224 vout_DestroySubPicture( p_sys->p_vout, p_spu );
228 /* SPU is finished - we can ask the video output to display it */
229 vout_DisplaySubPicture( p_sys->p_vout, p_spu );
233 /* Advance pointer to image pointer, update internal i_2bit_field counter
234 and check that we haven't goine too far in the image data. */
235 #define advance_color_pointer_byte \
240 "broken subtitle - tried to access beyond end " \
241 "in image extraction"); \
242 return VLC_EGENERIC; \
245 #define advance_color_pointer \
247 if ( i_2bit_field == 0 ) { \
248 advance_color_pointer_byte; \
251 #define OGT_FIELD_BITS (2)
252 #define OGT_FIELD_MASK ((1<<OGT_FIELD_BITS) - 1)
254 /* Get the next field - either a palette index or a RLE count for
255 color 0. To do this we use byte image pointer p, and i_2bit_field
256 which indicates where we are in the byte.
258 static inline ogt_color_t
259 ExtractField(uint8_t *p, unsigned int i_2bit_field)
261 return ( ( *p >> (OGT_FIELD_BITS*(i_2bit_field-1)) ) & OGT_FIELD_MASK );
264 /*****************************************************************************
265 * ParseImage: parse the image part of the subtitle
266 *****************************************************************************
267 This part parses the subtitle graphical data and stores it in a more
268 convenient structure for later rendering.
270 The image is encoded using two bits per pixel that select a palette
271 entry except that value 0 starts a limited run-length encoding for
272 color 0. When 0 is seen, the next two bits encode one less than the
273 number of pixels, so we can encode run lengths from 1 to 4. These get
274 filled with the color in palette entry 0.
276 The encoding of each line is padded to a whole number of bytes. The
277 first field is padded to an even byte length and the complete subtitle
278 is padded to a 4-byte multiple that always include one zero byte at
281 However we'll transform this so that that the RLE is expanded and
282 interlacing will also be removed. On output each pixel entry will by
283 an 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
285 *****************************************************************************/
287 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
289 decoder_sys_t *p_sys = p_dec->p_sys;
291 unsigned int i_field; /* The subtitles are interlaced, are we on an
292 even or odd scanline? */
294 unsigned int i_row; /* scanline row number */
295 unsigned int i_column; /* scanline column number */
297 unsigned int i_width = p_sys->i_width;
298 unsigned int i_height = p_sys->i_height;
300 uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
302 uint8_t i_2bit_field; /* The 2-bit field to sue in byte of *p.
304 uint8_t i_pending_zero = 0; /* number of pixels to fill with
306 ogt_color_t i_color; /* current pixel color: 0..3 */
307 uint8_t *p = p_sys->subtitle_data + p_sys->i_image_offset;
308 uint8_t *maxp = p + p_sys->i_image_length;
310 dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
313 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
316 for ( i_field=0; i_field < 2; i_field++ ) {
318 for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
319 for ( i_column=0; i_column<i_width; i_column++ ) {
321 if ( i_pending_zero ) {
322 /* We are in the middle of a RLE expansion, just decrement and
323 fall through with current color value */
327 i_color = ExtractField( p, i_2bit_field );
328 advance_color_pointer;
329 if ( i_color == 0 ) {
330 i_pending_zero = ExtractField( p, i_2bit_field );
331 advance_color_pointer;
332 /* Fall through with i_color == 0 to output the first cell */
337 p_dest[i_row*i_width+i_column] = i_color;
339 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
340 printf("%1d", i_color);
344 if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE))
347 if ( i_2bit_field != 4 ) {
348 /* Lines are padded to complete bytes, ignore padding */
349 advance_color_pointer_byte;
352 p = p_sys->subtitle_data + p_sys->i_image_offset
353 + p_sys->second_field_offset;
356 if (p_sys && (p_sys->i_debug & DECODE_DBG_IMAGE)) {
357 /* Dump out image not interlaced... */
358 VCDSubDumpImage( p_dest, i_height, i_width );
362 if (p_sys && (p_sys->i_debug & DECODE_DBG_PNG)) {
364 /* Dump image to a file in PNG format. */
366 png_text text_ptr[TEXT_COUNT];
368 text_ptr[0].key = "Preparer";
369 text_ptr[0].text = "VLC";
370 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
371 text_ptr[1].key = "Description";
372 text_ptr[1].text = "SVCD Subtitle";
373 text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
375 snprintf(filename, 300, "%s%d.png", "/tmp/vlc-svcd-sub", p_sys->i_image);
376 VCDSubDumpPNG( p_dest, p_dec, i_height, i_width, filename,
377 text_ptr, TEXT_COUNT );
379 #endif /*HAVE_LIBPNG*/
381 VCDSubHandleScaling( p_spu, p_dec );
388 * c-file-style: "gnu"
390 * indent-tabs-mode: nil