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