]> git.sesse.net Git - vlc/blob - modules/codec/kate.c
skins2: simplify equalizer initialization
[vlc] / modules / codec / kate.c
1 /*****************************************************************************
2  * kate.c : a decoder for the kate bitstream format
3  *****************************************************************************
4  * Copyright (C) 2000-2008 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
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"
36
37 #include <kate/kate.h>
38 #ifdef HAVE_TIGER
39 # include <tiger/tiger.h>
40 #endif
41
42 /* #define ENABLE_PACKETIZER */
43 /* #define ENABLE_PROFILE */
44
45 #ifdef 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 )
48 #else
49 # define PROFILE_START(name) ((void)0)
50 # define PROFILE_STOP(name) ((void)0)
51 #endif
52
53 #define CHECK_TIGER_RET( statement )                                   \
54     do                                                                 \
55     {                                                                  \
56         int i_ret = (statement);                                       \
57         if( i_ret < 0 )                                                \
58         {                                                              \
59             msg_Dbg( p_dec, "Error in " #statement ": %d", i_ret );    \
60         }                                                              \
61     } while( 0 )
62
63 /*****************************************************************************
64  * decoder_sys_t : decoder descriptor
65  *****************************************************************************/
66 struct decoder_sys_t
67 {
68 #ifdef ENABLE_PACKETIZER
69     /* Module mode */
70     bool b_packetizer;
71 #endif
72
73     /*
74      * Input properties
75      */
76     bool b_has_headers;
77
78     /*
79      * Kate properties
80      */
81     bool           b_ready;
82     kate_info      ki;
83     kate_comment   kc;
84     kate_state     k;
85
86     /*
87      * Common properties
88      */
89     mtime_t i_pts;
90     mtime_t i_max_stop;
91
92     /* decoder_sys_t is shared between decoder and spu units */
93     vlc_mutex_t lock;
94     int         i_refcount;
95
96 #ifdef HAVE_TIGER
97     /*
98      * Tiger properties
99      */
100     tiger_renderer    *p_tr;
101     bool               b_dirty;
102
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;
109 #endif
110
111     /*
112      * Options
113      */
114     bool   b_formatted;
115     bool   b_use_tiger;
116 };
117
118 struct subpicture_updater_sys_t
119 {
120     decoder_sys_t *p_dec_sys;
121     mtime_t        i_start;
122 };
123
124
125 /*
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.
139  * HOWEVER.
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.
145  */
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;
149
150 /*****************************************************************************
151  * Local prototypes
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 );
157 #endif
158
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,
164                             block_t *p_block );
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 );
170 #ifdef HAVE_TIGER
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,
182                                        void *p_data );
183 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
184                                    vlc_value_t oldval, vlc_value_t newval);
185 #endif
186
187 #define DEFAULT_NAME "Default"
188 #define MAX_LINE 8192
189
190 /*****************************************************************************
191  * Module descriptor.
192  *****************************************************************************/
193
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.")
198
199 #ifdef HAVE_TIGER
200
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") };
203
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") };
213
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.")
217
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.")
222
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.")
227
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).")
232
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.")
238
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.")
243
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.")
248
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.")
253
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.")
258
259 #endif
260
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." \
268     )
269
270 vlc_module_begin ()
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" )
279
280     add_bool( "kate-formatted", true, FORMAT_TEXT, FORMAT_LONGTEXT,
281               true )
282
283 #ifdef HAVE_TIGER
284     add_bool( "kate-use-tiger", true, TIGER_TEXT, TIGER_LONGTEXT,
285               true )
286     add_float_with_range( "kate-tiger-quality",
287                           TIGER_QUALITY_DEFAULT, 0.0f, 1.0f,
288                           TIGER_QUALITY_TEXT, TIGER_QUALITY_LONGTEXT,
289                           true )
290
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,
298                             true )
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,
303               true )
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,
307                             true);
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,
312                             true);
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,
316                             true);
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,
321                             true);
322 #endif
323
324 #ifdef ENABLE_PACKETIZER
325     add_submodule ()
326     set_description( N_("Kate text subtitles packetizer") )
327     set_capability( "packetizer", 100 )
328     set_callbacks( OpenPacketizer, CloseDecoder )
329     add_shortcut( "kate" )
330 #endif
331
332 vlc_module_end ()
333
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
338  * to chose.
339  *****************************************************************************/
340 static int OpenDecoder( vlc_object_t *p_this )
341 {
342     decoder_t     *p_dec = (decoder_t*)p_this;
343     decoder_sys_t *p_sys;
344
345     if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
346     {
347         return VLC_EGENERIC;
348     }
349
350     msg_Dbg( p_dec, "kate: OpenDecoder");
351
352     /* Set callbacks */
353     p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
354         DecodeBlock;
355     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
356         DecodeBlock;
357
358     /* Allocate the memory needed to store the decoder's structure */
359     if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
360         return VLC_ENOMEM;
361
362     vlc_mutex_init( &p_sys->lock );
363     p_sys->i_refcount = 0;
364     DecSysHold( p_sys );
365
366     /* init of p_sys */
367 #ifdef ENABLE_PACKETIZER
368     p_sys->b_packetizer = false;
369 #endif
370     p_sys->b_ready = false;
371     p_sys->i_pts =
372     p_sys->i_max_stop = VLC_TS_INVALID;
373
374     kate_comment_init( &p_sys->kc );
375     kate_info_init( &p_sys->ki );
376
377     p_sys->b_has_headers = false;
378
379     /* retrieve options */
380     p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
381
382     vlc_mutex_lock( &kate_decoder_list_mutex );
383
384 #ifdef HAVE_TIGER
385
386     p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
387
388     p_sys->p_tr = NULL;
389
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" );
397
398     if( p_sys->b_use_tiger )
399     {
400         int i_ret = tiger_renderer_create( &p_sys->p_tr );
401         if( i_ret < 0 )
402         {
403             msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
404             p_sys->p_tr = NULL;
405             p_sys->b_use_tiger = false;
406         }
407         else {
408             CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
409
410             UpdateTigerFontEffect( p_dec );
411             UpdateTigerFontColor( p_dec );
412             UpdateTigerBackgroundColor( p_dec );
413             UpdateTigerQuality( p_dec );
414             UpdateTigerFontDesc( p_dec );
415         }
416     }
417
418 #else
419
420     p_sys->b_use_tiger = false;
421
422 #endif
423
424     es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );
425
426     /* add the decoder to the global list */
427     decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
428     if( list )
429     {
430         list[ kate_decoder_list_size++ ] = p_dec;
431         kate_decoder_list = list;
432     }
433
434     vlc_mutex_unlock( &kate_decoder_list_mutex );
435
436     return VLC_SUCCESS;
437 }
438
439 #ifdef ENABLE_PACKETIZER
440 static int OpenPacketizer( vlc_object_t *p_this )
441 {
442     decoder_t *p_dec = (decoder_t*)p_this;
443
444     int i_ret = OpenDecoder( p_this );
445
446     if( i_ret == VLC_SUCCESS )
447     {
448         p_dec->p_sys->b_packetizer = true;
449         p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
450     }
451
452     return i_ret;
453 }
454 #endif
455
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 )
462 {
463     decoder_sys_t *p_sys = p_dec->p_sys;
464     block_t *p_block;
465     kate_packet kp;
466
467     if( !pp_block || !*pp_block )
468         return NULL;
469
470     p_block = *pp_block;
471
472     if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
473     {
474 #ifdef HAVE_TIGER
475         if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
476         {
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 );
481         }
482 #endif
483         p_sys->i_max_stop = VLC_TS_INVALID;
484         block_Release( p_block );
485         return NULL;
486     }
487
488     /* Block to Kate packet */
489     kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
490
491     if( !p_sys->b_has_headers )
492     {
493         if( ProcessHeaders( p_dec ) )
494         {
495             block_Release( *pp_block );
496             return NULL;
497         }
498         p_sys->b_has_headers = true;
499     }
500
501     return ProcessPacket( p_dec, &kp, pp_block );
502 }
503
504 /*****************************************************************************
505  * ProcessHeaders: process Kate headers.
506  *****************************************************************************/
507 static int ProcessHeaders( decoder_t *p_dec )
508 {
509     decoder_sys_t *p_sys = p_dec->p_sys;
510     kate_packet kp;
511
512     unsigned pi_size[XIPH_MAX_HEADER_COUNT];
513     void     *pp_data[XIPH_MAX_HEADER_COUNT];
514     unsigned i_count;
515     if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
516                            p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
517         return VLC_EGENERIC;
518     int i_ret = VLC_SUCCESS;
519     if( i_count < 1 )
520     {
521         i_ret = VLC_EGENERIC;
522         goto end;
523     }
524
525     /* Take care of the initial Kate header */
526     kp.nbytes = pi_size[0];
527     kp.data   = pp_data[0];
528     i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
529     if( i_ret < 0 )
530     {
531         msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
532         goto end;
533     }
534
535     msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
536              p_sys->ki.language, p_sys->ki.category,
537              (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
538              p_sys->ki.granule_shift);
539
540     /* parse all remaining header packets */
541     for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
542     {
543         kp.nbytes = pi_size[i_headeridx];
544         kp.data   = pp_data[i_headeridx];
545         i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
546         if( i_ret < 0 )
547         {
548             msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
549             goto end;
550         }
551
552         /* header 1 is comments */
553         if( i_headeridx == 1 )
554         {
555             ParseKateComments( p_dec );
556         }
557     }
558
559 #ifdef ENABLE_PACKETIZER
560     if( !p_sys->b_packetizer )
561 #endif
562     {
563         /* We have all the headers, initialize decoder */
564         msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
565         i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
566         if (i_ret < 0)
567         {
568             msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
569             return VLC_EGENERIC;
570         }
571         p_sys->b_ready = true;
572     }
573 #ifdef ENABLE_PACKETIZER
574     else
575     {
576         p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
577         p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
578                                                   p_dec->fmt_out.i_extra );
579         memcpy( p_dec->fmt_out.p_extra,
580                 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
581     }
582 #endif
583
584 end:
585     for( unsigned i = 0; i < i_count; i++ )
586         free( pp_data[i] );
587     return i_ret < 0 ? VLC_EGENERIC : VLC_SUCCESS;
588 }
589
590 /*****************************************************************************
591  * ProcessPacket: processes a kate packet.
592  *****************************************************************************/
593 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
594                             block_t **pp_block )
595 {
596     decoder_sys_t *p_sys = p_dec->p_sys;
597     block_t *p_block = *pp_block;
598     subpicture_t *p_buf = NULL;
599
600     /* Date management */
601     if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
602     {
603         p_sys->i_pts = p_block->i_pts;
604     }
605
606     *pp_block = NULL; /* To avoid being fed the same packet again */
607
608 #ifdef ENABLE_PACKETIZER
609     if( p_sys->b_packetizer )
610     {
611         /* Date management */
612         p_block->i_dts = p_block->i_pts = p_sys->i_pts;
613
614         if( p_sys->i_headers >= p_sys->i_num_headers )
615             p_block->i_length = p_sys->i_pts - p_block->i_pts;
616         else
617             p_block->i_length = 0;
618
619         p_buf = p_block;
620     }
621     else
622 #endif
623     {
624         p_buf = DecodePacket( p_dec, p_kp, p_block );
625
626         if( p_block )
627             block_Release( p_block );
628     }
629
630     return p_buf;
631 }
632
633 /* nicked off blend.c */
634 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
635                                int r, int g, int b )
636 {
637     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
638     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
639     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
640 }
641
642 /*
643   This retrieves the size of the video.
644   The best case is when the original video size is known, as we can then
645   scale images to match. In this case, since VLC autoscales, we want to
646   return the original size and let VLC scale everything.
647   if the original size is not known, then VLC can't resize, so we return
648   the size of the incoming video. If sizes in the Kate stream are in
649   relative units, it works fine. If they are absolute, you get what you
650   ask for. Images aren't rescaled.
651 */
652 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
653 {
654     /* searching for vout to get its size is frowned upon, so we don't and
655        use a default size if the original canvas size is not specified. */
656     decoder_sys_t *p_sys = p_dec->p_sys;
657     if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
658     {
659         *w = p_sys->ki.original_canvas_width;
660         *h = p_sys->ki.original_canvas_height;
661         msg_Dbg( p_dec, "original canvas %zu %zu",
662                  p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
663     }
664     else
665     {
666         /* nothing, leave defaults */
667         msg_Dbg( p_dec, "original canvas size unknown");
668     }
669 }
670
671 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
672 {
673     size_t y;
674
675     for( y=0; y<bitmap->height; ++y )
676     {
677         uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
678         const uint8_t *src = bitmap->pixels+y*bitmap->width;
679         memcpy( dest, src, bitmap->width );
680     }
681 }
682
683 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
684 {
685     size_t n;
686
687     fmt_palette->i_entries = palette->ncolors;
688     for( n=0; n<palette->ncolors; ++n )
689     {
690         rgb_to_yuv(
691             &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
692             palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
693         );
694         fmt_palette->palette[n][3] = palette->colors[n].a;
695     }
696 }
697
698 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
699 {
700     decoder_sys_t *p_sys = p_dec->p_sys;
701
702     if( ev->text_encoding != kate_utf8 )
703     {
704         msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
705         return;
706     }
707
708     switch( ev->text_markup_type )
709     {
710         case kate_markup_none:
711             p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
712             break;
713         case kate_markup_simple:
714             if( p_sys->b_formatted )
715             {
716                 /* the HTML renderer expects a top level text tag pair */
717                 char *buffer = NULL;
718                 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
719                 {
720                     p_spu->p_region->psz_html = buffer;
721                 }
722                 break;
723             }
724             /* if not formatted, we fall through */
725         default:
726             /* we don't know about this one, so remove markup and display as text */
727             {
728                 char *copy = strdup( ev->text );
729                 size_t len0 = strlen( copy ) + 1;
730                 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
731                 p_spu->p_region->psz_text = copy;
732             }
733             break;
734     }
735 }
736
737 #ifdef HAVE_TIGER
738
739 static void TigerDestroySubpicture( subpicture_t *p_subpic )
740 {
741     DecSysRelease( p_subpic->updater.p_sys->p_dec_sys );
742     free( p_subpic->updater.p_sys );
743 }
744 /*
745  * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
746  * alpha to avoid double multiply (and thus thinner text than we should)).
747  * Best would be to have VLC be able to handle premultiplied alpha, as it
748  * would be faster to blend as well.
749  *
750  * Also, we flip color components around for big endian machines, as Tiger
751  * outputs ARGB or ABGR (the one we selected here) in host endianness.
752  */
753 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
754 {
755     PROFILE_START( tiger_renderer_postprocess );
756     int y;
757     for( y=0; y<p_plane->i_lines; ++y )
758     {
759         uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
760         unsigned int x;
761         for( x=0; x<i_width; ++x )
762         {
763             uint8_t *p_pixel = p_line+x*4;
764 #ifdef WORDS_BIGENDIAN
765             uint8_t a = p_pixel[0];
766 #else
767             uint8_t a = p_pixel[3];
768 #endif
769             if( a )
770             {
771 #ifdef WORDS_BIGENDIAN
772                 uint8_t tmp = p_pixel[2];
773                 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
774                 p_pixel[3] = a;
775                 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
776                 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
777 #else
778                 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
779                 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
780                 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
781 #endif
782             }
783             else
784             {
785                 p_pixel[0] = 0;
786                 p_pixel[1] = 0;
787                 p_pixel[2] = 0;
788                 p_pixel[3] = 0;
789             }
790         }
791     }
792     PROFILE_STOP( tiger_renderer_postprocess );
793 }
794
795 static int TigerValidateSubpicture( subpicture_t *p_subpic,
796                                     bool b_fmt_src, const video_format_t *p_fmt_src,
797                                     bool b_fmt_dst, const video_format_t *p_fmt_dst,
798                                     mtime_t ts )
799 {
800     VLC_UNUSED(p_fmt_src); VLC_UNUSED(p_fmt_dst);
801
802     decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
803
804     if( b_fmt_src || b_fmt_dst )
805         return VLC_EGENERIC;
806
807     PROFILE_START( TigerValidateSubpicture );
808
809     /* time in seconds from the start of the stream */
810     kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
811
812     /* it is likely that the current region (if any) can be kept as is; test for this */
813     vlc_mutex_lock( &p_sys->lock );
814     int i_ret;
815     if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
816     {
817         i_ret = VLC_EGENERIC;
818         goto exit;
819     }
820     if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
821         tiger_renderer_is_dirty( p_sys->p_tr ) )
822     {
823         i_ret = VLC_EGENERIC;
824         goto exit;
825     }
826
827     i_ret = VLC_SUCCESS;
828 exit:
829     vlc_mutex_unlock( &p_sys->lock );
830     PROFILE_STOP( TigerValidateSubpicture );
831     return i_ret;
832 }
833
834 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
835    a subsampled YUV image, so there can be a fair amount of chroma bleeding.
836    Looks good with white though since it's all luma. Hopefully that will be the
837    common case. */
838 static void TigerUpdateSubpicture( subpicture_t *p_subpic,
839                                    const video_format_t *p_fmt_src,
840                                    const video_format_t *p_fmt_dst,
841                                    mtime_t ts )
842 {
843     decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
844     plane_t *p_plane;
845     kate_float t;
846     int i_ret;
847
848
849     /* time in seconds from the start of the stream */
850     t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
851
852     PROFILE_START( TigerUpdateSubpicture );
853
854     /* create a full frame region - this will also tell Tiger the size of the frame */
855     video_format_t fmt = *p_fmt_dst;
856     fmt.i_chroma         = VLC_CODEC_RGBA;
857     fmt.i_bits_per_pixel = 0;
858     fmt.i_width          =
859     fmt.i_visible_width  = p_fmt_src->i_width;
860     fmt.i_height         =
861     fmt.i_visible_height = p_fmt_src->i_height;
862     fmt.i_x_offset       = fmt.i_y_offset = 0;
863
864     subpicture_region_t *p_r = subpicture_region_New( &fmt );
865     if( !p_r )
866         return;
867
868     p_r->i_x = 0;
869     p_r->i_y = 0;
870     p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
871
872     vlc_mutex_lock( &p_sys->lock );
873
874     p_plane = &p_r->p_picture->p[0];
875     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 );
876     if( i_ret < 0 )
877     {
878         goto failure;
879     }
880
881     PROFILE_START( tiger_renderer_update );
882     i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
883     if( i_ret < 0 )
884     {
885         goto failure;
886     }
887     PROFILE_STOP( tiger_renderer_update );
888
889     PROFILE_START( tiger_renderer_render );
890     i_ret = tiger_renderer_render( p_sys->p_tr );
891     if( i_ret < 0 )
892     {
893         goto failure;
894     }
895     PROFILE_STOP( tiger_renderer_render );
896
897     PostprocessTigerImage( p_plane, fmt.i_width );
898     p_subpic->p_region = p_r;
899     p_sys->b_dirty = false;
900
901     PROFILE_STOP( TigerUpdateSubpicture );
902
903     vlc_mutex_unlock( &p_sys->lock );
904
905     return;
906
907 failure:
908     vlc_mutex_unlock( &p_sys->lock );
909     subpicture_region_ChainDelete( p_r );
910 }
911
912 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
913 {
914     char *psz_tmp;
915     uint32_t i_color = 0;
916
917     if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
918     {
919         uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
920         var_Destroy( p_dec, psz_tmp );
921         free( psz_tmp );
922         i_color |= i_rgb;
923     }
924
925     if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
926     {
927         uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
928         var_Destroy( p_dec, psz_tmp );
929         free( psz_tmp );
930         i_color |= (i_alpha << 24);
931     }
932
933     return i_color;
934 }
935
936 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
937 {
938     char *psz_value = var_CreateGetString( p_dec, psz_name );
939     if( psz_value)
940     {
941         psz_value = strdup( psz_value );
942     }
943     var_Destroy( p_dec, psz_name );
944     return psz_value;
945 }
946
947 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
948 {
949     int i_value = var_CreateGetInteger( p_dec, psz_name );
950     var_Destroy( p_dec, psz_name );
951     return i_value;
952 }
953
954 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
955 {
956     double f_value = var_CreateGetFloat( p_dec, psz_name );
957     var_Destroy( p_dec, psz_name );
958     return f_value;
959 }
960
961 static void UpdateTigerQuality( decoder_t *p_dec )
962 {
963     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
964     CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
965     p_sys->b_dirty = true;
966 }
967
968 static void UpdateTigerFontDesc( decoder_t *p_dec )
969 {
970     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
971     CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
972     p_sys->b_dirty = true;
973 }
974
975 static void UpdateTigerFontColor( decoder_t *p_dec )
976 {
977     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
978     double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
979     double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
980     double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
981     double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
982     CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
983     p_sys->b_dirty = true;
984 }
985
986 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
987 {
988     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
989     double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
990     double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
991     double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
992     double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
993     CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
994     p_sys->b_dirty = true;
995 }
996
997 static void UpdateTigerFontEffect( decoder_t *p_dec )
998 {
999     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1000     CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1001                                                              p_sys->e_tiger_default_font_effect,
1002                                                              p_sys->f_tiger_default_font_effect_strength ) );
1003     p_sys->b_dirty = true;
1004 }
1005
1006 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1007                                    vlc_value_t oldval, vlc_value_t newval )
1008 {
1009     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1010
1011     VLC_UNUSED( oldval );
1012
1013     vlc_mutex_lock( &p_sys->lock );
1014
1015     msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1016
1017     if( !p_sys->b_use_tiger || !p_sys->p_tr )
1018     {
1019         vlc_mutex_unlock( &p_sys->lock );
1020         return VLC_SUCCESS;
1021     }
1022
1023 #define TEST_TIGER_VAR( name ) \
1024     if( !strcmp( name, psz_var ) )
1025
1026     TEST_TIGER_VAR( "kate-tiger-quality" )
1027     {
1028         p_sys->f_tiger_quality = newval.f_float;
1029         UpdateTigerQuality( p_dec );
1030     }
1031
1032     TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1033     {
1034         if( p_sys->psz_tiger_default_font_desc )
1035         {
1036             free( p_sys->psz_tiger_default_font_desc );
1037             p_sys->psz_tiger_default_font_desc = NULL;
1038         }
1039         if( newval.psz_string )
1040         {
1041             p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1042         }
1043         UpdateTigerFontDesc( p_dec );
1044     }
1045
1046     TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1047     {
1048         p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1049         UpdateTigerFontColor( p_dec );
1050     }
1051
1052     TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1053     {
1054         p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1055         UpdateTigerFontColor( p_dec );
1056     }
1057
1058     TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1059     {
1060         p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1061         UpdateTigerBackgroundColor( p_dec );
1062     }
1063
1064     TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1065     {
1066         p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1067         UpdateTigerBackgroundColor( p_dec );
1068     }
1069
1070     TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1071     {
1072         p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1073         UpdateTigerFontEffect( p_dec );
1074     }
1075
1076     TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1077     {
1078         p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1079         UpdateTigerFontEffect( p_dec );
1080     }
1081
1082 #undef TEST_TIGER_VAR
1083
1084     vlc_mutex_unlock( &p_sys->lock );
1085
1086     return VLC_SUCCESS;
1087 }
1088
1089 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1090                                        vlc_value_t oldval, vlc_value_t newval,
1091                                        void *p_data )
1092 {
1093     size_t i_idx;
1094
1095     VLC_UNUSED( p_this );
1096     VLC_UNUSED( oldval );
1097     VLC_UNUSED( newval );
1098     VLC_UNUSED( p_data );
1099
1100     vlc_mutex_lock( &kate_decoder_list_mutex );
1101
1102     /* Update all existing decoders from the global user prefs */
1103     for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1104     {
1105         decoder_t *p_dec = kate_decoder_list[ i_idx ];
1106         OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1107     }
1108
1109     vlc_mutex_unlock( &kate_decoder_list_mutex );
1110
1111     return VLC_SUCCESS;
1112 }
1113
1114 #endif
1115
1116 /*****************************************************************************
1117  * DecodePacket: decodes a Kate packet.
1118  *****************************************************************************/
1119 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1120 {
1121     decoder_sys_t *p_sys = p_dec->p_sys;
1122     const kate_event *ev = NULL;
1123     subpicture_t *p_spu = NULL;
1124     int i_ret;
1125
1126     if( !p_sys->b_ready )
1127     {
1128         msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1129         return NULL;
1130     }
1131
1132     i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1133     if( i_ret < 0 )
1134     {
1135         msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1136         return NULL;
1137     }
1138
1139     i_ret = kate_decode_eventout( &p_sys->k, &ev );
1140     if( i_ret < 0 )
1141     {
1142         msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1143         return NULL;
1144     }
1145     if( i_ret > 0 )
1146     {
1147         /* no event to go with this packet, this is normal */
1148         return NULL;
1149     }
1150
1151     /* we have an event */
1152
1153     /* Get a new spu */
1154     subpicture_updater_sys_t *p_spu_sys = NULL;
1155     if( p_sys->b_use_tiger)
1156     {
1157         p_spu_sys = malloc( sizeof(*p_spu_sys) );
1158         if( !p_spu_sys )
1159             return NULL;
1160     }
1161     subpicture_updater_t updater = {
1162 #ifdef HAVE_TIGER
1163         .pf_validate = TigerValidateSubpicture,
1164         .pf_update   = TigerUpdateSubpicture,
1165         .pf_destroy  = TigerDestroySubpicture,
1166 #endif
1167         .p_sys       = p_spu_sys,
1168     };
1169     p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1170     if( !p_spu )
1171     {
1172         free( p_spu_sys );
1173         /* this will happen for lyrics as there is no vout - so no error */
1174         /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1175         return NULL;
1176     }
1177
1178     p_spu->i_start = p_block->i_pts;
1179     p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1180     p_spu->b_ephemer = false;
1181     p_spu->b_absolute = false;
1182
1183 #ifdef HAVE_TIGER
1184     if( p_sys->b_use_tiger)
1185     {
1186         p_spu_sys->p_dec_sys = p_sys;
1187         p_spu_sys->i_start   = p_block->i_pts;
1188         DecSysHold( p_sys );
1189
1190         p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1191         p_spu->b_ephemer = true;
1192         p_spu->b_absolute = true;
1193
1194         /* add the event to tiger */
1195         vlc_mutex_lock( &p_sys->lock );
1196         CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1197         vlc_mutex_unlock( &p_sys->lock );
1198     }
1199     else
1200 #endif
1201     {
1202         p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1203     }
1204
1205     return p_spu;
1206 }
1207
1208 /*****************************************************************************
1209  * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1210  *****************************************************************************/
1211 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1212                                          const kate_event *ev )
1213 {
1214     decoder_sys_t *p_sys = p_dec->p_sys;
1215     video_format_t fmt;
1216     subpicture_region_t *p_bitmap_region = NULL;
1217     video_palette_t palette;
1218     kate_tracker kin;
1219     bool b_tracker_valid = false;
1220     int i_ret;
1221
1222     /* these may be 0 for "not specified" */
1223     p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1224     p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1225
1226     /* Create a new subpicture region */
1227     memset( &fmt, 0, sizeof(video_format_t) );
1228
1229     if (p_sys->b_formatted)
1230     {
1231         i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1232         if( i_ret < 0)
1233         {
1234             msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1235         }
1236         else
1237         {
1238             int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1239             GetVideoSize(p_dec, &w, &h);
1240             i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1241             if( i_ret < 0)
1242             {
1243                 kate_tracker_clear(&kin);
1244                 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1245             }
1246             else
1247             {
1248                 // TODO: parse tracker and set style, init fmt
1249                 b_tracker_valid = true;
1250             }
1251         }
1252     }
1253
1254     if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1255
1256         /* create a separate region for the bitmap */
1257         memset( &fmt, 0, sizeof(video_format_t) );
1258         fmt.i_chroma = VLC_CODEC_YUVP;
1259         fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1260         fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1261         fmt.i_x_offset = fmt.i_y_offset = 0;
1262         fmt.p_palette = &palette;
1263         CreateKatePalette( fmt.p_palette, ev->palette );
1264
1265         p_bitmap_region = subpicture_region_New( &fmt );
1266         if( !p_bitmap_region )
1267         {
1268             msg_Err( p_dec, "cannot allocate SPU region" );
1269             decoder_DeleteSubpicture( p_dec, p_spu );
1270             return NULL;
1271         }
1272
1273         /* create the bitmap */
1274         CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1275
1276         msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1277     }
1278
1279     /* text region */
1280     fmt.i_chroma = VLC_CODEC_TEXT;
1281     fmt.i_sar_num = 0;
1282     fmt.i_sar_den = 1;
1283     fmt.i_width = fmt.i_height = 0;
1284     fmt.i_x_offset = fmt.i_y_offset = 0;
1285     p_spu->p_region = subpicture_region_New( &fmt );
1286     if( !p_spu->p_region )
1287     {
1288         msg_Err( p_dec, "cannot allocate SPU region" );
1289         decoder_DeleteSubpicture( p_dec, p_spu );
1290         return NULL;
1291     }
1292
1293     SetupText( p_dec, p_spu, ev );
1294
1295     /* default positioning */
1296     p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1297     if (p_bitmap_region)
1298     {
1299         p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1300     }
1301     p_spu->p_region->i_x = 0;
1302     p_spu->p_region->i_y = 10;
1303
1304     /* override if tracker info present */
1305     if (b_tracker_valid)
1306     {
1307         if (kin.has.region)
1308         {
1309             p_spu->p_region->i_x = kin.region_x;
1310             p_spu->p_region->i_y = kin.region_y;
1311             if (p_bitmap_region)
1312             {
1313                 p_bitmap_region->i_x = kin.region_x;
1314                 p_bitmap_region->i_y = kin.region_y;
1315             }
1316             p_spu->b_absolute = true;
1317         }
1318
1319         kate_tracker_clear(&kin);
1320     }
1321
1322     /* if we have a bitmap, chain it before the text */
1323     if (p_bitmap_region)
1324     {
1325         p_bitmap_region->p_next = p_spu->p_region;
1326         p_spu->p_region = p_bitmap_region;
1327     }
1328
1329     return p_spu;
1330 }
1331
1332 /*****************************************************************************
1333  * ParseKateComments:
1334  *****************************************************************************/
1335 static void ParseKateComments( decoder_t *p_dec )
1336 {
1337     char *psz_name, *psz_value, *psz_comment;
1338     int i = 0;
1339
1340     while ( i < p_dec->p_sys->kc.comments )
1341     {
1342         psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1343         if( !psz_comment )
1344             break;
1345         psz_name = psz_comment;
1346         psz_value = strchr( psz_comment, '=' );
1347         if( psz_value )
1348         {
1349             *psz_value = '\0';
1350             psz_value++;
1351
1352             if( !p_dec->p_description )
1353                 p_dec->p_description = vlc_meta_New();
1354             if( p_dec->p_description )
1355                 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1356         }
1357         free( psz_comment );
1358         i++;
1359     }
1360 }
1361
1362 /*****************************************************************************
1363  * CloseDecoder: clean up the decoder
1364  *****************************************************************************/
1365 static void CloseDecoder( vlc_object_t *p_this )
1366 {
1367     decoder_t *p_dec = (decoder_t *)p_this;
1368     size_t     i_index;
1369
1370     /* remove the decoder from the global list */
1371     vlc_mutex_lock( &kate_decoder_list_mutex );
1372     for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1373     {
1374         if( kate_decoder_list[ i_index ] == p_dec )
1375         {
1376             kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1377             break;
1378         }
1379     }
1380     vlc_mutex_unlock( &kate_decoder_list_mutex );
1381
1382     msg_Dbg( p_dec, "Closing Kate decoder" );
1383     DecSysRelease( p_dec->p_sys );
1384 }
1385
1386 static void DecSysHold( decoder_sys_t *p_sys )
1387 {
1388     vlc_mutex_lock( &p_sys->lock );
1389     p_sys->i_refcount++;
1390     vlc_mutex_unlock( &p_sys->lock );
1391 }
1392
1393 static void DecSysRelease( decoder_sys_t *p_sys )
1394 {
1395     vlc_mutex_lock( &p_sys->lock );
1396     p_sys->i_refcount--;
1397     if( p_sys->i_refcount > 0)
1398     {
1399         vlc_mutex_unlock( &p_sys->lock );
1400         return;
1401     }
1402
1403     vlc_mutex_unlock( &p_sys->lock );
1404     vlc_mutex_destroy( &p_sys->lock );
1405
1406 #ifdef HAVE_TIGER
1407     if( p_sys->p_tr )
1408         tiger_renderer_destroy( p_sys->p_tr );
1409     free( p_sys->psz_tiger_default_font_desc );
1410 #endif
1411
1412     if (p_sys->b_ready)
1413         kate_clear( &p_sys->k );
1414     kate_info_clear( &p_sys->ki );
1415     kate_comment_clear( &p_sys->kc );
1416
1417     free( p_sys );
1418 }
1419