OSDN Git Service

Don't drop subtitles when crossing PTS discontinuities by using buffer sequence numbe...
[handbrake-jp/handbrake-jp-git.git] / libhb / decsub.c
1 /* $Id: decsub.c,v 1.12 2005/04/14 17:37:54 titer Exp $
2
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. */
6
7 #include "hb.h"
8
9 struct hb_work_private_s
10 {
11     hb_job_t * job;
12
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;
26
27     int        offsets[2];
28     uint8_t    lum[4];
29     uint8_t    chromaU[4];
30     uint8_t    chromaV[4];
31     uint8_t    alpha[4];
32 };
33
34 static hb_buffer_t * Decode( hb_work_object_t * );
35
36 int decsubInit( hb_work_object_t * w, hb_job_t * job )
37 {
38     hb_work_private_t * pv;
39     
40     pv              = calloc( 1, sizeof( hb_work_private_t ) );
41     w->private_data = pv;
42
43     pv->job = job;
44     pv->pts = -1;
45
46     return 0;
47 }
48
49 int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
50                 hb_buffer_t ** buf_out )
51 {
52     hb_work_private_t * pv = w->private_data;
53     hb_buffer_t * in = *buf_in;
54
55     int size_sub, size_rle;
56
57     pv->stream_id = in->id;
58
59     size_sub = ( in->data[0] << 8 ) | in->data[1];
60     size_rle = ( in->data[2] << 8 ) | in->data[3];
61
62     if( !pv->size_sub )
63     {
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 )
67         {
68             /* Looks all right so far */
69             pv->size_sub = size_sub;
70             pv->size_rle = size_rle;
71
72             memcpy( pv->buf, in->data, in->size );
73             pv->size_got = in->size;
74             pv->pts      = in->start;
75         }
76     }
77     else
78     {
79         /* We are waiting for the end of the current subtitle */
80         if( in->size <= pv->size_sub - pv->size_got )
81         {
82             memcpy( pv->buf + pv->size_got, in->data, in->size );
83             pv->size_got += in->size;
84             if( in->start >= 0 )
85             {
86                 pv->pts = in->start;
87             }
88         }
89     }
90
91     *buf_out = NULL;
92
93     if( pv->size_sub && pv->size_sub == pv->size_got )
94     {
95         /* We got a complete subtitle, decode it */
96         *buf_out = Decode( w );
97
98         if( buf_out && *buf_out )
99         {
100             (*buf_out)->sequence = in->sequence;
101         }
102
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;
108     }
109
110     return HB_WORK_OK;
111 }
112
113 void decsubClose( hb_work_object_t * w )
114 {
115     free( w->private_data );
116 }
117
118 hb_work_object_t hb_decsub =
119 {
120     WORK_DECSUB,
121     "Subtitle decoder",
122     decsubInit,
123     decsubWork,
124     decsubClose
125 };
126
127
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 )
136 {
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;
141
142     int i, n;
143     int command;
144     int date, next;
145
146     pv->pts_start = 0;
147     pv->pts_stop  = 0;
148     pv->pts_forced  = 0;
149         
150     pv->alpha[3] = 0;
151     pv->alpha[2] = 0;
152     pv->alpha[1] = 0;
153     pv->alpha[0] = 0;
154     
155     for( i = pv->size_rle; ; )
156     {
157         date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
158         next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
159
160         for( ;; )
161         {
162             command = pv->buf[i++];
163
164             /*
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
169              */
170
171             if( command == 0xFF ) // 0xFF - CMD_END - ends one SP_DCSQ
172             {
173                 break;
174             }
175
176             switch( command )
177             {
178                 case 0x00: // 0x00 - FSTA_DSP - Forced Start Display, no arguments
179                     pv->pts_start = pv->pts + date * 900;
180                     pv->pts_forced = 1;
181
182                     /*
183                      * If we are doing a subtitle scan then note down
184                      */
185                     if( job->indepth_scan )
186                     {
187                         for( n=0; n < hb_list_count(title->list_subtitle); n++ ) 
188                         {
189                             subtitle = hb_list_item( title->list_subtitle, n);
190                             if( pv->stream_id == subtitle->id ) {
191                                 /*
192                                  * A hit, count it.
193                                  */
194                                 subtitle->forced_hits++;
195                             }
196                         }
197                     }
198                     break;
199
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;
204
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;
209
210                 case 0x03: // 0x03 - SET_COLOR - Set Colour indices
211                 {              
212                     /* 
213                      * SET_COLOR - provides four indices into the CLUT
214                      * for the current PGC to associate with the four
215                      * pixel values
216                      */
217                     int colors[4];
218                     int j;
219
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;
224
225                     for( j = 0; j < 4; j++ )
226                     {
227                         /*
228                          * Not sure what is happening here, in theory
229                          * the palette is in YCbCr. And we want YUV.
230                          *
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.
235                          */
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]); 
249                         */
250                     } 
251                     i += 2;
252                     break;
253                 }
254                 case 0x04: // 0x04 - SET_CONTR - Set Contrast
255                 {
256                     /* 
257                      * SET_CONTR - directly provides the four contrast
258                      * (alpha blend) values to associate with the four
259                      * pixel values
260                      */
261                     uint8_t    alpha[4];
262                     
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;
267                     
268                     
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];
271                     
272                     // fading-in, save the highest alpha value
273                     if( currAlpha > lastAlpha ) 
274                     {
275                         pv->alpha[3] = alpha[3];
276                         pv->alpha[2] = alpha[2];
277                         pv->alpha[1] = alpha[1];
278                         pv->alpha[0] = alpha[0];
279                     }
280                     
281                     // fading-out
282                     if( currAlpha < lastAlpha && !pv->pts_stop ) 
283                     {
284                         pv->pts_stop = pv->pts + date * 900;
285                     }
286                     
287                     i += 2;
288                     break;
289                 }
290                 case 0x05: // 0x05 - SET_DAREA - defines the display area
291                 {
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;
298                 }
299                 case 0x06: // 0x06 - SET_DSPXA - defines the pixel data addresses
300                 {
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;
304                 }
305             }
306         }
307                 
308
309
310         if( i > next )
311         {
312             break;
313         }
314         i = next;
315     }
316
317     if( !pv->pts_stop )
318     {
319         /* Show it for 3 seconds */
320         pv->pts_stop = pv->pts_start + 3 * 90000;
321     }
322 }
323
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 )
332 {
333     hb_work_private_t * pv = w->private_data;
334     int i;
335     for( i = 0; i < pv->width; i++ )
336     {
337         if( p[i] )
338         {
339             return 0;
340         }
341     }
342     return 1;
343 }
344 static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p )
345 {
346     hb_work_private_t * pv = w->private_data;
347     int i;
348     for( i = 0; i < pv->height; i++ )
349     {
350         if( p[i*pv->width] )
351         {
352             return 0;
353         }
354     }
355     return 1;
356 }
357 static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw )
358 {
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;
367
368     alpha = raw + pv->width * pv->height;
369
370     /* Top */
371     for( i = 0; i < pv->height; i++ )
372     {
373         if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
374         {
375             crop[0] = i;
376             break;
377         }
378     }
379
380     if( crop[0] < 0 )
381     {
382         /* Empty subtitle */
383         return NULL;
384     }
385
386     /* Bottom */
387     for( i = pv->height - 1; i >= 0; i-- )
388     {
389         if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
390         {
391             crop[1] = i;
392             break;
393         }
394     }
395
396     /* Left */
397     for( i = 0; i < pv->width; i++ )
398     {
399         if( !ColumnIsTransparent( w, &alpha[i] ) )
400         {
401             crop[2] = i;
402             break;
403         }
404     }
405
406     /* Right */
407     for( i = pv->width - 1; i >= 0; i-- )
408     {
409         if( !ColumnIsTransparent( w, &alpha[i] ) )
410         {
411             crop[3] = i;
412             break;
413         }
414     }
415
416     realwidth  = crop[3] - crop[2] + 1;
417     realheight = crop[1] - crop[0] + 1;
418
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;
426
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;
431
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;
436
437     for( i = 0; i < realheight; i++ )
438     {
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 );
443
444         lum_in    += pv->width;
445         alpha_in  += pv->width;
446         u_in      += pv->width;
447         v_in      += pv->width;
448
449         lum_out   += realwidth;
450         alpha_out += realwidth;
451         u_out     += realwidth;
452         v_out     += realwidth;
453     }
454
455     return buf;
456 }
457
458 static hb_buffer_t * Decode( hb_work_object_t * w )
459 {
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;
467
468     /* Get infos about the subtitle */
469     ParseControls( w );
470
471     if( job->indepth_scan || ( job->subtitle_force && pv->pts_forced == 0 ) )
472     {
473         /*
474          * Don't encode subtitles when doing a scan.
475          *
476          * When forcing subtitles, ignore all those that don't
477          * have the forced flag set.
478          */
479         return NULL;
480     }
481
482     /* Do the actual decoding now */
483     buf_raw = malloc( ( pv->width * pv->height ) * 4 );
484
485 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
486 ( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
487 (*offset)++
488     
489     offsets[0] = pv->offsets[0] * 2;
490     offsets[1] = pv->offsets[1] * 2;
491
492     for( line = 0; line < pv->height; line++ )
493     {
494         /* Select even or odd field */
495         offset = ( line & 1 ) ? &offsets[1] : &offsets[0];
496
497         for( col = 0; col < pv->width; col += code >> 2 )
498         {
499             uint8_t * lum, * alpha,  * chromaU, * chromaV;
500
501             code = 0;
502             GET_NEXT_NIBBLE;
503             if( code < 0x4 )
504             {
505                 GET_NEXT_NIBBLE;
506                 if( code < 0x10 )
507                 {
508                     GET_NEXT_NIBBLE;
509                     if( code < 0x40 )
510                     {
511                         GET_NEXT_NIBBLE;
512                         if( code < 0x100 )
513                         {
514                             /* End of line */
515                             code |= ( pv->width - col ) << 2;
516                         }
517                     }
518                 }
519             }
520
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;
525
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 );
534         }
535
536         /* Byte-align */
537         if( *offset & 1 )
538         {
539             (*offset)++;
540         }
541     }
542
543     /* Crop subtitle (remove transparent borders) */
544     buf = CropSubtitle( w, buf_raw );
545
546     free( buf_raw );
547
548     return buf;
549 }