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