Moves the filters' logging info to work.c, adds parameter info. I also changed the...
[HandBrake.git] / libhb / decsub.c
blob3666ea3fe3ec56f311e791736ac1baf57edfa99e
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 x;
21 int y;
22 int width;
23 int height;
25 int offsets[2];
26 uint8_t lum[4];
27 uint8_t alpha[4];
30 static hb_buffer_t * Decode( hb_work_object_t * );
32 int decsubInit( hb_work_object_t * w, hb_job_t * job )
34 hb_work_private_t * pv;
36 pv = calloc( 1, sizeof( hb_work_private_t ) );
37 w->private_data = pv;
39 pv->job = job;
40 pv->pts = -1;
42 return 0;
45 int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
46 hb_buffer_t ** buf_out )
48 hb_work_private_t * pv = w->private_data;
49 hb_buffer_t * in = *buf_in;
51 int size_sub, size_rle;
53 size_sub = ( in->data[0] << 8 ) | in->data[1];
54 size_rle = ( in->data[2] << 8 ) | in->data[3];
56 if( !pv->size_sub )
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 )
62 /* Looks all right so far */
63 pv->size_sub = size_sub;
64 pv->size_rle = size_rle;
66 memcpy( pv->buf, in->data, in->size );
67 pv->size_got = in->size;
68 pv->pts = in->start;
71 else
73 /* We are waiting for the end of the current subtitle */
74 if( in->size <= pv->size_sub - pv->size_got )
76 memcpy( pv->buf + pv->size_got, in->data, in->size );
77 pv->size_got += in->size;
78 if( in->start >= 0 )
80 pv->pts = in->start;
85 *buf_out = NULL;
87 if( pv->size_sub && pv->size_sub == pv->size_got )
89 /* We got a complete subtitle, decode it */
90 *buf_out = Decode( w );
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;
99 return HB_WORK_OK;
102 void decsubClose( hb_work_object_t * w )
104 free( w->private_data );
107 hb_work_object_t hb_decsub =
109 WORK_DECSUB,
110 "Subtitle decoder",
111 decsubInit,
112 decsubWork,
113 decsubClose
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 )
126 hb_work_private_t * pv = w->private_data;
127 hb_job_t * job = pv->job;
128 hb_title_t * title = job->title;
130 int i;
131 int command;
132 int date, next;
134 pv->pts_start = 0;
135 pv->pts_stop = 0;
137 for( i = pv->size_rle; ; )
139 date = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
140 next = ( pv->buf[i] << 8 ) | pv->buf[i+1]; i += 2;
142 for( ;; )
144 command = pv->buf[i++];
146 if( command == 0xFF )
148 break;
151 switch( command )
153 case 0x00:
154 break;
156 case 0x01:
157 pv->pts_start = pv->pts + date * 900;
158 break;
160 case 0x02:
161 pv->pts_stop = pv->pts + date * 900;
162 break;
164 case 0x03:
166 int colors[4];
167 int j;
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;
174 for( j = 0; j < 4; j++ )
176 uint32_t color = title->palette[colors[j]];
177 pv->lum[3-j] = (color>>16) & 0xff;
179 i += 2;
180 break;
182 case 0x04:
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;
191 case 0x05:
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;
200 case 0x06:
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;
209 if( i > next )
211 break;
213 i = next;
216 if( !pv->pts_stop )
218 /* Show it for 3 seconds */
219 pv->pts_stop = pv->pts_start + 3 * 90000;
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 )
232 hb_work_private_t * pv = w->private_data;
233 int i;
234 for( i = 0; i < pv->width; i++ )
236 if( p[i] )
238 return 0;
241 return 1;
243 static int ColumnIsTransparent( hb_work_object_t * w, uint8_t * p )
245 hb_work_private_t * pv = w->private_data;
246 int i;
247 for( i = 0; i < pv->height; i++ )
249 if( p[i*pv->width] )
251 return 0;
254 return 1;
256 static hb_buffer_t * CropSubtitle( hb_work_object_t * w, uint8_t * raw )
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;
266 alpha = raw + pv->width * pv->height;
268 /* Top */
269 for( i = 0; i < pv->height; i++ )
271 if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
273 crop[0] = i;
274 break;
278 if( crop[0] < 0 )
280 /* Empty subtitle */
281 return NULL;
284 /* Bottom */
285 for( i = pv->height - 1; i >= 0; i-- )
287 if( !LineIsTransparent( w, &alpha[i*pv->width] ) )
289 crop[1] = i;
290 break;
294 /* Left */
295 for( i = 0; i < pv->width; i++ )
297 if( !ColumnIsTransparent( w, &alpha[i] ) )
299 crop[2] = i;
300 break;
304 /* Right */
305 for( i = pv->width - 1; i >= 0; i-- )
307 if( !ColumnIsTransparent( w, &alpha[i] ) )
309 crop[3] = i;
310 break;
314 realwidth = crop[3] - crop[2] + 1;
315 realheight = crop[1] - crop[0] + 1;
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;
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;
330 for( i = 0; i < realheight; i++ )
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;
340 return buf;
343 static hb_buffer_t * Decode( hb_work_object_t * w )
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;
352 /* Get infos about the subtitle */
353 ParseControls( w );
355 /* Do the actual decoding now */
356 buf_raw = malloc( pv->width * pv->height * 2 );
358 #define GET_NEXT_NIBBLE code = ( code << 4 ) | ( ( ( *offset & 1 ) ? \
359 ( pv->buf[((*offset)>>1)] & 0xF ) : ( pv->buf[((*offset)>>1)] >> 4 ) ) ); \
360 (*offset)++
362 offsets[0] = pv->offsets[0] * 2;
363 offsets[1] = pv->offsets[1] * 2;
365 for( line = 0; line < pv->height; line++ )
367 /* Select even or odd field */
368 offset = ( line & 1 ) ? &offsets[1] : &offsets[0];
370 for( col = 0; col < pv->width; col += code >> 2 )
372 uint8_t * lum, * alpha;
374 code = 0;
375 GET_NEXT_NIBBLE;
376 if( code < 0x4 )
378 GET_NEXT_NIBBLE;
379 if( code < 0x10 )
381 GET_NEXT_NIBBLE;
382 if( code < 0x40 )
384 GET_NEXT_NIBBLE;
385 if( code < 0x100 )
387 /* End of line */
388 code |= ( pv->width - col ) << 2;
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 );
402 /* Byte-align */
403 if( *offset & 1 )
405 (*offset)++;
409 /* Crop subtitle (remove transparent borders) */
410 buf = CropSubtitle( w, buf_raw );
412 free( buf_raw );
414 return buf;