1 /*****************************************************************************
2 * Philips OGT (SVCD subtitle) packet parser
3 *****************************************************************************
4 * Copyright (C) 2003 VideoLAN
5 * $Id: ogt_parse.c,v 1.3 2003/12/29 04:47:44 rocky 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>
40 /* An image color is a two-bit palette entry: 0..3 */
41 typedef uint8_t ogt_color_t;
43 /*****************************************************************************
45 *****************************************************************************/
46 static int ParseImage ( decoder_t *, subpicture_t * );
49 The format is roughly as follows (everything is big-endian):
52 -------------------------------------------
53 byte subtitle channel (0..7) in bits 0-3
54 byte subtitle packet number of this subtitle image 0-N,
55 if the subtitle packet is complete, the top bit of the byte is 1.
56 u_int16 subtitle image number
57 u_int16 length in bytes of the rest
58 byte option flags, unknown meaning except bit 3 (0x08) indicates
59 presence of the duration field
61 u_int32 duration in 1/90000ths of a second (optional), start time
62 is as indicated by the PTS in the PES header
65 u_int32 width (must be even)
66 u_int32 height (must be even)
67 byte[16] palette, 4 palette entries, each contains values for
68 Y, U, V and transparency, 0 standing for transparent
70 cmd>>6==1 indicates shift
71 (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom)
72 u_int32 shift duration in 1/90000ths of a second
73 u_int16 offset of odd-numbered scanlines - subtitle images are
74 given in interlace order
75 byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with
76 2-bits per palette number
79 /* FIXME: do we really need p_buffer and p?
80 Can't all of thes _offset's and _lengths's get removed?
82 void E_(ParseHeader)( decoder_t *p_dec, uint8_t *p_buffer, block_t *p_block )
84 decoder_sys_t *p_sys = p_dec->p_sys;
85 u_int8_t *p = p_buffer;
88 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
90 p_sys->i_pts = p_block->i_pts;
91 p_sys->i_spu_size = GETINT16(p);
92 p_sys->i_options = *p++;
93 p_sys->i_options2 = *p++;
95 if ( p_sys->i_options & 0x08 ) {
96 p_sys->i_duration = GETINT32(p);
98 /* 0 means display until next subtitle comes in. */
99 p_sys->i_duration = 0;
101 p_sys->i_x_start= GETINT16(p);
102 p_sys->i_y_start= GETINT16(p);
103 p_sys->i_width = GETINT16(p);
104 p_sys->i_height = GETINT16(p);
106 for (i=0; i<4; i++) {
107 p_sys->pi_palette[i].s.y = *p++;
108 p_sys->pi_palette[i].s.u = *p++;
109 p_sys->pi_palette[i].s.v = *p++;
110 /* OGT has 8-bit resolution for alpha, but DVD's and CVDS use 4-bits.
111 Since we want to use the same render routine, rather than scale up
112 CVD (and DVD) subtitles, we'll scale down ours.
114 p_sys->pi_palette[i].s.t = (*p++) >> 4;
117 /* We do not really know this, FIXME */
118 if ( p_sys->i_cmd ) {
119 p_sys->i_cmd_arg = GETINT32(p);
122 /* Actually, this is measured against a different origin, so we have to
124 p_sys->second_field_offset = GETINT16(p);
125 p_sys->comp_image_offset = p - p_buffer;
126 p_sys->comp_image_length = p_sys->i_spu_size - p_sys->comp_image_offset;
127 p_sys->metadata_length = p_sys->comp_image_offset;
129 if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) {
130 msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, "
131 "spu size: %d, duration: %u (d:%d p:%d)",
132 p_sys->i_x_start, p_sys->i_y_start,
133 p_sys->i_width, p_sys->i_height,
134 p_sys->i_spu_size, p_sys->i_duration,
135 p_sys->comp_image_length, p_sys->comp_image_offset);
137 for (i=0; i<4; i++) {
138 msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i,
139 p_sys->pi_palette[i].s.t, p_sys->pi_palette[i].s.y,
140 p_sys->pi_palette[i].s.u, p_sys->pi_palette[i].s.v );
146 /*****************************************************************************
147 * ParsePacket: parse an SPU packet and send it to the video output
148 *****************************************************************************
149 * This function parses the SPU packet and, if valid, sends it to the
151 *****************************************************************************/
153 E_(ParsePacket)( decoder_t *p_dec)
155 decoder_sys_t *p_sys = p_dec->p_sys;
159 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
161 /* Allocate the subpicture internal data. */
162 p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );
168 /* In ParseImage we expand the run-length encoded color 0's; also
169 we expand pixels and remove the color palette. This should
170 facilitate scaling and antialiasing and speed up rendering.
172 p_spu->p_sys = malloc( sizeof( subpicture_sys_t )
173 + PIXEL_SIZE * (p_sys->i_width * p_sys->i_height) );
175 /* Fill the p_spu structure */
176 vlc_mutex_init( p_dec, &p_spu->p_sys->lock );
178 p_spu->pf_render = VCDSubRender;
179 p_spu->pf_destroy = VCDSubDestroySPU;
180 p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );
182 p_spu->p_sys->i_x_end = p_sys->i_x_start + p_sys->i_width - 1;
183 p_spu->p_sys->i_y_end = p_sys->i_y_start + p_sys->i_height - 1;
185 /* FIXME: use aspect ratio for x? */
186 p_spu->i_x = p_sys->i_x_start * 3 / 4;
187 p_spu->i_y = p_sys->i_y_start;
188 p_spu->i_width = p_sys->i_width;
189 p_spu->i_height = p_sys->i_height;
191 p_spu->i_start = p_sys->i_pts;
192 p_spu->i_stop = p_sys->i_pts + (p_sys->i_duration * 10);
194 p_spu->p_sys->b_crop = VLC_FALSE;
195 p_spu->p_sys->i_debug = p_sys->i_debug;
197 /* Get display time now. If we do it later, we may miss the PTS. */
198 p_spu->p_sys->i_pts = p_sys->i_pts;
200 /* Attach to our input thread */
201 p_spu->p_sys->p_input = vlc_object_find( p_dec,
202 VLC_OBJECT_INPUT, FIND_PARENT );
204 /* We try to display it */
205 if( ParseImage( p_dec, p_spu ) )
207 /* There was a parse error, delete the subpicture */
208 vout_DestroySubPicture( p_sys->p_vout, p_spu );
212 /* SPU is finished - we can ask the video output to display it */
213 vout_DisplaySubPicture( p_sys->p_vout, p_spu );
217 /* Advance pointer to image pointer, update internal i_remaining counter
218 and check that we haven't goine too far in the image data. */
219 #define advance_color_pointer_byte \
224 "broken subtitle - tried to access beyond end " \
225 "in image extraction"); \
226 return VLC_EGENERIC; \
229 #define advance_color_pointer \
231 if ( i_remaining == 0 ) { \
232 advance_color_pointer_byte; \
235 /* Get the next field - either a palette index or a RLE count for
236 color 0. To do this we use byte image pointer p, and i_remaining
237 which indicates where we are in the byte.
239 static inline ogt_color_t
240 ExtractField(uint8_t *p, unsigned int i_remaining)
242 return ( ( *p >> 2*(i_remaining-1) ) & 0x3 );
245 /*****************************************************************************
246 * ParseImage: parse the image part of the subtitle
247 *****************************************************************************
248 This part parses the subtitle graphical data and stores it in a more
249 convenient structure for later rendering.
251 The image is encoded using two bits per pixel that select a palette
252 entry except that value 0 starts a limited run-length encoding for
253 color 0. When 0 is seen, the next two bits encode one less than the
254 number of pixels, so we can encode run lengths from 1 to 4. These get
255 filled with the color in palette entry 0.
257 The encoding of each line is padded to a whole number of bytes. The
258 first field is padded to an even byte length and the complete subtitle
259 is padded to a 4-byte multiple that always include one zero byte at
262 However we'll transform this so that that the RLE is expanded and
263 interlacing will also be removed. On output each pixel entry will by
264 an 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
266 *****************************************************************************/
268 ParseImage( decoder_t *p_dec, subpicture_t * p_spu )
270 decoder_sys_t *p_sys = p_dec->p_sys;
272 unsigned int i_field; /* The subtitles are interlaced, are we on an
273 even or odd scanline? */
275 unsigned int i_row; /* scanline row number */
276 unsigned int i_column; /* scanline column number */
278 unsigned int i_width = p_sys->i_width;
279 unsigned int i_height = p_sys->i_height;
281 uint8_t *p_dest = (uint8_t *)p_spu->p_sys->p_data;
283 uint8_t i_remaining; /* number of 2-bit pixels remaining
285 uint8_t i_pending_zero = 0; /* number of pixels to fill with
287 ogt_color_t i_color; /* current pixel color: 0..3 */
288 uint8_t *p = p_sys->subtitle_data + p_sys->comp_image_offset;
289 uint8_t *maxp = p + p_sys->comp_image_length;
291 dbg_print( (DECODE_DBG_CALL) , "width x height: %dx%d ",
294 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
297 for ( i_field=0; i_field < 2; i_field++ ) {
299 for ( i_row=i_field; i_row < i_height; i_row += 2 ) {
300 for ( i_column=0; i_column<i_width; i_column++ ) {
302 if ( i_pending_zero ) {
303 /* We are in the middle of a RLE expansion, just decrement and
304 fall through with current color value */
308 i_color = ExtractField( p, i_remaining);
309 advance_color_pointer;
310 if ( i_color == 0 ) {
311 i_pending_zero = ExtractField( p, i_remaining );
312 advance_color_pointer;
313 /* Fall through with i_color == 0 to output the first cell */
318 p_dest[i_row*i_width+i_column] = i_color;
320 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
321 printf("%1d", i_color);
325 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE)
328 if ( i_remaining != 4 ) {
329 /* Lines are padded to complete bytes, ignore padding */
330 advance_color_pointer_byte;
333 p = p_sys->subtitle_data + p_sys->comp_image_offset
334 + p_sys->second_field_offset;
337 /* Dump out image not interlaced... */
338 if (p_sys && p_sys->i_debug & DECODE_DBG_IMAGE) {
340 printf("-------------------------------------\n++");
341 for ( i_row=0; i_row < i_height; i_row ++ ) {
342 for ( i_column=0; i_column<i_width; i_column++ ) {
343 printf("%1d", *p++ & 0x03);
347 printf("\n-------------------------------------\n");
350 /* Remove color palette by expanding pixel entries to contain the
351 palette values. We work from the free space at the end to the
352 beginning so we can expand inline.
355 int n = (i_height * i_width) - 1;
356 uint8_t *p_from = p_dest;
357 ogt_yuvt_t *p_to = (ogt_yuvt_t *) p_dest;
359 for ( ; n >= 0 ; n-- ) {
360 p_to[n] = p_sys->pi_palette[p_from[n]];
364 /* The video is automatically scaled. However subtitle bitmaps
365 assume a 1:1 aspect ratio. So we need to scale to compensate for
366 or undo the effects of video output scaling.
368 /* FIXME do the right scaling depending on vout. It may not be 4:3 */
369 VCDSubScaleX( p_dec, p_spu, 3, 4 );