1 /*****************************************************************************
2 * kate.c : a decoder for the kate bitstream format
3 *****************************************************************************
4 * Copyright (C) 2000-2008 VLC authors and VideoLAN
7 * Authors: Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_input.h>
34 #include <vlc_codec.h>
35 #include "../demux/xiph.h"
37 #include <kate/kate.h>
39 # include <tiger/tiger.h>
42 /* #define ENABLE_PACKETIZER */
43 /* #define ENABLE_PROFILE */
46 # define PROFILE_START(name) int64_t profile_start_##name = mdate()
47 # define PROFILE_STOP(name) fprintf( stderr, #name ": %f ms\n", (mdate() - profile_start_##name)/1000.0f )
49 # define PROFILE_START(name) ((void)0)
50 # define PROFILE_STOP(name) ((void)0)
53 #define CHECK_TIGER_RET( statement ) \
56 int i_ret = (statement); \
59 msg_Dbg( p_dec, "Error in " #statement ": %d", i_ret ); \
63 /*****************************************************************************
64 * decoder_sys_t : decoder descriptor
65 *****************************************************************************/
68 #ifdef ENABLE_PACKETIZER
92 /* decoder_sys_t is shared between decoder and spu units */
100 tiger_renderer *p_tr;
103 uint32_t i_tiger_default_font_color;
104 uint32_t i_tiger_default_background_color;
105 tiger_font_effect e_tiger_default_font_effect;
106 double f_tiger_default_font_effect_strength;
107 char *psz_tiger_default_font_desc;
108 double f_tiger_quality;
118 struct subpicture_updater_sys_t
120 decoder_sys_t *p_dec_sys;
126 * This is a global list of existing decoders.
127 * The reason for this list is that:
128 * - I want to be able to reconfigure Tiger when user prefs change
129 * - User prefs are variables which are not specific to a decoder (eg, if
130 * there are several decoders, there will still be one set of variables)
131 * - A callback set on those will not be passed a pointer to the decoder
132 * (as the decoder isn't known, and there could be multiple ones)
133 * - Creating variables in the decoder will create different ones, with
134 * values copied from the relevant user pref, so a callback on those
135 * won't be called when the user pref is changed
136 * Therefore, each decoder will register/unregister itself with this list,
137 * callbacks will be set for the user prefs, and these will in turn walk
138 * through this list and tell each decoder to update the relevant variable.
140 * VLC's variable system is still in my way as I can't get the value of
141 * the user pref variables at decoder start *unless* I create my own vars
142 * which inherit from the user ones, but those are utterly useless after
143 * that first use, since they'll be detached from the ones the user can
144 * change. So, I create them, read their values, and then destroy them.
146 static vlc_mutex_t kate_decoder_list_mutex = VLC_STATIC_MUTEX;
147 static size_t kate_decoder_list_size = 0;
148 static decoder_t **kate_decoder_list = NULL;
150 /*****************************************************************************
152 *****************************************************************************/
153 static int OpenDecoder ( vlc_object_t * );
154 static void CloseDecoder ( vlc_object_t * );
155 #ifdef ENABLE_PACKETIZER
156 static int OpenPacketizer( vlc_object_t *p_this );
159 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block );
160 static int ProcessHeaders( decoder_t *p_dec );
161 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
162 block_t **pp_block );
163 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp,
165 static void ParseKateComments( decoder_t * );
166 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
167 const kate_event *ev );
168 static void DecSysRelease( decoder_sys_t *p_sys );
169 static void DecSysHold( decoder_sys_t *p_sys );
171 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix );
172 static char *GetTigerString( decoder_t *p_dec, const char *psz_name );
173 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name );
174 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name );
175 static void UpdateTigerFontColor( decoder_t *p_dec );
176 static void UpdateTigerBackgroundColor( decoder_t *p_dec );
177 static void UpdateTigerFontEffect( decoder_t *p_dec );
178 static void UpdateTigerQuality( decoder_t *p_dec );
179 static void UpdateTigerFontDesc( decoder_t *p_dec );
180 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
181 vlc_value_t oldvar, vlc_value_t newval,
183 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
184 vlc_value_t oldval, vlc_value_t newval);
187 #define DEFAULT_NAME "Default"
188 #define MAX_LINE 8192
190 /*****************************************************************************
192 *****************************************************************************/
194 #define FORMAT_TEXT N_("Formatted Subtitles")
195 #define FORMAT_LONGTEXT N_("Kate streams allow for text formatting. " \
196 "VLC partly implements this, but you can choose to disable all formatting." \
197 "Note that this has no effect is rendering via Tiger is enabled.")
201 static const tiger_font_effect pi_font_effects[] = { tiger_font_plain, tiger_font_shadow, tiger_font_outline };
202 static const char * const ppsz_font_effect_names[] = { N_("None"), N_("Shadow"), N_("Outline") };
204 /* nicked off freetype.c */
205 static const int pi_color_values[] = {
206 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000,
207 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080,
208 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF };
209 static const char *const ppsz_color_descriptions[] = {
210 N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"),
211 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"),
212 N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") };
214 #define TIGER_TEXT N_("Use Tiger for rendering")
215 #define TIGER_LONGTEXT N_("Kate streams can be rendered using the Tiger library. " \
216 "Disabling this will only render static text and bitmap based streams.")
218 #define TIGER_QUALITY_DEFAULT 1.0
219 #define TIGER_QUALITY_TEXT N_("Rendering quality")
220 #define TIGER_QUALITY_LONGTEXT N_("Select rendering quality, at the expense of speed. " \
221 "0 is fastest, 1 is highest quality.")
223 #define TIGER_DEFAULT_FONT_EFFECT_DEFAULT 0
224 #define TIGER_DEFAULT_FONT_EFFECT_TEXT N_("Default font effect")
225 #define TIGER_DEFAULT_FONT_EFFECT_LONGTEXT N_("Add a font effect to text to improve readability " \
226 "against different backgrounds.")
228 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT 0.5
229 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT N_("Default font effect strength")
230 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT N_("How pronounced to make the chosen font effect " \
231 "(effect dependent).")
233 #define TIGER_DEFAULT_FONT_DESC_DEFAULT ""
234 #define TIGER_DEFAULT_FONT_DESC_TEXT N_("Default font description")
235 #define TIGER_DEFAULT_FONT_DESC_LONGTEXT N_("Which font description to use if the Kate stream " \
236 "does not specify particular font parameters (name, size, etc) to use. " \
237 "A blank name will let Tiger choose font parameters where appropriate.")
239 #define TIGER_DEFAULT_FONT_COLOR_DEFAULT 0x00ffffff
240 #define TIGER_DEFAULT_FONT_COLOR_TEXT N_("Default font color")
241 #define TIGER_DEFAULT_FONT_COLOR_LONGTEXT N_("Default font color to use if the Kate stream " \
242 "does not specify a particular font color to use.")
244 #define TIGER_DEFAULT_FONT_ALPHA_DEFAULT 0xff
245 #define TIGER_DEFAULT_FONT_ALPHA_TEXT N_("Default font alpha")
246 #define TIGER_DEFAULT_FONT_ALPHA_LONGTEXT N_("Transparency of the default font color if the Kate stream " \
247 "does not specify a particular font color to use.")
249 #define TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT 0x00ffffff
250 #define TIGER_DEFAULT_BACKGROUND_COLOR_TEXT N_("Default background color")
251 #define TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT N_("Default background color if the Kate stream " \
252 "does not specify a background color to use.")
254 #define TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT 0
255 #define TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT N_("Default background alpha")
256 #define TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT N_("Transparency of the default background color if the Kate stream " \
257 "does not specify a particular background color to use.")
261 #define HELP_TEXT N_( \
262 "Kate is a codec for text and image based overlays.\n" \
263 "The Tiger rendering library is needed to render complex Kate streams, " \
264 "but VLC can still render static text and image based subtitles if " \
265 "it is not available.\n" \
266 "Note that changing settings below will not take effect until a new stream is played. " \
267 "This will hopefully be fixed soon." \
271 set_shortname( N_("Kate"))
272 set_description( N_("Kate overlay decoder") )
273 set_help( HELP_TEXT )
274 set_capability( "decoder", 50 )
275 set_callbacks( OpenDecoder, CloseDecoder )
276 set_category( CAT_INPUT )
277 set_subcategory( SUBCAT_INPUT_SCODEC )
278 add_shortcut( "kate" )
280 add_bool( "kate-formatted", true, FORMAT_TEXT, FORMAT_LONGTEXT,
284 add_bool( "kate-use-tiger", true, TIGER_TEXT, TIGER_LONGTEXT,
286 add_float_with_range( "kate-tiger-quality",
287 TIGER_QUALITY_DEFAULT, 0.0f, 1.0f,
288 TIGER_QUALITY_TEXT, TIGER_QUALITY_LONGTEXT,
291 set_section( N_("Tiger rendering defaults"), NULL );
292 add_string( "kate-tiger-default-font-desc", TIGER_DEFAULT_FONT_DESC_DEFAULT,
293 TIGER_DEFAULT_FONT_DESC_TEXT, TIGER_DEFAULT_FONT_DESC_LONGTEXT, true);
294 add_integer_with_range( "kate-tiger-default-font-effect",
295 TIGER_DEFAULT_FONT_EFFECT_DEFAULT,
296 0, sizeof(pi_font_effects)/sizeof(pi_font_effects[0])-1,
297 TIGER_DEFAULT_FONT_EFFECT_TEXT, TIGER_DEFAULT_FONT_EFFECT_LONGTEXT,
299 change_integer_list( pi_font_effects, ppsz_font_effect_names );
300 add_float_with_range( "kate-tiger-default-font-effect-strength",
301 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT, 0.0f, 1.0f,
302 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT, TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT,
304 add_integer_with_range( "kate-tiger-default-font-color",
305 TIGER_DEFAULT_FONT_COLOR_DEFAULT, 0, 0x00ffffff,
306 TIGER_DEFAULT_FONT_COLOR_TEXT, TIGER_DEFAULT_FONT_COLOR_LONGTEXT,
308 change_integer_list( pi_color_values, ppsz_color_descriptions );
309 add_integer_with_range( "kate-tiger-default-font-alpha",
310 TIGER_DEFAULT_FONT_ALPHA_DEFAULT, 0, 255,
311 TIGER_DEFAULT_FONT_ALPHA_TEXT, TIGER_DEFAULT_FONT_ALPHA_LONGTEXT,
313 add_integer_with_range( "kate-tiger-default-background-color",
314 TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT, 0, 0x00ffffff,
315 TIGER_DEFAULT_BACKGROUND_COLOR_TEXT, TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT,
317 change_integer_list( pi_color_values, ppsz_color_descriptions );
318 add_integer_with_range( "kate-tiger-default-background-alpha",
319 TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT, 0, 255,
320 TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT, TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT,
324 #ifdef ENABLE_PACKETIZER
326 set_description( N_("Kate text subtitles packetizer") )
327 set_capability( "packetizer", 100 )
328 set_callbacks( OpenPacketizer, CloseDecoder )
329 add_shortcut( "kate" )
334 /*****************************************************************************
335 * OpenDecoder: probe the decoder and return score
336 *****************************************************************************
337 * Tries to launch a decoder and return score so that the interface is able
339 *****************************************************************************/
340 static int OpenDecoder( vlc_object_t *p_this )
342 decoder_t *p_dec = (decoder_t*)p_this;
343 decoder_sys_t *p_sys;
345 if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
350 msg_Dbg( p_dec, "kate: OpenDecoder");
353 p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
355 p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **))
358 /* Allocate the memory needed to store the decoder's structure */
359 if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
362 vlc_mutex_init( &p_sys->lock );
363 p_sys->i_refcount = 0;
367 #ifdef ENABLE_PACKETIZER
368 p_sys->b_packetizer = false;
370 p_sys->b_ready = false;
372 p_sys->i_max_stop = VLC_TS_INVALID;
374 kate_comment_init( &p_sys->kc );
375 kate_info_init( &p_sys->ki );
377 p_sys->b_has_headers = false;
379 /* retrieve options */
380 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
382 vlc_mutex_lock( &kate_decoder_list_mutex );
386 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
390 /* get initial value of configuration */
391 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
392 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
393 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
394 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
395 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
396 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
398 if( p_sys->b_use_tiger )
400 int i_ret = tiger_renderer_create( &p_sys->p_tr );
403 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
405 p_sys->b_use_tiger = false;
408 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
410 UpdateTigerFontEffect( p_dec );
411 UpdateTigerFontColor( p_dec );
412 UpdateTigerBackgroundColor( p_dec );
413 UpdateTigerQuality( p_dec );
414 UpdateTigerFontDesc( p_dec );
420 p_sys->b_use_tiger = false;
424 es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );
426 /* add the decoder to the global list */
427 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
430 list[ kate_decoder_list_size++ ] = p_dec;
431 kate_decoder_list = list;
434 vlc_mutex_unlock( &kate_decoder_list_mutex );
439 #ifdef ENABLE_PACKETIZER
440 static int OpenPacketizer( vlc_object_t *p_this )
442 decoder_t *p_dec = (decoder_t*)p_this;
444 int i_ret = OpenDecoder( p_this );
446 if( i_ret == VLC_SUCCESS )
448 p_dec->p_sys->b_packetizer = true;
449 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
456 /****************************************************************************
457 * DecodeBlock: the whole thing
458 ****************************************************************************
459 * This function must be fed with kate packets.
460 ****************************************************************************/
461 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
463 decoder_sys_t *p_sys = p_dec->p_sys;
467 if( !pp_block || !*pp_block )
472 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
475 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
477 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
478 vlc_mutex_lock( &p_sys->lock );
479 tiger_renderer_seek( p_sys->p_tr, 0 );
480 vlc_mutex_unlock( &p_sys->lock );
483 p_sys->i_max_stop = VLC_TS_INVALID;
484 block_Release( p_block );
488 /* Block to Kate packet */
489 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
491 if( !p_sys->b_has_headers )
493 if( ProcessHeaders( p_dec ) )
495 block_Release( *pp_block );
498 p_sys->b_has_headers = true;
501 return ProcessPacket( p_dec, &kp, pp_block );
504 /*****************************************************************************
505 * ProcessHeaders: process Kate headers.
506 *****************************************************************************/
507 static int ProcessHeaders( decoder_t *p_dec )
509 decoder_sys_t *p_sys = p_dec->p_sys;
512 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
513 void *pp_data[XIPH_MAX_HEADER_COUNT];
515 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
516 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
522 /* Take care of the initial Kate header */
523 kp.nbytes = pi_size[0];
524 kp.data = pp_data[0];
525 int i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
528 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
532 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
533 p_sys->ki.language, p_sys->ki.category,
534 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
535 p_sys->ki.granule_shift);
537 /* parse all remaining header packets */
538 for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
540 kp.nbytes = pi_size[i_headeridx];
541 kp.data = pp_data[i_headeridx];
542 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
545 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
549 /* header 1 is comments */
550 if( i_headeridx == 1 )
552 ParseKateComments( p_dec );
556 #ifdef ENABLE_PACKETIZER
557 if( !p_sys->b_packetizer )
560 /* We have all the headers, initialize decoder */
561 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
562 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
565 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
568 p_sys->b_ready = true;
570 #ifdef ENABLE_PACKETIZER
573 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
574 p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
575 p_dec->fmt_out.i_extra );
576 memcpy( p_dec->fmt_out.p_extra,
577 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
584 /*****************************************************************************
585 * ProcessPacket: processes a kate packet.
586 *****************************************************************************/
587 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
590 decoder_sys_t *p_sys = p_dec->p_sys;
591 block_t *p_block = *pp_block;
592 subpicture_t *p_buf = NULL;
594 /* Date management */
595 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
597 p_sys->i_pts = p_block->i_pts;
600 *pp_block = NULL; /* To avoid being fed the same packet again */
602 #ifdef ENABLE_PACKETIZER
603 if( p_sys->b_packetizer )
605 /* Date management */
606 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
608 if( p_sys->i_headers >= p_sys->i_num_headers )
609 p_block->i_length = p_sys->i_pts - p_block->i_pts;
611 p_block->i_length = 0;
618 p_buf = DecodePacket( p_dec, p_kp, p_block );
621 block_Release( p_block );
627 /* nicked off blend.c */
628 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
629 int r, int g, int b )
631 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
632 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
633 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
637 This retrieves the size of the video.
638 The best case is when the original video size is known, as we can then
639 scale images to match. In this case, since VLC autoscales, we want to
640 return the original size and let VLC scale everything.
641 if the original size is not known, then VLC can't resize, so we return
642 the size of the incoming video. If sizes in the Kate stream are in
643 relative units, it works fine. If they are absolute, you get what you
644 ask for. Images aren't rescaled.
646 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
648 /* searching for vout to get its size is frowned upon, so we don't and
649 use a default size if the original canvas size is not specified. */
650 decoder_sys_t *p_sys = p_dec->p_sys;
651 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
653 *w = p_sys->ki.original_canvas_width;
654 *h = p_sys->ki.original_canvas_height;
655 msg_Dbg( p_dec, "original canvas %zu %zu",
656 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
660 /* nothing, leave defaults */
661 msg_Dbg( p_dec, "original canvas size unknown");
665 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
669 for( y=0; y<bitmap->height; ++y )
671 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
672 const uint8_t *src = bitmap->pixels+y*bitmap->width;
673 memcpy( dest, src, bitmap->width );
677 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
681 fmt_palette->i_entries = palette->ncolors;
682 for( n=0; n<palette->ncolors; ++n )
685 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
686 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
688 fmt_palette->palette[n][3] = palette->colors[n].a;
692 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
694 decoder_sys_t *p_sys = p_dec->p_sys;
696 if( ev->text_encoding != kate_utf8 )
698 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
702 switch( ev->text_markup_type )
704 case kate_markup_none:
705 p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
707 case kate_markup_simple:
708 if( p_sys->b_formatted )
710 /* the HTML renderer expects a top level text tag pair */
712 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
714 p_spu->p_region->psz_html = buffer;
718 /* if not formatted, we fall through */
720 /* we don't know about this one, so remove markup and display as text */
722 char *copy = strdup( ev->text );
723 size_t len0 = strlen( copy ) + 1;
724 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
725 p_spu->p_region->psz_text = copy;
733 static void TigerDestroySubpicture( subpicture_t *p_subpic )
735 DecSysRelease( p_subpic->updater.p_sys->p_dec_sys );
736 free( p_subpic->updater.p_sys );
739 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
740 * alpha to avoid double multiply (and thus thinner text than we should)).
741 * Best would be to have VLC be able to handle premultiplied alpha, as it
742 * would be faster to blend as well.
744 * Also, we flip color components around for big endian machines, as Tiger
745 * outputs ARGB or ABGR (the one we selected here) in host endianness.
747 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
749 PROFILE_START( tiger_renderer_postprocess );
751 for( y=0; y<p_plane->i_lines; ++y )
753 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
755 for( x=0; x<i_width; ++x )
757 uint8_t *p_pixel = p_line+x*4;
758 #ifdef WORDS_BIGENDIAN
759 uint8_t a = p_pixel[0];
761 uint8_t a = p_pixel[3];
765 #ifdef WORDS_BIGENDIAN
766 uint8_t tmp = p_pixel[2];
767 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
769 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
770 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
772 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
773 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
774 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
786 PROFILE_STOP( tiger_renderer_postprocess );
789 static int TigerValidateSubpicture( subpicture_t *p_subpic,
790 bool b_fmt_src, const video_format_t *p_fmt_src,
791 bool b_fmt_dst, const video_format_t *p_fmt_dst,
794 VLC_UNUSED(p_fmt_src); VLC_UNUSED(p_fmt_dst);
796 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
798 if( b_fmt_src || b_fmt_dst )
801 PROFILE_START( TigerValidateSubpicture );
803 /* time in seconds from the start of the stream */
804 kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
806 /* it is likely that the current region (if any) can be kept as is; test for this */
807 vlc_mutex_lock( &p_sys->lock );
809 if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
811 i_ret = VLC_EGENERIC;
814 if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
815 tiger_renderer_is_dirty( p_sys->p_tr ) )
817 i_ret = VLC_EGENERIC;
823 vlc_mutex_unlock( &p_sys->lock );
824 PROFILE_STOP( TigerValidateSubpicture );
828 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
829 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
830 Looks good with white though since it's all luma. Hopefully that will be the
832 static void TigerUpdateSubpicture( subpicture_t *p_subpic,
833 const video_format_t *p_fmt_src,
834 const video_format_t *p_fmt_dst,
837 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
843 /* time in seconds from the start of the stream */
844 t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
846 PROFILE_START( TigerUpdateSubpicture );
848 /* create a full frame region - this will also tell Tiger the size of the frame */
849 video_format_t fmt = *p_fmt_dst;
850 fmt.i_chroma = VLC_CODEC_RGBA;
851 fmt.i_bits_per_pixel = 0;
853 fmt.i_visible_width = p_fmt_src->i_width;
855 fmt.i_visible_height = p_fmt_src->i_height;
856 fmt.i_x_offset = fmt.i_y_offset = 0;
858 subpicture_region_t *p_r = subpicture_region_New( &fmt );
864 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
866 vlc_mutex_lock( &p_sys->lock );
868 p_plane = &p_r->p_picture->p[0];
869 i_ret = tiger_renderer_set_buffer( p_sys->p_tr, p_plane->p_pixels, fmt.i_width, p_plane->i_lines, p_plane->i_pitch, 1 );
875 PROFILE_START( tiger_renderer_update );
876 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
881 PROFILE_STOP( tiger_renderer_update );
883 PROFILE_START( tiger_renderer_render );
884 i_ret = tiger_renderer_render( p_sys->p_tr );
889 PROFILE_STOP( tiger_renderer_render );
891 PostprocessTigerImage( p_plane, fmt.i_width );
892 p_subpic->p_region = p_r;
893 p_sys->b_dirty = false;
895 PROFILE_STOP( TigerUpdateSubpicture );
897 vlc_mutex_unlock( &p_sys->lock );
902 vlc_mutex_unlock( &p_sys->lock );
903 subpicture_region_ChainDelete( p_r );
906 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
909 uint32_t i_color = 0;
911 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
913 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
914 var_Destroy( p_dec, psz_tmp );
919 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
921 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
922 var_Destroy( p_dec, psz_tmp );
924 i_color |= (i_alpha << 24);
930 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
932 char *psz_value = var_CreateGetString( p_dec, psz_name );
935 psz_value = strdup( psz_value );
937 var_Destroy( p_dec, psz_name );
941 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
943 int i_value = var_CreateGetInteger( p_dec, psz_name );
944 var_Destroy( p_dec, psz_name );
948 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
950 double f_value = var_CreateGetFloat( p_dec, psz_name );
951 var_Destroy( p_dec, psz_name );
955 static void UpdateTigerQuality( decoder_t *p_dec )
957 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
958 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
959 p_sys->b_dirty = true;
962 static void UpdateTigerFontDesc( decoder_t *p_dec )
964 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
965 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
966 p_sys->b_dirty = true;
969 static void UpdateTigerFontColor( decoder_t *p_dec )
971 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
972 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
973 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
974 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
975 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
976 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
977 p_sys->b_dirty = true;
980 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
982 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
983 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
984 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
985 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
986 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
987 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
988 p_sys->b_dirty = true;
991 static void UpdateTigerFontEffect( decoder_t *p_dec )
993 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
994 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
995 p_sys->e_tiger_default_font_effect,
996 p_sys->f_tiger_default_font_effect_strength ) );
997 p_sys->b_dirty = true;
1000 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1001 vlc_value_t oldval, vlc_value_t newval )
1003 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1005 VLC_UNUSED( oldval );
1007 vlc_mutex_lock( &p_sys->lock );
1009 msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1011 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1013 vlc_mutex_unlock( &p_sys->lock );
1017 #define TEST_TIGER_VAR( name ) \
1018 if( !strcmp( name, psz_var ) )
1020 TEST_TIGER_VAR( "kate-tiger-quality" )
1022 p_sys->f_tiger_quality = newval.f_float;
1023 UpdateTigerQuality( p_dec );
1026 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1028 if( p_sys->psz_tiger_default_font_desc )
1030 free( p_sys->psz_tiger_default_font_desc );
1031 p_sys->psz_tiger_default_font_desc = NULL;
1033 if( newval.psz_string )
1035 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1037 UpdateTigerFontDesc( p_dec );
1040 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1042 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1043 UpdateTigerFontColor( p_dec );
1046 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1048 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1049 UpdateTigerFontColor( p_dec );
1052 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1054 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1055 UpdateTigerBackgroundColor( p_dec );
1058 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1060 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1061 UpdateTigerBackgroundColor( p_dec );
1064 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1066 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1067 UpdateTigerFontEffect( p_dec );
1070 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1072 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1073 UpdateTigerFontEffect( p_dec );
1076 #undef TEST_TIGER_VAR
1078 vlc_mutex_unlock( &p_sys->lock );
1083 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1084 vlc_value_t oldval, vlc_value_t newval,
1089 VLC_UNUSED( p_this );
1090 VLC_UNUSED( oldval );
1091 VLC_UNUSED( newval );
1092 VLC_UNUSED( p_data );
1094 vlc_mutex_lock( &kate_decoder_list_mutex );
1096 /* Update all existing decoders from the global user prefs */
1097 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1099 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1100 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1103 vlc_mutex_unlock( &kate_decoder_list_mutex );
1110 /*****************************************************************************
1111 * DecodePacket: decodes a Kate packet.
1112 *****************************************************************************/
1113 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1115 decoder_sys_t *p_sys = p_dec->p_sys;
1116 const kate_event *ev = NULL;
1117 subpicture_t *p_spu = NULL;
1120 if( !p_sys->b_ready )
1122 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1126 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1129 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1133 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1136 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1141 /* no event to go with this packet, this is normal */
1145 /* we have an event */
1148 subpicture_updater_sys_t *p_spu_sys = NULL;
1149 if( p_sys->b_use_tiger)
1151 p_spu_sys = malloc( sizeof(*p_spu_sys) );
1155 subpicture_updater_t updater = {
1157 .pf_validate = TigerValidateSubpicture,
1158 .pf_update = TigerUpdateSubpicture,
1159 .pf_destroy = TigerDestroySubpicture,
1163 p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1167 /* this will happen for lyrics as there is no vout - so no error */
1168 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1172 p_spu->i_start = p_block->i_pts;
1173 p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1174 p_spu->b_ephemer = false;
1175 p_spu->b_absolute = false;
1178 if( p_sys->b_use_tiger)
1180 p_spu_sys->p_dec_sys = p_sys;
1181 p_spu_sys->i_start = p_block->i_pts;
1182 DecSysHold( p_sys );
1184 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1185 p_spu->b_ephemer = true;
1186 p_spu->b_absolute = true;
1188 /* add the event to tiger */
1189 vlc_mutex_lock( &p_sys->lock );
1190 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1191 vlc_mutex_unlock( &p_sys->lock );
1196 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1202 /*****************************************************************************
1203 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1204 *****************************************************************************/
1205 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1206 const kate_event *ev )
1208 decoder_sys_t *p_sys = p_dec->p_sys;
1210 subpicture_region_t *p_bitmap_region = NULL;
1211 video_palette_t palette;
1213 bool b_tracker_valid = false;
1216 /* these may be 0 for "not specified" */
1217 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1218 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1220 /* Create a new subpicture region */
1221 memset( &fmt, 0, sizeof(video_format_t) );
1223 if (p_sys->b_formatted)
1225 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1228 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1232 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1233 GetVideoSize(p_dec, &w, &h);
1234 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1237 kate_tracker_clear(&kin);
1238 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1242 // TODO: parse tracker and set style, init fmt
1243 b_tracker_valid = true;
1248 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1250 /* create a separate region for the bitmap */
1251 memset( &fmt, 0, sizeof(video_format_t) );
1252 fmt.i_chroma = VLC_CODEC_YUVP;
1253 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1254 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1255 fmt.i_x_offset = fmt.i_y_offset = 0;
1256 fmt.p_palette = &palette;
1257 CreateKatePalette( fmt.p_palette, ev->palette );
1259 p_bitmap_region = subpicture_region_New( &fmt );
1260 if( !p_bitmap_region )
1262 msg_Err( p_dec, "cannot allocate SPU region" );
1263 decoder_DeleteSubpicture( p_dec, p_spu );
1267 /* create the bitmap */
1268 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1270 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1274 fmt.i_chroma = VLC_CODEC_TEXT;
1277 fmt.i_width = fmt.i_height = 0;
1278 fmt.i_x_offset = fmt.i_y_offset = 0;
1279 p_spu->p_region = subpicture_region_New( &fmt );
1280 if( !p_spu->p_region )
1282 msg_Err( p_dec, "cannot allocate SPU region" );
1283 if( p_bitmap_region )
1284 subpicture_region_Delete( p_bitmap_region );
1285 decoder_DeleteSubpicture( p_dec, p_spu );
1289 SetupText( p_dec, p_spu, ev );
1291 /* default positioning */
1292 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1293 if (p_bitmap_region)
1295 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1297 p_spu->p_region->i_x = 0;
1298 p_spu->p_region->i_y = 10;
1300 /* override if tracker info present */
1301 if (b_tracker_valid)
1305 p_spu->p_region->i_x = kin.region_x;
1306 p_spu->p_region->i_y = kin.region_y;
1307 if (p_bitmap_region)
1309 p_bitmap_region->i_x = kin.region_x;
1310 p_bitmap_region->i_y = kin.region_y;
1312 p_spu->b_absolute = true;
1315 kate_tracker_clear(&kin);
1318 /* if we have a bitmap, chain it before the text */
1319 if (p_bitmap_region)
1321 p_bitmap_region->p_next = p_spu->p_region;
1322 p_spu->p_region = p_bitmap_region;
1328 /*****************************************************************************
1329 * ParseKateComments:
1330 *****************************************************************************/
1331 static void ParseKateComments( decoder_t *p_dec )
1333 char *psz_name, *psz_value, *psz_comment;
1336 while ( i < p_dec->p_sys->kc.comments )
1338 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1341 psz_name = psz_comment;
1342 psz_value = strchr( psz_comment, '=' );
1348 if( !p_dec->p_description )
1349 p_dec->p_description = vlc_meta_New();
1350 if( p_dec->p_description )
1351 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1353 free( psz_comment );
1358 /*****************************************************************************
1359 * CloseDecoder: clean up the decoder
1360 *****************************************************************************/
1361 static void CloseDecoder( vlc_object_t *p_this )
1363 decoder_t *p_dec = (decoder_t *)p_this;
1366 /* remove the decoder from the global list */
1367 vlc_mutex_lock( &kate_decoder_list_mutex );
1368 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1370 if( kate_decoder_list[ i_index ] == p_dec )
1372 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1376 vlc_mutex_unlock( &kate_decoder_list_mutex );
1378 msg_Dbg( p_dec, "Closing Kate decoder" );
1379 DecSysRelease( p_dec->p_sys );
1382 static void DecSysHold( decoder_sys_t *p_sys )
1384 vlc_mutex_lock( &p_sys->lock );
1385 p_sys->i_refcount++;
1386 vlc_mutex_unlock( &p_sys->lock );
1389 static void DecSysRelease( decoder_sys_t *p_sys )
1391 vlc_mutex_lock( &p_sys->lock );
1392 p_sys->i_refcount--;
1393 if( p_sys->i_refcount > 0)
1395 vlc_mutex_unlock( &p_sys->lock );
1399 vlc_mutex_unlock( &p_sys->lock );
1400 vlc_mutex_destroy( &p_sys->lock );
1404 tiger_renderer_destroy( p_sys->p_tr );
1405 free( p_sys->psz_tiger_default_font_desc );
1409 kate_clear( &p_sys->k );
1410 kate_info_clear( &p_sys->ki );
1411 kate_comment_clear( &p_sys->kc );