Refer to transitions in the presence-or-lack-thereof of progressive flags on MPEG...
[HandBrake.git] / libhb / decsub.c
blob209c1c80f45e29e7502db4b5dc515356c4884204
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. */
7 #include "hb.h"
9 struct hb_work_private_s
11 hb_job_t * job;
13 uint8_t buf[0xFFFF];
14 int size_sub;
15 int size_got;
16 int size_rle;
17 int64_t pts;
18 int64_t pts_start;
19 int64_t pts_stop;
20 int pts_forced;
21 int x;
22 int y;
23 int width;
24 int height;
25 int stream_id;
27 int offsets[2];
28 uint8_t lum[4];
29 uint8_t chromaU[4];
30 uint8_t chromaV[4];
31 uint8_t alpha[4];
34 static hb_buffer_t * Decode( hb_work_object_t * );
36 int decsubInit( hb_work_object_t * w, hb_job_t * job )
38 hb_work_private_t * pv;
40 pv = calloc( 1, sizeof( hb_work_private_t ) );
41 w->private_data = pv;
43 pv->job = job;
44 pv->pts = -1;
46 return 0;
49 int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
50 hb_buffer_t ** buf_out )
52 hb_work_private_t * pv = w->private_data;
53 hb_buffer_t * in = *buf_in;
55 int size_sub, size_rle;
57 pv->stream_id = in->id;
59 size_sub = ( in->data[0] << 8 ) | in->data[1];
60 size_rle = ( in->data[2] << 8 ) | in->data[3];
62 if( !pv->size_sub )
64 /* We are looking for the start of a new subtitle */
65 if( size_sub && size_rle && size_sub > size_rle &&
66 in->size <= size_sub )
68 /* Looks all right so far */
69 pv->size_sub = size_sub;
70 pv->size_rle = size_rle;
72 memcpy( pv->buf, in->data, in->size );
73 pv->size_got = in->size;
74 pv->pts = in->start;
77 else
79 /* We are waiting for the end of the current subtitle */
80 if( in->size <= pv->size_sub - pv->size_got )
82 memcpy( pv->buf + pv->size_got, in->data, in->size );
83 pv->size_got += in->size;
84 if( in->start >= 0 )
86 pv->pts = in->start;
91 *buf_out = NULL;
93 if( pv->size_sub && pv->size_sub == pv->size_got )
95 /* We got a complete subtitle, decode it */
96 *buf_out = Decode( w );
98 if( buf_out && *buf_out )
100 (*buf_out)->sequence = in->sequence;
103 /* Wait for the next one */
104 pv->size_sub = 0;
105 pv->size_got = 0;
106 pv->size_rle = 0;
107 pv->pts = -1;
110 return HB_WORK_OK;
113 void decsubClose( hb_work_object_t * w )
115 free( w->private_data );
118 hb_work_object_t hb_decsub =
120 WORK_DECSUB,
121 "Subtitle decoder",
122 decsubInit,
123 decsubWork,
124 decsubClose
128 /***********************************************************************
129 * ParseControls
130 ***********************************************************************
131 * Get the start and end dates (relative to the PTS from the PES
132 * header), the width and height of the subpicture and the colors and
133 * alphas used in it
134 **********************************************************************/
135 static void ParseControls( hb_work_object_t * w )
137 hb_work_private_t * pv = w->private_data;
138 hb_job_t * job = pv->job;
139 hb_title_t * title = job->title;
140 hb_subtitle_t * subtitle;
142 int i, n;
143 int command;
144 int date, next;
146 pv->pts_start = 0;
147 pv->pts_stop = 0;
148 pv->pts_forced = 0;
150 pv->alpha[3] = 0;
151 pv->alpha[2] = 0;
152 pv->alpha[1] = 0;
153 pv->alpha[0] = 0;
155 for( i = pv->size_rle; ; )
157 date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
158 next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
160 for( ;; )
162 command = pv->buf[i++];
165 * There are eight commands available for
166 * Sub-Pictures. The first SP_DCSQ should contain, as a
167 * minimum, SET_COLOR, SET_CONTR, SET_DAREA, and
168 * SET_DSPXA
171 if( command == 0xFF ) // 0xFF - CMD_END - ends one SP_DCSQ
173 break;
176 switch( command )
178 case 0x00: // 0x00 - FSTA_DSP - Forced Start Display, no arguments
179 pv->pts_start = pv->pts + date * 900;
180 pv->pts_forced = 1;
183 * If we are doing a subtitle scan then note down
185 if( job->indepth_scan )
187 for( n=0; n < hb_list_count(title->list_subtitle); n++ )
189 subtitle = hb_list_item( title->list_subtitle, n);
190 if( pv->stream_id == subtitle->id ) {
192 * A hit, count it.
194 subtitle->forced_hits++;
198 break;
200 case 0x01: // 0x01 - STA_DSP - Start Display, no arguments
201 pv->pts_start = pv->pts + date * 900;
202 pv->pts_forced = 0;
203 break;
205 case 0x02: // 0x02 - STP_DSP - Stop Display, no arguments
206 if(!pv->pts_stop)
207 pv->pts_stop = pv->pts + date * 900;
208 break;
210 case 0x03: // 0x03 - SET_COLOR - Set Colour indices
213 * SET_COLOR - provides four indices into the CLUT
214 * for the current PGC to associate with the four
215 * pixel values
217 int colors[4];
218 int j;
220 colors[0] = (pv->buf[i+0]>>4)&0x0f;
221 colors[1] = (pv->buf[i+0])&0x0f;
222 colors[2] = (pv->buf[i+1]>>4)&0x0f;
223 colors[3] = (pv->buf[i+1])&0x0f;
225 for( j = 0; j < 4; j++ )
228 * Not sure what is happening here, in theory
229 * the palette is in YCbCr. And we want YUV.
231 * However it looks more like YCrCb (according
232 * to pgcedit). And the scalers for YCrCb don't
233 * work, but I get the right colours by doing
234 * no conversion.
236 uint32_t color = title->palette[colors[j]];
237 uint8_t Cr, Cb, y;
238 y = (color>>16) & 0xff;
239 Cr = (color>>8) & 0xff;
240 Cb = (color) & 0xff;
241 pv->lum[3-j] = y;
242 pv->chromaU[3-j] = Cb;
243 pv->chromaV[3-j] = Cr;
244 /* hb_log("color[%d] y = %d, u = %d, v = %d",
245 3-j,
246 pv->lum[3-j],
247 pv->chromaU[3-j],
248 pv->chromaV[3-j]);
251 i += 2;
252 break;
254 case 0x04: // 0x04 - SET_CONTR - Set Contrast
257 * SET_CONTR - directly provides the four contrast
258 * (alpha blend) values to associate with the four
259 * pixel values
261 uint8_t alpha[4];
263 alpha[3] = (pv->buf[i+0]>>4)&0x0f;
264 alpha[2] = (pv->buf[i+0])&0x0f;
265 alpha[1] = (pv->buf[i+1]>>4)&0x0f;
266 alpha[0] = (pv->buf[i+1])&0x0f;
269 int lastAlpha = pv->alpha[3] + pv->alpha[2] + pv->alpha[1] + pv->alpha[0];
270 int currAlpha = alpha[3] + alpha[2] + alpha[1] + alpha[0];
272 // fading-in, save the highest alpha value
273 if( currAlpha > lastAlpha )
275 pv->alpha[3] = alpha[3];
276 pv->alpha[2] = alpha[2];
277 pv->alpha[1] = alpha[1];
278 pv->alpha[0] = alpha[0];
281 // fading-out
282 if( currAlpha < lastAlpha && !pv->pts_stop )
284 pv->pts_stop = pv->pts + date * 900;
287 i += 2;
288 break;
290 case 0x05: // 0x05 - SET_DAREA - defines the display area
292 pv->x = (pv->buf[i+0]<<4) | ((pv->buf[i+1]>>4)&0x0f);
293 pv->width = (((pv->buf[i+1]&0x0f)<<8)| pv->buf[i+2]) - pv->x + 1;
294 pv->y = (pv->buf[i+3]<<4)| ((pv->buf[i+4]>>4)&0x0f);
295 pv->height = (((pv->buf[i+4]&0x0f)<<8)| pv->buf[i+5]) - pv->y + 1;
296 i += 6;
297 break;
299 case 0x06: // 0x06 - SET_DSPXA - defines the pixel data addresses
301 pv->offsets[0] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
302 pv->offsets[1] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
303 break;
310 if( i > next )
312 break;
314 i = next;
317 if( !pv->pts_stop )
319 /* Show it for 3 seconds */
320 pv->pts_stop = pv->pts_start + 3 * 90000;
324 /***********************************************************************
325 * CropSubtitle
326 ***********************************************************************
327 * Given a raw decoded subtitle, detects transparent borders and
328 * returns a cropped subtitle in a hb_buffer_t ready to be used by
329 * the renderer, or NULL if the subtitle was completely transparent
330 **********************************************************************/
331 static int LineIsTransparent( hb_work_object_t * w, uint8_t * p )
333 hb_work_private_t * pv = w->private_data;
334 int i;
335 for( i = 0; i < pv->width; i++ )
337 if( p[i] )
339 return 0;
342 return 1;
344 static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p )
346 hb_work_private_t * pv = w->private_data;
347 int i;
348 for( i = 0; i < pv->height; i++ )
350 if( p[i*pv->width] )
352 return 0;
355 return 1;
357 static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw )
359 hb_work_private_t * pv = w->private_data;
360 int i;
361 int crop[4] = { -1,-1,-1,-1 };
362 uint8_t * alpha;
363 int realwidth, realheight;
364 hb_buffer_t * buf;
365 uint8_t * lum_in, * lum_out, * alpha_in, * alpha_out;
366 uint8_t * u_in, * u_out, * v_in, * v_out;
368 alpha = raw + pv->width * pv->height;
370 /* Top */
371 for( i = 0; i < pv->height; i++ )
373 if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
375 crop[0] = i;
376 break;
380 if( crop[0] < 0 )
382 /* Empty subtitle */
383 return NULL;
386 /* Bottom */
387 for( i = pv->height - 1; i >= 0; i-- )
389 if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
391 crop[1] = i;
392 break;
396 /* Left */
397 for( i = 0; i < pv->width; i++ )
399 if( !ColumnIsTransparent( w, &alpha[i] ) )
401 crop[2] = i;
402 break;
406 /* Right */
407 for( i = pv->width - 1; i >= 0; i-- )
409 if( !ColumnIsTransparent( w, &alpha[i] ) )
411 crop[3] = i;
412 break;
416 realwidth = crop[3] - crop[2] + 1;
417 realheight = crop[1] - crop[0] + 1;
419 buf = hb_buffer_init( realwidth * realheight * 4 );
420 buf->start = pv->pts_start;
421 buf->stop = pv->pts_stop;
422 buf->x = pv->x + crop[2];
423 buf->y = pv->y + crop[0];
424 buf->width = realwidth;
425 buf->height = realheight;
427 lum_in = raw + crop[0] * pv->width + crop[2];
428 alpha_in = lum_in + pv->width * pv->height;
429 u_in = alpha_in + pv->width * pv->height;
430 v_in = u_in + pv->width * pv->height;
432 lum_out = buf->data;
433 alpha_out = lum_out + realwidth * realheight;
434 u_out = alpha_out + realwidth * realheight;
435 v_out = u_out + realwidth * realheight;
437 for( i = 0; i < realheight; i++ )
439 memcpy( lum_out, lum_in, realwidth );
440 memcpy( alpha_out, alpha_in, realwidth );
441 memcpy( u_out, u_in, realwidth );
442 memcpy( v_out, v_in, realwidth );
444 lum_in += pv->width;
445 alpha_in += pv->width;
446 u_in += pv->width;
447 v_in += pv->width;
449 lum_out += realwidth;
450 alpha_out += realwidth;
451 u_out += realwidth;
452 v_out += realwidth;
455 return buf;
458 static hb_buffer_t * Decode( hb_work_object_t * w )
460 hb_work_private_t * pv = w->private_data;
461 int code, line, col;
462 int offsets[2];
463 int * offset;
464 hb_buffer_t * buf;
465 uint8_t * buf_raw = NULL;
466 hb_job_t * job = pv->job;
468 /* Get infos about the subtitle */
469 ParseControls( w );
471 if( job->indepth_scan || ( job->subtitle_force && pv->pts_forced == 0 ) )
474 * Don't encode subtitles when doing a scan.
476 * When forcing subtitles, ignore all those that don't
477 * have the forced flag set.
479 return NULL;
482 /* Do the actual decoding now */
483 buf_raw = malloc( ( pv->width * pv->height ) * 4 );
485 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
486 ( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
487 (*offset)++
489 offsets[0] = pv->offsets[0] * 2;
490 offsets[1] = pv->offsets[1] * 2;
492 for( line = 0; line < pv->height; line++ )
494 /* Select even or odd field */
495 offset = ( line & 1 ) ? &offsets[1] : &offsets[0];
497 for( col = 0; col < pv->width; col += code >> 2 )
499 uint8_t * lum, * alpha, * chromaU, * chromaV;
501 code = 0;
502 GET_NEXT_NIBBLE;
503 if( code < 0x4 )
505 GET_NEXT_NIBBLE;
506 if( code < 0x10 )
508 GET_NEXT_NIBBLE;
509 if( code < 0x40 )
511 GET_NEXT_NIBBLE;
512 if( code < 0x100 )
514 /* End of line */
515 code |= ( pv->width - col ) << 2;
521 lum = buf_raw;
522 alpha = lum + pv->width * pv->height;
523 chromaU = alpha + pv->width * pv->height;
524 chromaV = chromaU + pv->width * pv->height;
526 memset( lum + line * pv->width + col,
527 pv->lum[code & 3], code >> 2 );
528 memset( alpha + line * pv->width + col,
529 pv->alpha[code & 3], code >> 2 );
530 memset( chromaU + line * pv->width + col,
531 pv->chromaU[code & 3], code >> 2 );
532 memset( chromaV + line * pv->width + col,
533 pv->chromaV[code & 3], code >> 2 );
536 /* Byte-align */
537 if( *offset & 1 )
539 (*offset)++;
543 /* Crop subtitle (remove transparent borders) */
544 buf = CropSubtitle( w, buf_raw );
546 free( buf_raw );
548 return buf;