OSDN Git Service

Implements libswscale in HandBrake, giving it Lanczos scaling! This major enhancement...
[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        x;
21     int        y;
22     int        width;
23     int        height;
24
25     int        offsets[2];
26     uint8_t    lum[4];
27     uint8_t    alpha[4];
28 };
29
30 static hb_buffer_t * Decode( hb_work_object_t * );
31
32 int decsubInit( hb_work_object_t * w, hb_job_t * job )
33 {
34     hb_work_private_t * pv;
35     
36     pv              = calloc( 1, sizeof( hb_work_private_t ) );
37     w->private_data = pv;
38
39     pv->job = job;
40     pv->pts = -1;
41
42     return 0;
43 }
44
45 int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
46                 hb_buffer_t ** buf_out )
47 {
48     hb_work_private_t * pv = w->private_data;
49     hb_buffer_t * in = *buf_in;
50
51     int size_sub, size_rle;
52
53     size_sub = ( in->data[0] << 8 ) | in->data[1];
54     size_rle = ( in->data[2] << 8 ) | in->data[3];
55
56     if( !pv->size_sub )
57     {
58         /* We are looking for the start of a new subtitle */
59         if( size_sub && size_rle && size_sub > size_rle &&
60             in->size <= size_sub )
61         {
62             /* Looks all right so far */
63             pv->size_sub = size_sub;
64             pv->size_rle = size_rle;
65
66             memcpy( pv->buf, in->data, in->size );
67             pv->size_got = in->size;
68             pv->pts      = in->start;
69         }
70     }
71     else
72     {
73         /* We are waiting for the end of the current subtitle */
74         if( in->size <= pv->size_sub - pv->size_got )
75         {
76             memcpy( pv->buf + pv->size_got, in->data, in->size );
77             pv->size_got += in->size;
78             if( in->start >= 0 )
79             {
80                 pv->pts = in->start;
81             }
82         }
83     }
84
85     *buf_out = NULL;
86
87     if( pv->size_sub && pv->size_sub == pv->size_got )
88     {
89         /* We got a complete subtitle, decode it */
90         *buf_out = Decode( w );
91
92         /* Wait for the next one */
93         pv->size_sub = 0;
94         pv->size_got = 0;
95         pv->size_rle = 0;
96         pv->pts      = -1;
97     }
98
99     return HB_WORK_OK;
100 }
101
102 void decsubClose( hb_work_object_t * w )
103 {
104     free( w->private_data );
105 }
106
107 hb_work_object_t hb_decsub =
108 {
109     WORK_DECSUB,
110     "Subtitle decoder",
111     decsubInit,
112     decsubWork,
113     decsubClose
114 };
115
116
117 /***********************************************************************
118  * ParseControls
119  ***********************************************************************
120  * Get the start and end dates (relative to the PTS from the PES
121  * header), the width and height of the subpicture and the colors and
122  * alphas used in it
123  **********************************************************************/
124 static void ParseControls( hb_work_object_t * w )
125 {
126     hb_work_private_t * pv = w->private_data;
127     hb_job_t * job = pv->job;
128     hb_title_t * title = job->title;
129
130     int i;
131     int command;
132     int date, next;
133
134     pv->pts_start = 0;
135     pv->pts_stop  = 0;
136
137     for( i = pv->size_rle; ; )
138     {
139         date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
140         next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
141
142         for( ;; )
143         {
144             command = pv->buf[i++];
145
146             if( command == 0xFF )
147             {
148                 break;
149             }
150
151             switch( command )
152             {
153                 case 0x00:
154                     break;
155
156                 case 0x01:
157                     pv->pts_start = pv->pts + date * 900;
158                     break;
159
160                 case 0x02:
161                     pv->pts_stop = pv->pts + date * 900;
162                     break;
163
164                 case 0x03:
165                 {
166                     int colors[4];
167                     int j;
168
169                     colors[0] = (pv->buf[i+0]>>4)&0x0f;
170                     colors[1] = (pv->buf[i+0])&0x0f;
171                     colors[2] = (pv->buf[i+1]>>4)&0x0f;
172                     colors[3] = (pv->buf[i+1])&0x0f;
173
174                     for( j = 0; j < 4; j++ )
175                     {
176                         uint32_t color = title->palette[colors[j]];
177                         pv->lum[3-j] = (color>>16) & 0xff;
178                     }
179                     i += 2;
180                     break;
181                 }
182                 case 0x04:
183                 {
184                     pv->alpha[3] = (pv->buf[i+0]>>4)&0x0f;
185                     pv->alpha[2] = (pv->buf[i+0])&0x0f;
186                     pv->alpha[1] = (pv->buf[i+1]>>4)&0x0f;
187                     pv->alpha[0] = (pv->buf[i+1])&0x0f;
188                     i += 2;
189                     break;
190                 }
191                 case 0x05:
192                 {
193                     pv->x     = (pv->buf[i+0]<<4) | ((pv->buf[i+1]>>4)&0x0f);
194                     pv->width = (((pv->buf[i+1]&0x0f)<<8)| pv->buf[i+2]) - pv->x + 1;
195                     pv->y     = (pv->buf[i+3]<<4)| ((pv->buf[i+4]>>4)&0x0f);
196                     pv->height = (((pv->buf[i+4]&0x0f)<<8)| pv->buf[i+5]) - pv->y + 1;
197                     i += 6;
198                     break;
199                 }
200                 case 0x06:
201                 {
202                     pv->offsets[0] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
203                     pv->offsets[1] = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
204                     break;
205                 }
206             }
207         }
208
209         if( i > next )
210         {
211             break;
212         }
213         i = next;
214     }
215
216     if( !pv->pts_stop )
217     {
218         /* Show it for 3 seconds */
219         pv->pts_stop = pv->pts_start + 3 * 90000;
220     }
221 }
222
223 /***********************************************************************
224  * CropSubtitle
225  ***********************************************************************
226  * Given a raw decoded subtitle, detects transparent borders and
227  * returns a cropped subtitle in a hb_buffer_t ready to be used by
228  * the renderer, or NULL if the subtitle was completely transparent
229  **********************************************************************/
230 static int LineIsTransparent( hb_work_object_t * w, uint8_t * p )
231 {
232     hb_work_private_t * pv = w->private_data;
233     int i;
234     for( i = 0; i < pv->width; i++ )
235     {
236         if( p[i] )
237         {
238             return 0;
239         }
240     }
241     return 1;
242 }
243 static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p )
244 {
245     hb_work_private_t * pv = w->private_data;
246     int i;
247     for( i = 0; i < pv->height; i++ )
248     {
249         if( p[i*pv->width] )
250         {
251             return 0;
252         }
253     }
254     return 1;
255 }
256 static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw )
257 {
258     hb_work_private_t * pv = w->private_data;
259     int i;
260     int crop[4] = { -1,-1,-1,-1 };
261     uint8_t * alpha;
262     int realwidth, realheight;
263     hb_buffer_t * buf;
264     uint8_t * lum_in, * lum_out, * alpha_in, * alpha_out;
265
266     alpha = raw + pv->width * pv->height;
267
268     /* Top */
269     for( i = 0; i < pv->height; i++ )
270     {
271         if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
272         {
273             crop[0] = i;
274             break;
275         }
276     }
277
278     if( crop[0] < 0 )
279     {
280         /* Empty subtitle */
281         return NULL;
282     }
283
284     /* Bottom */
285     for( i = pv->height - 1; i >= 0; i-- )
286     {
287         if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
288         {
289             crop[1] = i;
290             break;
291         }
292     }
293
294     /* Left */
295     for( i = 0; i < pv->width; i++ )
296     {
297         if( !ColumnIsTransparent( w, &alpha[i] ) )
298         {
299             crop[2] = i;
300             break;
301         }
302     }
303
304     /* Right */
305     for( i = pv->width - 1; i >= 0; i-- )
306     {
307         if( !ColumnIsTransparent( w, &alpha[i] ) )
308         {
309             crop[3] = i;
310             break;
311         }
312     }
313
314     realwidth  = crop[3] - crop[2] + 1;
315     realheight = crop[1] - crop[0] + 1;
316
317     buf         = hb_buffer_init( realwidth * realheight * 2 );
318     buf->start  = pv->pts_start;
319     buf->stop   = pv->pts_stop;
320     buf->x      = pv->x + crop[2];
321     buf->y      = pv->y + crop[0];
322     buf->width  = realwidth;
323     buf->height = realheight;
324
325     lum_in    = raw + crop[0] * pv->width + crop[2];
326     alpha_in  = lum_in + pv->width * pv->height;
327     lum_out   = buf->data;
328     alpha_out = lum_out + realwidth * realheight;
329
330     for( i = 0; i < realheight; i++ )
331     {
332         memcpy( lum_out, lum_in, realwidth );
333         memcpy( alpha_out, alpha_in, realwidth );
334         lum_in    += pv->width;
335         alpha_in  += pv->width;
336         lum_out   += realwidth;
337         alpha_out += realwidth;
338     }
339
340     return buf;
341 }
342
343 static hb_buffer_t * Decode( hb_work_object_t * w )
344 {
345     hb_work_private_t * pv = w->private_data;
346     int code, line, col;
347     int offsets[2];
348     int * offset;
349     hb_buffer_t * buf;
350     uint8_t * buf_raw = NULL;
351
352     /* Get infos about the subtitle */
353     ParseControls( w );
354
355     /* Do the actual decoding now */
356     buf_raw = malloc( pv->width * pv->height * 2 );
357
358 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
359 ( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
360 (*offset)++
361     
362     offsets[0] = pv->offsets[0] * 2;
363     offsets[1] = pv->offsets[1] * 2;
364
365     for( line = 0; line < pv->height; line++ )
366     {
367         /* Select even or odd field */
368         offset = ( line & 1 ) ? &offsets[1] : &offsets[0];
369
370         for( col = 0; col < pv->width; col += code >> 2 )
371         {
372             uint8_t * lum, * alpha;
373
374             code = 0;
375             GET_NEXT_NIBBLE;
376             if( code < 0x4 )
377             {
378                 GET_NEXT_NIBBLE;
379                 if( code < 0x10 )
380                 {
381                     GET_NEXT_NIBBLE;
382                     if( code < 0x40 )
383                     {
384                         GET_NEXT_NIBBLE;
385                         if( code < 0x100 )
386                         {
387                             /* End of line */
388                             code |= ( pv->width - col ) << 2;
389                         }
390                     }
391                 }
392             }
393
394             lum   = buf_raw;
395             alpha = lum + pv->width * pv->height;
396             memset( lum + line * pv->width + col,
397                     pv->lum[code & 3], code >> 2 );
398             memset( alpha + line * pv->width + col,
399                     pv->alpha[code & 3], code >> 2 );
400         }
401
402         /* Byte-align */
403         if( *offset & 1 )
404         {
405             (*offset)++;
406         }
407     }
408
409     /* Crop subtitle (remove transparent borders) */
410     buf = CropSubtitle( w, buf_raw );
411
412     free( buf_raw );
413
414     return buf;
415 }