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