1 /*****************************************************************************
2 * SSA/ASS subtitle decoder using libass.
3 *****************************************************************************
4 * Copyright (C) 2008-2009 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
37 #include <vlc_common.h>
38 #include <vlc_plugin.h>
39 #include <vlc_codec.h>
40 #include <vlc_input.h>
41 #include <vlc_dialog.h>
46 # include <vlc_charset.h>
49 /* Compatibility with old libass */
50 #if !defined(LIBASS_VERSION) || LIBASS_VERSION < 0x00907010
51 # define ASS_Renderer ass_renderer_t
52 # define ASS_Library ass_library_t
53 # define ASS_Track ass_track_t
54 # define ASS_Image ass_image_t
57 /*****************************************************************************
59 *****************************************************************************/
60 static int Create ( vlc_object_t
* );
61 static void Destroy( vlc_object_t
* );
64 set_shortname( N_("Subtitles (advanced)"))
65 set_description( N_("Subtitle renderers using libass") )
66 set_capability( "decoder", 100 )
67 set_category( CAT_INPUT
)
68 set_subcategory( SUBCAT_INPUT_SCODEC
)
69 set_callbacks( Create
, Destroy
)
72 /*****************************************************************************
74 *****************************************************************************/
75 static subpicture_t
*DecodeBlock( decoder_t
*, block_t
** );
77 /* Yes libass sux with threads */
80 vlc_object_t
*p_libvlc
;
83 ASS_Library
*p_library
;
84 ASS_Renderer
*p_renderer
;
87 static ass_handle_t
*AssHandleHold( decoder_t
*p_dec
);
88 static void AssHandleRelease( ass_handle_t
* );
95 /* decoder_sys_t is shared between decoder and spu units */
105 static void DecSysRelease( decoder_sys_t
*p_sys
);
106 static void DecSysHold( decoder_sys_t
*p_sys
);
109 static int SubpictureValidate( subpicture_t
*,
110 bool, const video_format_t
*,
111 bool, const video_format_t
*,
113 static void SubpictureUpdate( subpicture_t
*,
114 const video_format_t
*,
115 const video_format_t
*,
117 static void SubpictureDestroy( subpicture_t
* );
119 struct subpicture_updater_sys_t
121 decoder_sys_t
*p_dec_sys
;
137 static int BuildRegions( rectangle_t
*p_region
, int i_max_region
, ASS_Image
*p_img_list
, int i_width
, int i_height
);
138 static void RegionDraw( subpicture_region_t
*p_region
, ASS_Image
*p_img
);
140 static vlc_mutex_t libass_lock
= VLC_STATIC_MUTEX
;
142 //#define DEBUG_REGION
144 /*****************************************************************************
145 * Create: Open libass decoder.
146 *****************************************************************************/
147 static int Create( vlc_object_t
*p_this
)
149 decoder_t
*p_dec
= (decoder_t
*)p_this
;
150 decoder_sys_t
*p_sys
;
153 if( p_dec
->fmt_in
.i_codec
!= VLC_CODEC_SSA
)
156 p_dec
->pf_decode_sub
= DecodeBlock
;
158 p_dec
->p_sys
= p_sys
= malloc( sizeof( decoder_sys_t
) );
163 p_sys
->i_max_stop
= VLC_TS_INVALID
;
164 p_sys
->p_ass
= AssHandleHold( p_dec
);
170 vlc_mutex_init( &p_sys
->lock
);
171 p_sys
->i_refcount
= 1;
174 vlc_mutex_lock( &libass_lock
);
175 p_sys
->p_track
= p_track
= ass_new_track( p_sys
->p_ass
->p_library
);
178 vlc_mutex_unlock( &libass_lock
);
179 DecSysRelease( p_sys
);
182 ass_process_codec_private( p_track
, p_dec
->fmt_in
.p_extra
, p_dec
->fmt_in
.i_extra
);
183 vlc_mutex_unlock( &libass_lock
);
185 p_dec
->fmt_out
.i_cat
= SPU_ES
;
186 p_dec
->fmt_out
.i_codec
= VLC_CODEC_RGBA
;
191 /*****************************************************************************
193 *****************************************************************************/
194 static void Destroy( vlc_object_t
*p_this
)
196 decoder_t
*p_dec
= (decoder_t
*)p_this
;
198 DecSysRelease( p_dec
->p_sys
);
201 static void DecSysHold( decoder_sys_t
*p_sys
)
203 vlc_mutex_lock( &p_sys
->lock
);
205 vlc_mutex_unlock( &p_sys
->lock
);
207 static void DecSysRelease( decoder_sys_t
*p_sys
)
210 vlc_mutex_lock( &p_sys
->lock
);
212 if( p_sys
->i_refcount
> 0 )
214 vlc_mutex_unlock( &p_sys
->lock
);
217 vlc_mutex_unlock( &p_sys
->lock
);
218 vlc_mutex_destroy( &p_sys
->lock
);
220 vlc_mutex_lock( &libass_lock
);
222 ass_free_track( p_sys
->p_track
);
223 vlc_mutex_unlock( &libass_lock
);
225 AssHandleRelease( p_sys
->p_ass
);
229 /****************************************************************************
231 ****************************************************************************/
232 static subpicture_t
*DecodeBlock( decoder_t
*p_dec
, block_t
**pp_block
)
234 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
236 subpicture_t
*p_spu
= NULL
;
239 if( !pp_block
|| *pp_block
== NULL
)
243 if( p_block
->i_flags
& (BLOCK_FLAG_DISCONTINUITY
|BLOCK_FLAG_CORRUPTED
) )
245 p_sys
->i_max_stop
= VLC_TS_INVALID
;
246 block_Release( p_block
);
251 if( p_block
->i_buffer
== 0 || p_block
->p_buffer
[0] == '\0' )
253 block_Release( p_block
);
257 subpicture_updater_sys_t
*p_spu_sys
= malloc( sizeof(*p_spu_sys
) );
260 block_Release( p_block
);
264 subpicture_updater_t updater
= {
265 .pf_validate
= SubpictureValidate
,
266 .pf_update
= SubpictureUpdate
,
267 .pf_destroy
= SubpictureDestroy
,
270 p_spu
= decoder_NewSubpicture( p_dec
, &updater
);
273 msg_Warn( p_dec
, "can't get spu buffer" );
275 block_Release( p_block
);
279 p_spu_sys
->p_img
= NULL
;
280 p_spu_sys
->p_dec_sys
= p_sys
;
281 p_spu_sys
->i_subs_len
= p_block
->i_buffer
;
282 p_spu_sys
->p_subs_data
= malloc( p_block
->i_buffer
);
283 p_spu_sys
->i_pts
= p_block
->i_pts
;
284 if( !p_spu_sys
->p_subs_data
)
286 decoder_DeleteSubpicture( p_dec
, p_spu
);
287 block_Release( p_block
);
290 memcpy( p_spu_sys
->p_subs_data
, p_block
->p_buffer
,
293 p_spu
->i_start
= p_block
->i_pts
;
294 p_spu
->i_stop
= __MAX( p_sys
->i_max_stop
, p_block
->i_pts
+ p_block
->i_length
);
295 p_spu
->b_ephemer
= true;
296 p_spu
->b_absolute
= true;
298 p_sys
->i_max_stop
= p_spu
->i_stop
;
300 vlc_mutex_lock( &libass_lock
);
303 ass_process_chunk( p_sys
->p_track
, p_spu_sys
->p_subs_data
, p_spu_sys
->i_subs_len
,
304 p_block
->i_pts
/ 1000, p_block
->i_length
/ 1000 );
306 vlc_mutex_unlock( &libass_lock
);
308 DecSysHold( p_sys
); /* Keep a reference for the returned subpicture */
310 block_Release( p_block
);
315 /****************************************************************************
317 ****************************************************************************/
318 static int SubpictureValidate( subpicture_t
*p_subpic
,
319 bool b_fmt_src
, const video_format_t
*p_fmt_src
,
320 bool b_fmt_dst
, const video_format_t
*p_fmt_dst
,
323 decoder_sys_t
*p_sys
= p_subpic
->updater
.p_sys
->p_dec_sys
;
324 ass_handle_t
*p_ass
= p_sys
->p_ass
;
326 vlc_mutex_lock( &libass_lock
);
328 /* FIXME why this mix of src/dst */
329 video_format_t fmt
= *p_fmt_dst
;
330 fmt
.i_chroma
= VLC_CODEC_RGBA
;
331 fmt
.i_bits_per_pixel
= 0;
333 fmt
.i_visible_width
= p_fmt_src
->i_width
;
335 fmt
.i_visible_height
= p_fmt_src
->i_height
;
339 if( b_fmt_src
|| b_fmt_dst
)
341 ass_set_frame_size( p_ass
->p_renderer
, fmt
.i_width
, fmt
.i_height
);
342 #if defined( LIBASS_VERSION ) && LIBASS_VERSION >= 0x00907000
343 ass_set_aspect_ratio( p_ass
->p_renderer
, 1.0, 1.0 ); // TODO ?
345 ass_set_aspect_ratio( p_ass
->p_renderer
, 1.0 ); // TODO ?
351 const mtime_t i_stream_date
= p_subpic
->updater
.p_sys
->i_pts
+ (i_ts
- p_subpic
->i_start
);
353 ASS_Image
*p_img
= ass_render_frame( p_ass
->p_renderer
, p_sys
->p_track
,
354 i_stream_date
/1000, &i_changed
);
356 if( !i_changed
&& !b_fmt_src
&& !b_fmt_dst
&&
357 (p_img
!= NULL
) == (p_subpic
->p_region
!= NULL
) )
359 vlc_mutex_unlock( &libass_lock
);
362 p_subpic
->updater
.p_sys
->p_img
= p_img
;
364 /* The lock is released by SubpictureUpdate */
368 static void SubpictureUpdate( subpicture_t
*p_subpic
,
369 const video_format_t
*p_fmt_src
,
370 const video_format_t
*p_fmt_dst
,
373 VLC_UNUSED( p_fmt_src
); VLC_UNUSED( p_fmt_dst
); VLC_UNUSED( i_ts
);
375 decoder_sys_t
*p_sys
= p_subpic
->updater
.p_sys
->p_dec_sys
;
376 ass_handle_t
*p_ass
= p_sys
->p_ass
;
378 video_format_t fmt
= p_ass
->fmt
;
379 ASS_Image
*p_img
= p_subpic
->updater
.p_sys
->p_img
;
380 //vlc_assert_locked( &libass_lock );
383 p_subpic
->i_original_picture_height
= fmt
.i_height
;
384 p_subpic
->i_original_picture_width
= fmt
.i_width
;
386 /* XXX to improve efficiency we merge regions that are close minimizing
388 * libass tends to create a lot of small regions and thus spu engine
389 * reinstanciate a lot the scaler, and as we do not support subpel blending
390 * it looks ugly (text unaligned).
392 const int i_max_region
= 4;
393 rectangle_t region
[i_max_region
];
394 const int i_region
= BuildRegions( region
, i_max_region
, p_img
, fmt
.i_width
, fmt
.i_height
);
398 vlc_mutex_unlock( &libass_lock
);
402 /* Allocate the regions and draw them */
403 subpicture_region_t
*pp_region
[i_max_region
];
404 subpicture_region_t
**pp_region_last
= &p_subpic
->p_region
;
406 for( int i
= 0; i
< i_region
; i
++ )
408 subpicture_region_t
*r
;
409 video_format_t fmt_region
;
414 fmt_region
.i_visible_width
= region
[i
].x1
- region
[i
].x0
;
415 fmt_region
.i_height
=
416 fmt_region
.i_visible_height
= region
[i
].y1
- region
[i
].y0
;
418 pp_region
[i
] = r
= subpicture_region_New( &fmt_region
);
421 r
->i_x
= region
[i
].x0
;
422 r
->i_y
= region
[i
].y0
;
423 r
->i_align
= SUBPICTURE_ALIGN_TOP
| SUBPICTURE_ALIGN_LEFT
;
426 RegionDraw( r
, p_img
);
430 pp_region_last
= &r
->p_next
;
432 vlc_mutex_unlock( &libass_lock
);
435 static void SubpictureDestroy( subpicture_t
*p_subpic
)
437 subpicture_updater_sys_t
*p_sys
= p_subpic
->updater
.p_sys
;
439 DecSysRelease( p_sys
->p_dec_sys
);
440 free( p_sys
->p_subs_data
);
444 static rectangle_t
r_create( int x0
, int y0
, int x1
, int y1
)
446 rectangle_t r
= { x0
, y0
, x1
, y1
};
449 static rectangle_t
r_img( const ASS_Image
*p_img
)
451 return r_create( p_img
->dst_x
, p_img
->dst_y
, p_img
->dst_x
+p_img
->w
, p_img
->dst_y
+p_img
->h
);
453 static void r_add( rectangle_t
*r
, const rectangle_t
*n
)
455 r
->x0
= __MIN( r
->x0
, n
->x0
);
456 r
->y0
= __MIN( r
->y0
, n
->y0
);
457 r
->x1
= __MAX( r
->x1
, n
->x1
);
458 r
->y1
= __MAX( r
->y1
, n
->y1
);
460 static int r_surface( const rectangle_t
*r
)
462 return (r
->x1
-r
->x0
) * (r
->y1
-r
->y0
);
464 static bool r_overlap( const rectangle_t
*a
, const rectangle_t
*b
, int i_dx
, int i_dy
)
466 return __MAX(a
->x0
-i_dx
, b
->x0
) < __MIN( a
->x1
+i_dx
, b
->x1
) &&
467 __MAX(a
->y0
-i_dy
, b
->y0
) < __MIN( a
->y1
+i_dy
, b
->y1
);
470 static int BuildRegions( rectangle_t
*p_region
, int i_max_region
, ASS_Image
*p_img_list
, int i_width
, int i_height
)
476 int64_t i_ck_start
= mdate();
479 for( p_tmp
= p_img_list
, i_count
= 0; p_tmp
!= NULL
; p_tmp
= p_tmp
->next
)
480 if( p_tmp
->w
> 0 && p_tmp
->h
> 0 )
485 ASS_Image
**pp_img
= calloc( i_count
, sizeof(*pp_img
) );
489 for( p_tmp
= p_img_list
, i_count
= 0; p_tmp
!= NULL
; p_tmp
= p_tmp
->next
)
490 if( p_tmp
->w
> 0 && p_tmp
->h
> 0 )
491 pp_img
[i_count
++] = p_tmp
;
494 const int i_w_inc
= __MAX( ( i_width
+ 49 ) / 50, 32 );
495 const int i_h_inc
= __MAX( ( i_height
+ 99 ) / 100, 32 );
496 int i_maxh
= i_w_inc
;
497 int i_maxw
= i_h_inc
;
499 rectangle_t region
[i_max_region
+1];
502 for( int i_used
= 0; i_used
< i_count
; )
505 for( n
= 0; n
< i_count
; n
++ )
510 assert( i_region
< i_max_region
+ 1 );
511 region
[i_region
++] = r_img( pp_img
[n
] );
512 pp_img
[n
] = NULL
; i_used
++;
517 for( n
= 0; n
< i_count
; n
++ )
519 ASS_Image
*p_img
= pp_img
[n
];
522 rectangle_t r
= r_img( p_img
);
526 int i_best_s
= INT_MAX
;
527 for( k
= 0; k
< i_region
; k
++ )
529 if( !r_overlap( ®ion
[k
], &r
, i_maxw
, i_maxh
) )
531 int s
= r_surface( &r
);
540 r_add( ®ion
[i_best
], &r
);
541 pp_img
[n
] = NULL
; i_used
++;
547 if( i_region
> i_max_region
)
551 int i_best_ds
= INT_MAX
;
554 for( int i
= 0; i
< i_region
; i
++ )
556 for( int j
= i
+1; j
< i_region
; j
++ )
558 rectangle_t n
= region
[i
];
559 r_add( &n
, ®ion
[j
] );
560 int ds
= r_surface( &n
) - r_surface( ®ion
[i
] ) - r_surface( ®ion
[j
] );
571 msg_Err( p_spu
, "Merging %d and %d", i_best_i
, i_best_j
);
573 r_add( ®ion
[i_best_i
], ®ion
[i_best_j
] );
575 if( i_best_j
+1 < i_region
)
576 memmove( ®ion
[i_best_j
], ®ion
[i_best_j
+1], sizeof(*region
) * ( i_region
- (i_best_j
+1) ) );
582 for( int n
= 0; n
< i_region
; n
++ )
583 p_region
[n
] = region
[n
];
586 int64_t i_ck_time
= mdate() - i_ck_start
;
587 msg_Err( p_spu
, "ASS: %d objects merged into %d region in %d micros", i_count
, i_region
, (int)(i_ck_time
) );
595 static void RegionDraw( subpicture_region_t
*p_region
, ASS_Image
*p_img
)
597 const plane_t
*p
= &p_region
->p_picture
->p
[0];
598 const int i_x
= p_region
->i_x
;
599 const int i_y
= p_region
->i_y
;
600 const int i_width
= p_region
->fmt
.i_width
;
601 const int i_height
= p_region
->fmt
.i_height
;
603 memset( p
->p_pixels
, 0x00, p
->i_pitch
* p
->i_lines
);
604 for( ; p_img
!= NULL
; p_img
= p_img
->next
)
606 if( p_img
->dst_x
< i_x
|| p_img
->dst_x
+ p_img
->w
> i_x
+ i_width
||
607 p_img
->dst_y
< i_y
|| p_img
->dst_y
+ p_img
->h
> i_y
+ i_height
)
610 const unsigned r
= (p_img
->color
>> 24)&0xff;
611 const unsigned g
= (p_img
->color
>> 16)&0xff;
612 const unsigned b
= (p_img
->color
>> 8)&0xff;
613 const unsigned a
= (p_img
->color
)&0xff;
616 for( y
= 0; y
< p_img
->h
; y
++ )
618 for( x
= 0; x
< p_img
->w
; x
++ )
620 const unsigned alpha
= p_img
->bitmap
[y
*p_img
->stride
+x
];
621 const unsigned an
= (255 - a
) * alpha
/ 255;
623 uint8_t *p_rgba
= &p
->p_pixels
[(y
+p_img
->dst_y
-i_y
) * p
->i_pitch
+ 4 * (x
+p_img
->dst_x
-i_x
)];
624 const unsigned ao
= p_rgba
[3];
626 /* Native endianness, but RGBA ordering */
629 /* Optimized but the else{} will produce the same result */
637 p_rgba
[3] = 255 - ( 255 - p_rgba
[3] ) * ( 255 - an
) / 255;
640 p_rgba
[0] = ( p_rgba
[0] * ao
* (255-an
) / 255 + r
* an
) / p_rgba
[3];
641 p_rgba
[1] = ( p_rgba
[1] * ao
* (255-an
) / 255 + g
* an
) / p_rgba
[3];
642 p_rgba
[2] = ( p_rgba
[2] * ao
* (255-an
) / 255 + b
* an
) / p_rgba
[3];
650 /* XXX Draw a box for debug */
651 #define P(x,y) ((uint32_t*)&p->p_pixels[(y)*p->i_pitch + 4*(x)])
652 for( int y
= 0; y
< p
->i_lines
; y
++ )
653 *P(0,y
) = *P(p
->i_visible_pitch
/4-1,y
) = 0xff000000;
654 for( int x
= 0; x
< p
->i_visible_pitch
; x
++ )
655 *P(x
/4,0) = *P(x
/4,p
->i_visible_lines
-1) = 0xff000000;
661 static ass_handle_t
*AssHandleHold( decoder_t
*p_dec
)
663 vlc_mutex_lock( &libass_lock
);
665 ass_handle_t
*p_ass
= NULL
;
666 ASS_Library
*p_library
= NULL
;
667 ASS_Renderer
*p_renderer
= NULL
;
670 var_Create( p_dec
->p_libvlc
, "libass-handle", VLC_VAR_ADDRESS
);
671 if( var_Get( p_dec
->p_libvlc
, "libass-handle", &val
) )
672 val
.p_address
= NULL
;
676 p_ass
= val
.p_address
;
680 vlc_mutex_unlock( &libass_lock
);
685 p_ass
= malloc( sizeof(*p_ass
) );
690 p_ass
->p_libvlc
= VLC_OBJECT(p_dec
->p_libvlc
);
691 p_ass
->i_refcount
= 1;
693 /* Create libass library */
694 p_ass
->p_library
= p_library
= ass_library_init();
698 /* load attachments */
699 input_attachment_t
**pp_attachments
;
702 if( decoder_GetInputAttachments( p_dec
, &pp_attachments
, &i_attachments
))
705 pp_attachments
= NULL
;
707 for( int k
= 0; k
< i_attachments
; k
++ )
709 input_attachment_t
*p_attach
= pp_attachments
[k
];
711 if( !strcasecmp( p_attach
->psz_mime
, "application/x-truetype-font" ) )
713 msg_Dbg( p_dec
, "adding embedded font %s", p_attach
->psz_name
);
715 ass_add_font( p_ass
->p_library
, p_attach
->psz_name
, p_attach
->p_data
, p_attach
->i_data
);
717 vlc_input_attachment_Delete( p_attach
);
719 free( pp_attachments
);
721 ass_set_extract_fonts( p_library
, true );
722 ass_set_style_overrides( p_library
, NULL
);
724 /* Create the renderer */
725 p_ass
->p_renderer
= p_renderer
= ass_renderer_init( p_library
);
729 ass_set_use_margins( p_renderer
, false);
731 // ass_set_margins( p_renderer, int t, int b, int l, int r);
732 ass_set_hinting( p_renderer
, ASS_HINTING_LIGHT
);
733 ass_set_font_scale( p_renderer
, 1.0 );
734 ass_set_line_spacing( p_renderer
, 0.0 );
736 const char *psz_font
= NULL
; /* We don't ship a default font with VLC */
737 const char *psz_family
= "Arial"; /* Use Arial if we can't find anything more suitable */
739 #ifdef HAVE_FONTCONFIG
741 dialog_progress_bar_t
*p_dialog
= dialog_ProgressCreate( p_dec
,
742 _("Building font cache"),
743 _( "Please wait while your font cache is rebuilt.\n"
744 "This should take less than a minute." ), NULL
);
746 dialog_ProgressSet( p_dialog
, NULL
, 0.2 );
748 #if defined( LIBASS_VERSION ) && LIBASS_VERSION >= 0x00907000
749 ass_set_fonts( p_renderer
, psz_font
, psz_family
, true, NULL
, 1 ); // setup default font/family
751 ass_set_fonts( p_renderer
, psz_font
, psz_family
); // setup default font/family
756 dialog_ProgressSet( p_dialog
, NULL
, 1.0 );
757 dialog_ProgressDestroy( p_dialog
);
762 /* FIXME you HAVE to give him a font if no fontconfig */
763 #if defined( LIBASS_VERSION ) && LIBASS_VERSION >= 0x00907000
764 ass_set_fonts( p_renderer
, psz_font
, psz_family
, false, NULL
, 1 );
766 ass_set_fonts_nofc( p_renderer
, psz_font
, psz_family
);
769 memset( &p_ass
->fmt
, 0, sizeof(p_ass
->fmt
) );
772 val
.p_address
= p_ass
;
773 var_Set( p_dec
->p_libvlc
, "libass-handle", val
);
776 vlc_mutex_unlock( &libass_lock
);
781 ass_renderer_done( p_renderer
);
783 ass_library_done( p_library
);
785 msg_Warn( p_dec
, "Libass creation failed" );
788 vlc_mutex_unlock( &libass_lock
);
791 static void AssHandleRelease( ass_handle_t
*p_ass
)
793 vlc_mutex_lock( &libass_lock
);
795 if( p_ass
->i_refcount
> 0 )
797 vlc_mutex_unlock( &libass_lock
);
801 ass_renderer_done( p_ass
->p_renderer
);
802 ass_library_done( p_ass
->p_library
);
805 val
.p_address
= NULL
;
806 var_Set( p_ass
->p_libvlc
, "libass-handle", val
);
808 vlc_mutex_unlock( &libass_lock
);