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