OSDN Git Service

import 0.9.3
[handbrake-jp/handbrake-jp.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.fr/>.
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     int size_sub, size_rle;
55
56     if ( in->size <= 0 )
57     {
58         /* EOF on input stream - send it downstream & say that we're done */
59         *buf_out = in;
60         *buf_in = NULL;
61         return HB_WORK_DONE;
62     }
63
64     pv->stream_id = in->id;
65
66     size_sub = ( in->data[0] << 8 ) | in->data[1];
67     size_rle = ( in->data[2] << 8 ) | in->data[3];
68
69     if( !pv->size_sub )
70     {
71         /* We are looking for the start of a new subtitle */
72         if( size_sub && size_rle && size_sub > size_rle &&
73             in->size <= size_sub )
74         {
75             /* Looks all right so far */
76             pv->size_sub = size_sub;
77             pv->size_rle = size_rle;
78
79             memcpy( pv->buf, in->data, in->size );
80             pv->size_got = in->size;
81             pv->pts      = in->start;
82         }
83     }
84     else
85     {
86         /* We are waiting for the end of the current subtitle */
87         if( in->size <= pv->size_sub - pv->size_got )
88         {
89             memcpy( pv->buf + pv->size_got, in->data, in->size );
90             pv->size_got += in->size;
91             if( in->start >= 0 )
92             {
93                 pv->pts = in->start;
94             }
95         }
96     }
97
98     *buf_out = NULL;
99
100     if( pv->size_sub && pv->size_sub == pv->size_got )
101     {
102         /* We got a complete subtitle, decode it */
103         *buf_out = Decode( w );
104
105         if( buf_out && *buf_out )
106         {
107             (*buf_out)->sequence = in->sequence;
108         }
109
110         /* Wait for the next one */
111         pv->size_sub = 0;
112         pv->size_got = 0;
113         pv->size_rle = 0;
114         pv->pts      = -1;
115     }
116
117     return HB_WORK_OK;
118 }
119
120 void decsubClose( hb_work_object_t * w )
121 {
122     free( w->private_data );
123 }
124
125 hb_work_object_t hb_decsub =
126 {
127     WORK_DECSUB,
128     "Subtitle decoder",
129     decsubInit,
130     decsubWork,
131     decsubClose
132 };
133
134
135 /***********************************************************************
136  * ParseControls
137  ***********************************************************************
138  * Get the start and end dates (relative to the PTS from the PES
139  * header), the width and height of the subpicture and the colors and
140  * alphas used in it
141  **********************************************************************/
142 static void ParseControls( hb_work_object_t * w )
143 {
144     hb_work_private_t * pv = w->private_data;
145     hb_job_t * job = pv->job;
146     hb_title_t * title = job->title;
147     hb_subtitle_t * subtitle;
148
149     int i, n;
150     int command;
151     int date, next;
152
153     pv->pts_start = 0;
154     pv->pts_stop  = 0;
155     pv->pts_forced  = 0;
156
157     pv->alpha[3] = 0;
158     pv->alpha[2] = 0;
159     pv->alpha[1] = 0;
160     pv->alpha[0] = 0;
161
162     for( i = pv->size_rle; ; )
163     {
164         date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
165         next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
166
167         for( ;; )
168         {
169             command = pv->buf[i++];
170
171             /*
172              * There are eight commands available for
173              * Sub-Pictures. The first SP_DCSQ should contain, as a
174              * minimum, SET_COLOR, SET_CONTR, SET_DAREA, and
175              * SET_DSPXA
176              */
177
178             if( command == 0xFF ) // 0xFF - CMD_END - ends one SP_DCSQ
179             {
180                 break;
181             }
182
183             switch( command )
184             {
185                 case 0x00: // 0x00 - FSTA_DSP - Forced Start Display, no arguments
186                     pv->pts_start = pv->pts + date * 900;
187                     pv->pts_forced = 1;
188
189                     /*
190                      * If we are doing a subtitle scan then note down
191                      */
192                     if( job->indepth_scan )
193                     {
194                         for( n=0; n < hb_list_count(title->list_subtitle); n++ )
195                         {
196                             subtitle = hb_list_item( title->list_subtitle, n);
197                             if( pv->stream_id == subtitle->id ) {
198                                 /*
199                                  * A hit, count it.
200                                  */
201                                 subtitle->forced_hits++;
202                             }
203                         }
204                     }
205                     break;
206
207                 case 0x01: // 0x01 - STA_DSP - Start Display, no arguments
208                     pv->pts_start = pv->pts + date * 900;
209                     pv->pts_forced  = 0;
210                     break;
211
212                 case 0x02: // 0x02 - STP_DSP - Stop Display, no arguments
213                     if(!pv->pts_stop)
214                         pv->pts_stop = pv->pts + date * 900;
215                     break;
216
217                 case 0x03: // 0x03 - SET_COLOR - Set Colour indices
218                 {
219                     /*
220                      * SET_COLOR - provides four indices into the CLUT
221                      * for the current PGC to associate with the four
222                      * pixel values
223                      */
224                     int colors[4];
225                     int j;
226
227                     colors[0] = (pv->buf[i+0]>>4)&0x0f;
228                     colors[1] = (pv->buf[i+0])&0x0f;
229                     colors[2] = (pv->buf[i+1]>>4)&0x0f;
230                     colors[3] = (pv->buf[i+1])&0x0f;
231
232                     for( j = 0; j < 4; j++ )
233                     {
234                         /*
235                          * Not sure what is happening here, in theory
236                          * the palette is in YCbCr. And we want YUV.
237                          *
238                          * However it looks more like YCrCb (according
239                          * to pgcedit). And the scalers for YCrCb don't
240                          * work, but I get the right colours by doing
241                          * no conversion.
242                          */
243                         uint32_t color = title->palette[colors[j]];
244                         uint8_t Cr, Cb, y;
245                         y = (color>>16) & 0xff;
246                         Cr = (color>>8) & 0xff;
247                         Cb = (color) & 0xff;
248                         pv->lum[3-j] = y;
249                         pv->chromaU[3-j] = Cb;
250                         pv->chromaV[3-j] = Cr;
251                         /* hb_log("color[%d] y = %d, u = %d, v = %d",
252                                3-j,
253                                pv->lum[3-j],
254                                pv->chromaU[3-j],
255                                pv->chromaV[3-j]);
256                         */
257                     }
258                     i += 2;
259                     break;
260                 }
261                 case 0x04: // 0x04 - SET_CONTR - Set Contrast
262                 {
263                     /*
264                      * SET_CONTR - directly provides the four contrast
265                      * (alpha blend) values to associate with the four
266                      * pixel values
267                      */
268                     uint8_t    alpha[4];
269
270                     alpha[3] = (pv->buf[i+0]>>4)&0x0f;
271                     alpha[2] = (pv->buf[i+0])&0x0f;
272                     alpha[1] = (pv->buf[i+1]>>4)&0x0f;
273                     alpha[0] = (pv->buf[i+1])&0x0f;
274
275
276                     int lastAlpha = pv->alpha[3] + pv->alpha[2] + pv->alpha[1] + pv->alpha[0];
277                     int currAlpha = alpha[3] + alpha[2] + alpha[1] + alpha[0];
278
279                     // fading-in, save the highest alpha value
280                     if( currAlpha > lastAlpha )
281                     {
282                         pv->alpha[3] = alpha[3];
283                         pv->alpha[2] = alpha[2];
284                         pv->alpha[1] = alpha[1];
285                         pv->alpha[0] = alpha[0];
286                     }
287
288                     // fading-out
289                     if( currAlpha < lastAlpha && !pv->pts_stop )
290                     {
291                         pv->pts_stop = pv->pts + date * 900;
292                     }
293
294                     i += 2;
295                     break;
296                 }
297                 case 0x05: // 0x05 - SET_DAREA - defines the display area
298                 {
299                     pv->x     = (pv->buf[i+0]<<4) | ((pv->buf[i+1]>>4)&0x0f);
300                     pv->width = (((pv->buf[i+1]&0x0f)<<8)| pv->buf[i+2]) - pv->x + 1;
301                     pv->y     = (pv->buf[i+3]<<4)| ((pv->buf[i+4]>>4)&0x0f);
302                     pv->height = (((pv->buf[i+4]&0x0f)<<8)| pv->buf[i+5]) - pv->y + 1;
303                     i += 6;
304                     break;
305                 }
306                 case 0x06: // 0x06 - SET_DSPXA - defines the pixel data addresses
307                 {
308                     pv->offsets[0] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
309                     pv->offsets[1] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
310                     break;
311                 }
312             }
313         }
314
315
316
317         if( i > next )
318         {
319             break;
320         }
321         i = next;
322     }
323
324     if( !pv->pts_stop )
325     {
326         /* Show it for 3 seconds */
327         pv->pts_stop = pv->pts_start + 3 * 90000;
328     }
329 }
330
331 /***********************************************************************
332  * CropSubtitle
333  ***********************************************************************
334  * Given a raw decoded subtitle, detects transparent borders and
335  * returns a cropped subtitle in a hb_buffer_t ready to be used by
336  * the renderer, or NULL if the subtitle was completely transparent
337  **********************************************************************/
338 static int LineIsTransparent( hb_work_object_t * w, uint8_t * p )
339 {
340     hb_work_private_t * pv = w->private_data;
341     int i;
342     for( i = 0; i < pv->width; i++ )
343     {
344         if( p[i] )
345         {
346             return 0;
347         }
348     }
349     return 1;
350 }
351 static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p )
352 {
353     hb_work_private_t * pv = w->private_data;
354     int i;
355     for( i = 0; i < pv->height; i++ )
356     {
357         if( p[i*pv->width] )
358         {
359             return 0;
360         }
361     }
362     return 1;
363 }
364 static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw )
365 {
366     hb_work_private_t * pv = w->private_data;
367     int i;
368     int crop[4] = { -1,-1,-1,-1 };
369     uint8_t * alpha;
370     int realwidth, realheight;
371     hb_buffer_t * buf;
372     uint8_t * lum_in, * lum_out, * alpha_in, * alpha_out;
373     uint8_t * u_in, * u_out, * v_in, * v_out;
374
375     alpha = raw + pv->width * pv->height;
376
377     /* Top */
378     for( i = 0; i < pv->height; i++ )
379     {
380         if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
381         {
382             crop[0] = i;
383             break;
384         }
385     }
386
387     if( crop[0] < 0 )
388     {
389         /* Empty subtitle */
390         return NULL;
391     }
392
393     /* Bottom */
394     for( i = pv->height - 1; i >= 0; i-- )
395     {
396         if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
397         {
398             crop[1] = i;
399             break;
400         }
401     }
402
403     /* Left */
404     for( i = 0; i < pv->width; i++ )
405     {
406         if( !ColumnIsTransparent( w, &alpha[i] ) )
407         {
408             crop[2] = i;
409             break;
410         }
411     }
412
413     /* Right */
414     for( i = pv->width - 1; i >= 0; i-- )
415     {
416         if( !ColumnIsTransparent( w, &alpha[i] ) )
417         {
418             crop[3] = i;
419             break;
420         }
421     }
422
423     realwidth  = crop[3] - crop[2] + 1;
424     realheight = crop[1] - crop[0] + 1;
425
426     buf         = hb_buffer_init( realwidth * realheight * 4 );
427     buf->start  = pv->pts_start;
428     buf->stop   = pv->pts_stop;
429     buf->x      = pv->x + crop[2];
430     buf->y      = pv->y + crop[0];
431     buf->width  = realwidth;
432     buf->height = realheight;
433
434     lum_in    = raw + crop[0] * pv->width + crop[2];
435     alpha_in  = lum_in + pv->width * pv->height;
436     u_in      = alpha_in + pv->width * pv->height;
437     v_in      = u_in + pv->width * pv->height;
438
439     lum_out   = buf->data;
440     alpha_out = lum_out + realwidth * realheight;
441     u_out     = alpha_out + realwidth * realheight;
442     v_out     = u_out + realwidth * realheight;
443
444     for( i = 0; i < realheight; i++ )
445     {
446         memcpy( lum_out, lum_in, realwidth );
447         memcpy( alpha_out, alpha_in, realwidth );
448         memcpy( u_out, u_in, realwidth );
449         memcpy( v_out, v_in, realwidth );
450
451         lum_in    += pv->width;
452         alpha_in  += pv->width;
453         u_in      += pv->width;
454         v_in      += pv->width;
455
456         lum_out   += realwidth;
457         alpha_out += realwidth;
458         u_out     += realwidth;
459         v_out     += realwidth;
460     }
461
462     return buf;
463 }
464
465 static hb_buffer_t * Decode( hb_work_object_t * w )
466 {
467     hb_work_private_t * pv = w->private_data;
468     int code, line, col;
469     int offsets[2];
470     int * offset;
471     hb_buffer_t * buf;
472     uint8_t * buf_raw = NULL;
473     hb_job_t * job = pv->job;
474
475     /* Get infos about the subtitle */
476     ParseControls( w );
477
478     if( job->indepth_scan || ( job->subtitle_force && pv->pts_forced == 0 ) )
479     {
480         /*
481          * Don't encode subtitles when doing a scan.
482          *
483          * When forcing subtitles, ignore all those that don't
484          * have the forced flag set.
485          */
486         return NULL;
487     }
488
489     /* Do the actual decoding now */
490     buf_raw = malloc( ( pv->width * pv->height ) * 4 );
491
492 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
493 ( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
494 (*offset)++
495
496     offsets[0] = pv->offsets[0] * 2;
497     offsets[1] = pv->offsets[1] * 2;
498
499     for( line = 0; line < pv->height; line++ )
500     {
501         /* Select even or odd field */
502         offset = ( line & 1 ) ? &offsets[1] : &offsets[0];
503
504         for( col = 0; col < pv->width; col += code >> 2 )
505         {
506             uint8_t * lum, * alpha,  * chromaU, * chromaV;
507
508             code = 0;
509             GET_NEXT_NIBBLE;
510             if( code < 0x4 )
511             {
512                 GET_NEXT_NIBBLE;
513                 if( code < 0x10 )
514                 {
515                     GET_NEXT_NIBBLE;
516                     if( code < 0x40 )
517                     {
518                         GET_NEXT_NIBBLE;
519                         if( code < 0x100 )
520                         {
521                             /* End of line */
522                             code |= ( pv->width - col ) << 2;
523                         }
524                     }
525                 }
526             }
527
528             lum   = buf_raw;
529             alpha = lum + pv->width * pv->height;
530             chromaU = alpha + pv->width * pv->height;
531             chromaV = chromaU + pv->width * pv->height;
532
533             memset( lum + line * pv->width + col,
534                     pv->lum[code & 3], code >> 2 );
535             memset( alpha + line * pv->width + col,
536                     pv->alpha[code & 3], code >> 2 );
537             memset( chromaU + line * pv->width + col,
538                     pv->chromaU[code & 3], code >> 2 );
539             memset( chromaV + line * pv->width + col,
540                     pv->chromaV[code & 3], code >> 2 );
541         }
542
543         /* Byte-align */
544         if( *offset & 1 )
545         {
546             (*offset)++;
547         }
548     }
549
550     /* Crop subtitle (remove transparent borders) */
551     buf = CropSubtitle( w, buf_raw );
552
553     free( buf_raw );
554
555     return buf;
556 }