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. */
9 struct hb_work_private_s
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
) );
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];
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
;
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
;
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 */
102 void decsubClose( hb_work_object_t
* w
)
104 free( w
->private_data
);
107 hb_work_object_t hb_decsub
=
117 /***********************************************************************
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
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
;
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;
144 command
= pv
->buf
[i
++];
146 if( command
== 0xFF )
157 pv
->pts_start
= pv
->pts
+ date
* 900;
161 pv
->pts_stop
= pv
->pts
+ date
* 900;
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;
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;
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;
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;
218 /* Show it for 3 seconds */
219 pv
->pts_stop
= pv
->pts_start
+ 3 * 90000;
223 /***********************************************************************
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
;
234 for( i
= 0; i
< pv
->width
; i
++ )
243 static int ColumnIsTransparent( hb_work_object_t
* w
, uint8_t * p
)
245 hb_work_private_t
* pv
= w
->private_data
;
247 for( i
= 0; i
< pv
->height
; i
++ )
256 static hb_buffer_t
* CropSubtitle( hb_work_object_t
* w
, uint8_t * raw
)
258 hb_work_private_t
* pv
= w
->private_data
;
260 int crop
[4] = { -1,-1,-1,-1 };
262 int realwidth
, realheight
;
264 uint8_t * lum_in
, * lum_out
, * alpha_in
, * alpha_out
;
266 alpha
= raw
+ pv
->width
* pv
->height
;
269 for( i
= 0; i
< pv
->height
; i
++ )
271 if( !LineIsTransparent( w
, &alpha
[i
*pv
->width
] ) )
285 for( i
= pv
->height
- 1; i
>= 0; i
-- )
287 if( !LineIsTransparent( w
, &alpha
[i
*pv
->width
] ) )
295 for( i
= 0; i
< pv
->width
; i
++ )
297 if( !ColumnIsTransparent( w
, &alpha
[i
] ) )
305 for( i
= pv
->width
- 1; i
>= 0; i
-- )
307 if( !ColumnIsTransparent( w
, &alpha
[i
] ) )
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
;
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
);
335 alpha_in
+= pv
->width
;
336 lum_out
+= realwidth
;
337 alpha_out
+= realwidth
;
343 static hb_buffer_t
* Decode( hb_work_object_t
* w
)
345 hb_work_private_t
* pv
= w
->private_data
;
350 uint8_t * buf_raw
= NULL
;
352 /* Get infos about the subtitle */
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 ) ) ); \
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
;
388 code
|= ( pv
->width
- col
) << 2;
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 );
409 /* Crop subtitle (remove transparent borders) */
410 buf
= CropSubtitle( w
, buf_raw
);