OSDN Git Service

Added "--subtitle-force" option to the CLI, and added changes to decsub to
[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
26     int        offsets[2];
27     uint8_t    lum[4];
28     uint8_t    chromaU[4];
29     uint8_t    chromaV[4];
30     uint8_t    alpha[4];
31 };
32
33 static hb_buffer_t * Decode( hb_work_object_t * );
34
35 int decsubInit( hb_work_object_t * w, hb_job_t * job )
36 {
37     hb_work_private_t * pv;
38     
39     pv              = calloc( 1, sizeof( hb_work_private_t ) );
40     w->private_data = pv;
41
42     pv->job = job;
43     pv->pts = -1;
44
45     return 0;
46 }
47
48 int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
49                 hb_buffer_t ** buf_out )
50 {
51     hb_work_private_t * pv = w->private_data;
52     hb_buffer_t * in = *buf_in;
53
54     int size_sub, size_rle;
55
56     size_sub = ( in->data[0] << 8 ) | in->data[1];
57     size_rle = ( in->data[2] << 8 ) | in->data[3];
58
59     if( !pv->size_sub )
60     {
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 )
64         {
65             /* Looks all right so far */
66             pv->size_sub = size_sub;
67             pv->size_rle = size_rle;
68
69             memcpy( pv->buf, in->data, in->size );
70             pv->size_got = in->size;
71             pv->pts      = in->start;
72         }
73     }
74     else
75     {
76         /* We are waiting for the end of the current subtitle */
77         if( in->size <= pv->size_sub - pv->size_got )
78         {
79             memcpy( pv->buf + pv->size_got, in->data, in->size );
80             pv->size_got += in->size;
81             if( in->start >= 0 )
82             {
83                 pv->pts = in->start;
84             }
85         }
86     }
87
88     *buf_out = NULL;
89
90     if( pv->size_sub && pv->size_sub == pv->size_got )
91     {
92         /* We got a complete subtitle, decode it */
93         *buf_out = Decode( w );
94
95         /* Wait for the next one */
96         pv->size_sub = 0;
97         pv->size_got = 0;
98         pv->size_rle = 0;
99         pv->pts      = -1;
100     }
101
102     return HB_WORK_OK;
103 }
104
105 void decsubClose( hb_work_object_t * w )
106 {
107     free( w->private_data );
108 }
109
110 hb_work_object_t hb_decsub =
111 {
112     WORK_DECSUB,
113     "Subtitle decoder",
114     decsubInit,
115     decsubWork,
116     decsubClose
117 };
118
119
120 /***********************************************************************
121  * ParseControls
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
125  * alphas used in it
126  **********************************************************************/
127 static void ParseControls( hb_work_object_t * w )
128 {
129     hb_work_private_t * pv = w->private_data;
130     hb_job_t * job = pv->job;
131     hb_title_t * title = job->title;
132
133     int i;
134     int command;
135     int date, next;
136
137     pv->pts_start = 0;
138     pv->pts_stop  = 0;
139     pv->pts_forced  = 0;
140
141     for( i = pv->size_rle; ; )
142     {
143         date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
144         next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
145
146         for( ;; )
147         {
148             command = pv->buf[i++];
149
150             /*
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
154              * SET_DSPXA
155              */
156
157             if( command == 0xFF ) // 0xFF - CMD_END - ends one SP_DCSQ
158             {
159                 break;
160             }
161
162             switch( command )
163             {
164                 case 0x00: // 0x00 - FSTA_DSP - Forced Start Display, no arguments
165                     pv->pts_start = pv->pts + date * 900;
166                     pv->pts_forced = 1;
167                     break;
168
169                 case 0x01: // 0x01 - STA_DSP - Start Display, no arguments
170                     pv->pts_start = pv->pts + date * 900;
171                     pv->pts_forced  = 0;
172                     break;
173
174                 case 0x02: // 0x02 - STP_DSP - Stop Display, no arguments
175                     pv->pts_stop = pv->pts + date * 900;
176                     break;
177
178                 case 0x03: // 0x03 - SET_COLOR - Set Colour indices
179                 {              
180                     /* 
181                      * SET_COLOR - provides four indices into the CLUT
182                      * for the current PGC to associate with the four
183                      * pixel values
184                      */
185                     int colors[4];
186                     int j;
187
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;
192
193                     for( j = 0; j < 4; j++ )
194                     {
195                         /*
196                          * Not sure what is happening here, in theory
197                          * the palette is in YCbCr. And we want YUV.
198                          *
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
202                          * no conversion.
203                          */
204                         uint32_t color = title->palette[colors[j]];
205                         uint8_t Cr, Cb, y;
206                         y = (color>>16) & 0xff;
207                         Cr = (color>>8) & 0xff;
208                         Cb = (color) & 0xff;
209                         pv->lum[3-j] = y;
210                         pv->chromaU[3-j] = Cb;
211                         pv->chromaV[3-j] = Cr;
212                         /* hb_log("color[%d] y = %d, u = %d, v = %d",
213                                3-j,
214                                pv->lum[3-j],
215                                pv->chromaU[3-j],
216                                pv->chromaV[3-j]); 
217                         */
218                     }
219                     i += 2;
220                     break;
221                 }
222                 case 0x04: // 0x04 - SET_CONTR - Set Contrast
223                 {
224                     /* 
225                      * SET_CONTR - directly provides the four contrast
226                      * (alpha blend) values to associate with the four
227                      * pixel values
228                      */
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;
233                     i += 2;
234                     break;
235                 }
236                 case 0x05: // 0x05 - SET_DAREA - defines the display area
237                 {
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;
242                     i += 6;
243                     break;
244                 }
245                 case 0x06: // 0x06 - SET_DSPXA - defines the pixel data addresses
246                 {
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;
249                     break;
250                 }
251             }
252         }
253
254         if( i > next )
255         {
256             break;
257         }
258         i = next;
259     }
260
261     if( !pv->pts_stop )
262     {
263         /* Show it for 3 seconds */
264         pv->pts_stop = pv->pts_start + 3 * 90000;
265     }
266 }
267
268 /***********************************************************************
269  * CropSubtitle
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 )
276 {
277     hb_work_private_t * pv = w->private_data;
278     int i;
279     for( i = 0; i < pv->width; i++ )
280     {
281         if( p[i] )
282         {
283             return 0;
284         }
285     }
286     return 1;
287 }
288 static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p )
289 {
290     hb_work_private_t * pv = w->private_data;
291     int i;
292     for( i = 0; i < pv->height; i++ )
293     {
294         if( p[i*pv->width] )
295         {
296             return 0;
297         }
298     }
299     return 1;
300 }
301 static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw )
302 {
303     hb_work_private_t * pv = w->private_data;
304     int i;
305     int crop[4] = { -1,-1,-1,-1 };
306     uint8_t * alpha;
307     int realwidth, realheight;
308     hb_buffer_t * buf;
309     uint8_t * lum_in, * lum_out, * alpha_in, * alpha_out;
310     uint8_t * u_in, * u_out, * v_in, * v_out;
311
312     alpha = raw + pv->width * pv->height;
313
314     /* Top */
315     for( i = 0; i < pv->height; i++ )
316     {
317         if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
318         {
319             crop[0] = i;
320             break;
321         }
322     }
323
324     if( crop[0] < 0 )
325     {
326         /* Empty subtitle */
327         return NULL;
328     }
329
330     /* Bottom */
331     for( i = pv->height - 1; i >= 0; i-- )
332     {
333         if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
334         {
335             crop[1] = i;
336             break;
337         }
338     }
339
340     /* Left */
341     for( i = 0; i < pv->width; i++ )
342     {
343         if( !ColumnIsTransparent( w, &alpha[i] ) )
344         {
345             crop[2] = i;
346             break;
347         }
348     }
349
350     /* Right */
351     for( i = pv->width - 1; i >= 0; i-- )
352     {
353         if( !ColumnIsTransparent( w, &alpha[i] ) )
354         {
355             crop[3] = i;
356             break;
357         }
358     }
359
360     realwidth  = crop[3] - crop[2] + 1;
361     realheight = crop[1] - crop[0] + 1;
362
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;
370
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;
375
376     lum_out   = buf->data;
377     alpha_out = lum_out + realwidth * realheight;
378     u_out     = alpha_out + realwidth * realheight;
379     v_out     = u_out + realwidth * realheight;
380
381     for( i = 0; i < realheight; i++ )
382     {
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 );
387
388         lum_in    += pv->width;
389         alpha_in  += pv->width;
390         u_in      += pv->width;
391         v_in      += pv->width;
392
393         lum_out   += realwidth;
394         alpha_out += realwidth;
395         u_out     += realwidth;
396         v_out     += realwidth;
397     }
398
399     return buf;
400 }
401
402 static hb_buffer_t * Decode( hb_work_object_t * w )
403 {
404     hb_work_private_t * pv = w->private_data;
405     int code, line, col;
406     int offsets[2];
407     int * offset;
408     hb_buffer_t * buf;
409     uint8_t * buf_raw = NULL;
410     hb_job_t * job = pv->job;
411
412     /* Get infos about the subtitle */
413     ParseControls( w );
414
415     if( job->subtitle_force && pv->pts_forced == 0 )
416     {
417         /*
418          * When forcing subtitles, ignore all those that don't
419          * have the forced flag set.
420          */
421         return NULL;
422     } 
423
424     /* Do the actual decoding now */
425     buf_raw = malloc( pv->width * pv->height * 4 );
426
427 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
428 ( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
429 (*offset)++
430     
431     offsets[0] = pv->offsets[0] * 2;
432     offsets[1] = pv->offsets[1] * 2;
433
434     for( line = 0; line < pv->height; line++ )
435     {
436         /* Select even or odd field */
437         offset = ( line & 1 ) ? &offsets[1] : &offsets[0];
438
439         for( col = 0; col < pv->width; col += code >> 2 )
440         {
441             uint8_t * lum, * alpha,  * chromaU, * chromaV;
442
443             code = 0;
444             GET_NEXT_NIBBLE;
445             if( code < 0x4 )
446             {
447                 GET_NEXT_NIBBLE;
448                 if( code < 0x10 )
449                 {
450                     GET_NEXT_NIBBLE;
451                     if( code < 0x40 )
452                     {
453                         GET_NEXT_NIBBLE;
454                         if( code < 0x100 )
455                         {
456                             /* End of line */
457                             code |= ( pv->width - col ) << 2;
458                         }
459                     }
460                 }
461             }
462
463             lum   = buf_raw;
464             alpha = lum + pv->width * pv->height;
465             chromaU = alpha + pv->width * pv->height;
466             chromaV = chromaU + pv->width * pv->height;
467
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 );
476         }
477
478         /* Byte-align */
479         if( *offset & 1 )
480         {
481             (*offset)++;
482         }
483     }
484
485     /* Crop subtitle (remove transparent borders) */
486     buf = CropSubtitle( w, buf_raw );
487
488     free( buf_raw );
489
490     return buf;
491 }