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