1 /* $Id: decsub.c,v 1.12 2005/04/14 17:37:54 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.m0k.org/>.
5 It may be used under the terms of the GNU General Public License. */
9 struct hb_work_private_s
33 static hb_buffer_t * Decode( hb_work_object_t * );
35 int decsubInit( hb_work_object_t * w, hb_job_t * job )
37 hb_work_private_t * pv;
39 pv = calloc( 1, sizeof( hb_work_private_t ) );
48 int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
49 hb_buffer_t ** buf_out )
51 hb_work_private_t * pv = w->private_data;
52 hb_buffer_t * in = *buf_in;
54 int size_sub, size_rle;
56 size_sub = ( in->data[0] << 8 ) | in->data[1];
57 size_rle = ( in->data[2] << 8 ) | in->data[3];
61 /* We are looking for the start of a new subtitle */
62 if( size_sub && size_rle && size_sub > size_rle &&
63 in->size <= size_sub )
65 /* Looks all right so far */
66 pv->size_sub = size_sub;
67 pv->size_rle = size_rle;
69 memcpy( pv->buf, in->data, in->size );
70 pv->size_got = in->size;
76 /* We are waiting for the end of the current subtitle */
77 if( in->size <= pv->size_sub - pv->size_got )
79 memcpy( pv->buf + pv->size_got, in->data, in->size );
80 pv->size_got += in->size;
90 if( pv->size_sub && pv->size_sub == pv->size_got )
92 /* We got a complete subtitle, decode it */
93 *buf_out = Decode( w );
95 /* Wait for the next one */
105 void decsubClose( hb_work_object_t * w )
107 free( w->private_data );
110 hb_work_object_t hb_decsub =
120 /***********************************************************************
122 ***********************************************************************
123 * Get the start and end dates (relative to the PTS from the PES
124 * header), the width and height of the subpicture and the colors and
126 **********************************************************************/
127 static void ParseControls( hb_work_object_t * w )
129 hb_work_private_t * pv = w->private_data;
130 hb_job_t * job = pv->job;
131 hb_title_t * title = job->title;
141 for( i = pv->size_rle; ; )
143 date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
144 next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
148 command = pv->buf[i++];
151 * There are eight commands available for
152 * Sub-Pictures. The first SP_DCSQ should contain, as a
153 * minimum, SET_COLOR, SET_CONTR, SET_DAREA, and
157 if( command == 0xFF ) // 0xFF - CMD_END - ends one SP_DCSQ
164 case 0x00: // 0x00 - FSTA_DSP - Forced Start Display, no arguments
165 pv->pts_start = pv->pts + date * 900;
169 case 0x01: // 0x01 - STA_DSP - Start Display, no arguments
170 pv->pts_start = pv->pts + date * 900;
174 case 0x02: // 0x02 - STP_DSP - Stop Display, no arguments
175 pv->pts_stop = pv->pts + date * 900;
178 case 0x03: // 0x03 - SET_COLOR - Set Colour indices
181 * SET_COLOR - provides four indices into the CLUT
182 * for the current PGC to associate with the four
188 colors[0] = (pv->buf[i+0]>>4)&0x0f;
189 colors[1] = (pv->buf[i+0])&0x0f;
190 colors[2] = (pv->buf[i+1]>>4)&0x0f;
191 colors[3] = (pv->buf[i+1])&0x0f;
193 for( j = 0; j < 4; j++ )
196 * Not sure what is happening here, in theory
197 * the palette is in YCbCr. And we want YUV.
199 * However it looks more like YCrCb (according
200 * to pgcedit). And the scalers for YCrCb don't
201 * work, but I get the right colours by doing
204 uint32_t color = title->palette[colors[j]];
206 y = (color>>16) & 0xff;
207 Cr = (color>>8) & 0xff;
210 pv->chromaU[3-j] = Cb;
211 pv->chromaV[3-j] = Cr;
212 /* hb_log("color[%d] y = %d, u = %d, v = %d",
222 case 0x04: // 0x04 - SET_CONTR - Set Contrast
225 * SET_CONTR - directly provides the four contrast
226 * (alpha blend) values to associate with the four
229 pv->alpha[3] = (pv->buf[i+0]>>4)&0x0f;
230 pv->alpha[2] = (pv->buf[i+0])&0x0f;
231 pv->alpha[1] = (pv->buf[i+1]>>4)&0x0f;
232 pv->alpha[0] = (pv->buf[i+1])&0x0f;
236 case 0x05: // 0x05 - SET_DAREA - defines the display area
238 pv->x = (pv->buf[i+0]<<4) | ((pv->buf[i+1]>>4)&0x0f);
239 pv->width = (((pv->buf[i+1]&0x0f)<<8)| pv->buf[i+2]) - pv->x + 1;
240 pv->y = (pv->buf[i+3]<<4)| ((pv->buf[i+4]>>4)&0x0f);
241 pv->height = (((pv->buf[i+4]&0x0f)<<8)| pv->buf[i+5]) - pv->y + 1;
245 case 0x06: // 0x06 - SET_DSPXA - defines the pixel data addresses
247 pv->offsets[0] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
248 pv->offsets[1] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
263 /* Show it for 3 seconds */
264 pv->pts_stop = pv->pts_start + 3 * 90000;
268 /***********************************************************************
270 ***********************************************************************
271 * Given a raw decoded subtitle, detects transparent borders and
272 * returns a cropped subtitle in a hb_buffer_t ready to be used by
273 * the renderer, or NULL if the subtitle was completely transparent
274 **********************************************************************/
275 static int LineIsTransparent( hb_work_object_t * w, uint8_t * p )
277 hb_work_private_t * pv = w->private_data;
279 for( i = 0; i < pv->width; i++ )
288 static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p )
290 hb_work_private_t * pv = w->private_data;
292 for( i = 0; i < pv->height; i++ )
301 static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw )
303 hb_work_private_t * pv = w->private_data;
305 int crop[4] = { -1,-1,-1,-1 };
307 int realwidth, realheight;
309 uint8_t * lum_in, * lum_out, * alpha_in, * alpha_out;
310 uint8_t * u_in, * u_out, * v_in, * v_out;
312 alpha = raw + pv->width * pv->height;
315 for( i = 0; i < pv->height; i++ )
317 if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
331 for( i = pv->height - 1; i >= 0; i-- )
333 if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
341 for( i = 0; i < pv->width; i++ )
343 if( !ColumnIsTransparent( w, &alpha[i] ) )
351 for( i = pv->width - 1; i >= 0; i-- )
353 if( !ColumnIsTransparent( w, &alpha[i] ) )
360 realwidth = crop[3] - crop[2] + 1;
361 realheight = crop[1] - crop[0] + 1;
363 buf = hb_buffer_init( realwidth * realheight * 4 );
364 buf->start = pv->pts_start;
365 buf->stop = pv->pts_stop;
366 buf->x = pv->x + crop[2];
367 buf->y = pv->y + crop[0];
368 buf->width = realwidth;
369 buf->height = realheight;
371 lum_in = raw + crop[0] * pv->width + crop[2];
372 alpha_in = lum_in + pv->width * pv->height;
373 u_in = alpha_in + pv->width * pv->height;
374 v_in = u_in + pv->width * pv->height;
377 alpha_out = lum_out + realwidth * realheight;
378 u_out = alpha_out + realwidth * realheight;
379 v_out = u_out + realwidth * realheight;
381 for( i = 0; i < realheight; i++ )
383 memcpy( lum_out, lum_in, realwidth );
384 memcpy( alpha_out, alpha_in, realwidth );
385 memcpy( u_out, u_in, realwidth );
386 memcpy( v_out, v_in, realwidth );
389 alpha_in += pv->width;
393 lum_out += realwidth;
394 alpha_out += realwidth;
402 static hb_buffer_t * Decode( hb_work_object_t * w )
404 hb_work_private_t * pv = w->private_data;
409 uint8_t * buf_raw = NULL;
410 hb_job_t * job = pv->job;
412 /* Get infos about the subtitle */
415 if( job->subtitle_force && pv->pts_forced == 0 )
418 * When forcing subtitles, ignore all those that don't
419 * have the forced flag set.
424 /* Do the actual decoding now */
425 buf_raw = malloc( pv->width * pv->height * 4 );
427 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
428 ( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
431 offsets[0] = pv->offsets[0] * 2;
432 offsets[1] = pv->offsets[1] * 2;
434 for( line = 0; line < pv->height; line++ )
436 /* Select even or odd field */
437 offset = ( line & 1 ) ? &offsets[1] : &offsets[0];
439 for( col = 0; col < pv->width; col += code >> 2 )
441 uint8_t * lum, * alpha, * chromaU, * chromaV;
457 code |= ( pv->width - col ) << 2;
464 alpha = lum + pv->width * pv->height;
465 chromaU = alpha + pv->width * pv->height;
466 chromaV = chromaU + pv->width * pv->height;
468 memset( lum + line * pv->width + col,
469 pv->lum[code & 3], code >> 2 );
470 memset( alpha + line * pv->width + col,
471 pv->alpha[code & 3], code >> 2 );
472 memset( chromaU + line * pv->width + col,
473 pv->chromaU[code & 3], code >> 2 );
474 memset( chromaV + line * pv->width + col,
475 pv->chromaV[code & 3], code >> 2 );
485 /* Crop subtitle (remove transparent borders) */
486 buf = CropSubtitle( w, buf_raw );