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