]> git.sesse.net Git - vlc/blob - modules/codec/kate.c
Trailing ;
[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_FOURCC('k','a','t','e') )
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 =
364           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
365         return VLC_ENOMEM;
366
367     vlc_mutex_init( &p_sys->lock );
368     p_sys->i_refcount = 0;
369     DecSysHold( p_sys );
370
371     /* init of p_sys */
372 #ifdef ENABLE_PACKETIZER
373     p_sys->b_packetizer = false;
374 #endif
375     p_sys->b_ready = false;
376     p_sys->i_pts = 0;
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     /* add the decoder to the global list */
430     decoder_t **list = ( decoder_t** ) realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( decoder_t* ));
431     if( list )
432     {
433         list[ kate_decoder_list_size++ ] = p_dec;
434         kate_decoder_list = list;
435     }
436
437     vlc_mutex_unlock( &kate_decoder_list_mutex );
438
439     return VLC_SUCCESS;
440 }
441
442 #ifdef ENABLE_PACKETIZER
443 static int OpenPacketizer( vlc_object_t *p_this )
444 {
445     decoder_t *p_dec = (decoder_t*)p_this;
446
447     int i_ret = OpenDecoder( p_this );
448
449     if( i_ret == VLC_SUCCESS )
450     {
451         p_dec->p_sys->b_packetizer = true;
452         p_dec->fmt_out.i_codec = VLC_FOURCC( 'k', 'a', 't', 'e' );
453     }
454
455     return i_ret;
456 }
457 #endif
458
459 /****************************************************************************
460  * DecodeBlock: the whole thing
461  ****************************************************************************
462  * This function must be fed with kate packets.
463  ****************************************************************************/
464 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
465 {
466     decoder_sys_t *p_sys = p_dec->p_sys;
467     block_t *p_block;
468     kate_packet kp;
469
470     if( !pp_block || !*pp_block )
471         return NULL;
472
473     p_block = *pp_block;
474
475     if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) )
476     {
477         block_Release( p_block );
478         return NULL;
479     }
480
481     if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY) )
482     {
483 #ifdef HAVE_TIGER
484         /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
485         vlc_mutex_lock( &p_sys->lock );
486         tiger_renderer_seek( p_sys->p_tr, 0 );
487         vlc_mutex_unlock( &p_sys->lock );
488 #endif
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\n",
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\n");
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\n",
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 static void TigerPreRender( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt )
829 {
830     decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys;
831
832     VLC_UNUSED( p_spu );
833     VLC_UNUSED( p_fmt );
834
835     p_sys->p_spu_final = p_subpic;
836 }
837
838 /*
839  * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
840  * alpha to avoid double multiply (and thus thinner text than we should)).
841  * Best would be to have VLC be able to handle premultiplied alpha, as it
842  * would be faster to blend as well.
843  *
844  * Also, we flip color components around for big endian machines, as Tiger
845  * outputs ARGB or ABGR (the one we selected here) in host endianness.
846  */
847 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
848 {
849     PROFILE_START( tiger_renderer_postprocess );
850     int y;
851     for( y=0; y<p_plane->i_lines; ++y )
852     {
853         uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
854         unsigned int x;
855         for( x=0; x<i_width; ++x )
856         {
857             uint8_t *p_pixel = p_line+x*4;
858 #ifdef WORDS_BIGENDIAN
859             uint8_t a = p_pixel[0];
860 #else
861             uint8_t a = p_pixel[3];
862 #endif
863             if( a )
864             {
865 #ifdef WORDS_BIGENDIAN
866                 uint8_t tmp = pixel[2];
867                 p_pixel[0] = p_pixel[3] * 255 / a;
868                 p_pixel[3] = a;
869                 p_pixel[2] = p_pixel[1] * 255 / a;
870                 p_pixel[1] = tmp * 255 / a;
871 #else
872                 p_pixel[0] = p_pixel[0] * 255 / a;
873                 p_pixel[1] = p_pixel[1] * 255 / a;
874                 p_pixel[2] = p_pixel[2] * 255 / a;
875 #endif
876             }
877             else
878             {
879                 p_pixel[0] = 0;
880                 p_pixel[1] = 0;
881                 p_pixel[2] = 0;
882                 p_pixel[3] = 0;
883             }
884         }
885     }
886     PROFILE_STOP( tiger_renderer_postprocess );
887 }
888
889 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
890    a subsampled YUV image, so there can be a fair amount of chroma bleeding.
891    Looks good with white though since it's all luma. Hopefully that will be the
892    common case. */
893 static void TigerUpdateRegions( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt, mtime_t ts )
894 {
895     decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys;
896     subpicture_region_t *p_r;
897     video_format_t fmt;
898     plane_t *p_plane;
899     kate_float t;
900     int i_ret;
901
902     VLC_UNUSED( p_spu );
903
904     PROFILE_START( TigerUpdateRegions );
905
906     /* do not render more than once per frame, libtiger renders all events at once */
907     if (ts <= p_sys->last_render_ts)
908     {
909         SubpictureReleaseRegions( p_subpic );
910         return;
911     }
912
913     /* remember what frame we've rendered already */
914     p_sys->last_render_ts = ts;
915
916     if( p_subpic != p_sys->p_spu_final )
917     {
918         SubpictureReleaseRegions( p_subpic );
919         return;
920     }
921
922     /* time in seconds from the start of the stream */
923     t = (p_subpic->p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
924
925     /* it is likely that the current region (if any) can be kept as is; test for this */
926     vlc_mutex_lock( &p_sys->lock );
927     if( p_subpic->p_region && !p_sys->b_dirty && !tiger_renderer_is_dirty( p_sys->p_tr ))
928     {
929         PROFILE_START( tiger_renderer_update1 );
930         i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
931         PROFILE_STOP( tiger_renderer_update1 );
932         if( i_ret < 0 )
933         {
934             SubpictureReleaseRegions( p_subpic );
935             vlc_mutex_unlock( &p_sys->lock );
936             return;
937         }
938
939         if( !tiger_renderer_is_dirty( p_sys->p_tr ) )
940         {
941             /* we can keep the current region list */
942             PROFILE_STOP( TigerUpdateRegions );
943             vlc_mutex_unlock( &p_sys->lock );
944             return;
945         }
946     }
947     vlc_mutex_unlock( &p_sys->lock );
948
949     /* we have to render again, reset current region list */
950     SubpictureReleaseRegions( p_subpic );
951
952     /* create a full frame region - this will also tell Tiger the size of the frame */
953     fmt = *p_fmt;
954     fmt.i_chroma = VLC_FOURCC('R','G','B','A');
955     fmt.i_width = fmt.i_visible_width;
956     fmt.i_height = fmt.i_visible_height;
957     fmt.i_bits_per_pixel = 0;
958     fmt.i_x_offset = fmt.i_y_offset = 0;
959
960     p_r = subpicture_region_New( &fmt );
961     if( !p_r )
962     {
963         return;
964     }
965
966     p_r->i_x = 0;
967     p_r->i_y = 0;
968     p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
969
970     vlc_mutex_lock( &p_sys->lock );
971
972     p_plane = &p_r->p_picture->p[0];
973     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 );
974     if( i_ret < 0 )
975     {
976         goto failure;
977     }
978
979     PROFILE_START( tiger_renderer_update );
980     i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
981     if( i_ret < 0 )
982     {
983         goto failure;
984     }
985     PROFILE_STOP( tiger_renderer_update );
986
987     PROFILE_START( tiger_renderer_render );
988     i_ret = tiger_renderer_render( p_sys->p_tr );
989     if( i_ret < 0 )
990     {
991         goto failure;
992     }
993     PROFILE_STOP( tiger_renderer_render );
994
995     PostprocessTigerImage( p_plane, fmt.i_width );
996     p_subpic->p_region = p_r;
997     p_sys->b_dirty = false;
998
999     PROFILE_STOP( TigerUpdateRegions );
1000
1001     vlc_mutex_unlock( &p_sys->lock );
1002
1003     return;
1004
1005 failure:
1006     vlc_mutex_unlock( &p_sys->lock );
1007     subpicture_region_ChainDelete( p_r );
1008 }
1009
1010 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
1011 {
1012     char *psz_tmp;
1013     uint32_t i_color = 0;
1014
1015     if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
1016     {
1017         uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
1018         var_Destroy( p_dec, psz_tmp );
1019         free( psz_tmp );
1020         i_color |= i_rgb;
1021     }
1022
1023     if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
1024     {
1025         uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
1026         var_Destroy( p_dec, psz_tmp );
1027         free( psz_tmp );
1028         i_color |= (i_alpha << 24);
1029     }
1030
1031     return i_color;
1032 }
1033
1034 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
1035 {
1036     char *psz_value = var_CreateGetString( p_dec, psz_name );
1037     if( psz_value)
1038     {
1039         psz_value = strdup( psz_value );
1040     }
1041     var_Destroy( p_dec, psz_name );
1042     return psz_value;
1043 }
1044
1045 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
1046 {
1047     int i_value = var_CreateGetInteger( p_dec, psz_name );
1048     var_Destroy( p_dec, psz_name );
1049     return i_value;
1050 }
1051
1052 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
1053 {
1054     double f_value = var_CreateGetFloat( p_dec, psz_name );
1055     var_Destroy( p_dec, psz_name );
1056     return f_value;
1057 }
1058
1059 static void UpdateTigerQuality( decoder_t *p_dec )
1060 {
1061     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1062     CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
1063     p_sys->b_dirty = true;
1064 }
1065
1066 static void UpdateTigerFontDesc( decoder_t *p_dec )
1067 {
1068     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1069     CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
1070     p_sys->b_dirty = true;
1071 }
1072
1073 static void UpdateTigerFontColor( decoder_t *p_dec )
1074 {
1075     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1076     double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
1077     double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
1078     double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
1079     double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
1080     CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1081     p_sys->b_dirty = true;
1082 }
1083
1084 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
1085 {
1086     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1087     double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
1088     double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1089     double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1090     double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1091     CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1092     p_sys->b_dirty = true;
1093 }
1094
1095 static void UpdateTigerFontEffect( decoder_t *p_dec )
1096 {
1097     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1098     CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1099                                                              p_sys->e_tiger_default_font_effect,
1100                                                              p_sys->f_tiger_default_font_effect_strength ) );
1101     p_sys->b_dirty = true;
1102 }
1103
1104 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1105                                    vlc_value_t oldval, vlc_value_t newval )
1106 {
1107     decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1108
1109     VLC_UNUSED( oldval );
1110
1111     vlc_mutex_lock( &p_sys->lock );
1112
1113     msg_Dbg( p_dec, "OnConfigurationChanged: %s\n", psz_var );
1114
1115     if( !p_sys->b_use_tiger || !p_sys->p_tr )
1116     {
1117         vlc_mutex_unlock( &p_sys->lock );
1118         return VLC_SUCCESS;
1119     }
1120
1121 #define TEST_TIGER_VAR( name ) \
1122     if( !strcmp( name, psz_var ) )
1123
1124     TEST_TIGER_VAR( "kate-tiger-quality" )
1125     {
1126         p_sys->f_tiger_quality = newval.f_float;
1127         UpdateTigerQuality( p_dec );
1128     }
1129
1130     TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1131     {
1132         if( p_sys->psz_tiger_default_font_desc )
1133         {
1134             free( p_sys->psz_tiger_default_font_desc );
1135             p_sys->psz_tiger_default_font_desc = NULL;
1136         }
1137         if( newval.psz_string )
1138         {
1139             p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1140         }
1141         UpdateTigerFontDesc( p_dec );
1142     }
1143
1144     TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1145     {
1146         p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1147         UpdateTigerFontColor( p_dec );
1148     }
1149
1150     TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1151     {
1152         p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1153         UpdateTigerFontColor( p_dec );
1154     }
1155
1156     TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1157     {
1158         p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1159         UpdateTigerBackgroundColor( p_dec );
1160     }
1161
1162     TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1163     {
1164         p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1165         UpdateTigerBackgroundColor( p_dec );
1166     }
1167
1168     TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1169     {
1170         p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1171         UpdateTigerFontEffect( p_dec );
1172     }
1173
1174     TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1175     {
1176         p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1177         UpdateTigerFontEffect( p_dec );
1178     }
1179
1180 #undef TEST_TIGER_VAR
1181
1182     vlc_mutex_unlock( &p_sys->lock );
1183
1184     return VLC_SUCCESS;
1185 }
1186
1187 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1188                                        vlc_value_t oldval, vlc_value_t newval,
1189                                        void *p_data )
1190 {
1191     size_t i_idx;
1192
1193     VLC_UNUSED( p_this );
1194     VLC_UNUSED( oldval );
1195     VLC_UNUSED( newval );
1196     VLC_UNUSED( p_data );
1197
1198     vlc_mutex_lock( &kate_decoder_list_mutex );
1199
1200     /* Update all existing decoders from the global user prefs */
1201     for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1202     {
1203         decoder_t *p_dec = kate_decoder_list[ i_idx ];
1204         OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1205     }
1206
1207     vlc_mutex_unlock( &kate_decoder_list_mutex );
1208
1209     return VLC_SUCCESS;
1210 }
1211
1212 #endif
1213
1214 /*****************************************************************************
1215  * DecodePacket: decodes a Kate packet.
1216  *****************************************************************************/
1217 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1218 {
1219     decoder_sys_t *p_sys = p_dec->p_sys;
1220     const kate_event *ev = NULL;
1221     subpicture_t *p_spu = NULL;
1222     int i_ret;
1223
1224     if( !p_sys->b_ready )
1225     {
1226         msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1227         return NULL;
1228     }
1229
1230     i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1231     if( i_ret < 0 )
1232     {
1233         msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1234         return NULL;
1235     }
1236
1237     i_ret = kate_decode_eventout( &p_sys->k, &ev );
1238     if( i_ret < 0 )
1239     {
1240         msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1241         return NULL;
1242     }
1243     if( i_ret > 0 )
1244     {
1245         /* no event to go with this packet, this is normal */
1246         return NULL;
1247     }
1248
1249     /* we have an event */
1250
1251     /* Get a new spu */
1252     p_spu = decoder_NewSubpicture( p_dec );
1253     if( !p_spu )
1254     {
1255         /* this will happen for lyrics as there is no vout - so no error */
1256         /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1257         return NULL;
1258     }
1259
1260     p_spu->i_start = p_block->i_pts;
1261     p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1262     p_spu->b_ephemer = false;
1263     p_spu->b_absolute = false;
1264
1265 #ifdef HAVE_TIGER
1266     if( p_sys->b_use_tiger)
1267     {
1268         /* setup the structure to get our decoder struct back */
1269         p_spu->p_sys = malloc( sizeof( subpicture_sys_t ));
1270         if( !p_spu->p_sys )
1271         {
1272             decoder_DeleteSubpicture( p_dec, p_spu );
1273             return NULL;
1274         }
1275         p_spu->p_sys->p_dec_sys = p_sys;
1276         p_spu->p_sys->i_start = p_block->i_pts;
1277         DecSysHold( p_sys );
1278
1279         p_spu->b_absolute = true;
1280
1281         /* add the event to tiger */
1282         vlc_mutex_lock( &p_sys->lock );
1283         CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1284         vlc_mutex_unlock( &p_sys->lock );
1285
1286         /* hookup render/update routines */
1287         p_spu->pf_pre_render = TigerPreRender;
1288         p_spu->pf_update_regions = TigerUpdateRegions;
1289         p_spu->pf_destroy = TigerDestroySubpicture;
1290     }
1291     else
1292 #endif
1293     {
1294         p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1295     }
1296
1297     return p_spu;
1298 }
1299
1300 /*****************************************************************************
1301  * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1302  *****************************************************************************/
1303 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1304                                          const kate_event *ev )
1305 {
1306     decoder_sys_t *p_sys = p_dec->p_sys;
1307     video_format_t fmt;
1308     subpicture_region_t *p_bitmap_region = NULL;
1309     video_palette_t palette;
1310     kate_tracker kin;
1311     bool b_tracker_valid = false;
1312     int i_ret;
1313
1314     /* these may be 0 for "not specified" */
1315     p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1316     p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1317
1318     /* Create a new subpicture region */
1319     memset( &fmt, 0, sizeof(video_format_t) );
1320
1321     if (p_sys->b_formatted)
1322     {
1323         i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1324         if( i_ret < 0)
1325         {
1326             msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1327         }
1328         else
1329         {
1330             int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1331             GetVideoSize(p_dec, &w, &h);
1332             i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1333             if( i_ret < 0)
1334             {
1335                 kate_tracker_clear(&kin);
1336                 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1337             }
1338             else
1339             {
1340                 // TODO: parse tracker and set style, init fmt
1341                 b_tracker_valid = true;
1342             }
1343         }
1344     }
1345
1346     if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1347
1348         /* create a separate region for the bitmap */
1349         memset( &fmt, 0, sizeof(video_format_t) );
1350         fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
1351         fmt.i_aspect = 0;
1352         fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1353         fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1354         fmt.i_x_offset = fmt.i_y_offset = 0;
1355         fmt.p_palette = &palette;
1356         CreateKatePalette( fmt.p_palette, ev->palette );
1357
1358         p_bitmap_region = subpicture_region_New( &fmt );
1359         if( !p_bitmap_region )
1360         {
1361             msg_Err( p_dec, "cannot allocate SPU region" );
1362             decoder_DeleteSubpicture( p_dec, p_spu );
1363             return NULL;
1364         }
1365
1366         /* create the bitmap */
1367         CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1368
1369         msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors\n", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1370     }
1371
1372     /* text region */
1373     fmt.i_chroma = VLC_FOURCC('T','E','X','T');
1374     fmt.i_aspect = 0;
1375     fmt.i_width = fmt.i_height = 0;
1376     fmt.i_x_offset = fmt.i_y_offset = 0;
1377     p_spu->p_region = subpicture_region_New( &fmt );
1378     if( !p_spu->p_region )
1379     {
1380         msg_Err( p_dec, "cannot allocate SPU region" );
1381         decoder_DeleteSubpicture( p_dec, p_spu );
1382         return NULL;
1383     }
1384
1385     SetupText( p_dec, p_spu, ev );
1386
1387     /* default positioning */
1388     p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1389     if (p_bitmap_region)
1390     {
1391         p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1392     }
1393     p_spu->p_region->i_x = 0;
1394     p_spu->p_region->i_y = 10;
1395
1396     /* override if tracker info present */
1397     if (b_tracker_valid)
1398     {
1399         if (kin.has.region)
1400         {
1401             p_spu->p_region->i_x = kin.region_x;
1402             p_spu->p_region->i_y = kin.region_y;
1403             if (p_bitmap_region)
1404             {
1405                 p_bitmap_region->i_x = kin.region_x;
1406                 p_bitmap_region->i_y = kin.region_y;
1407             }
1408             p_spu->b_absolute = true;
1409         }
1410
1411         kate_tracker_clear(&kin);
1412     }
1413
1414     /* if we have a bitmap, chain it before the text */
1415     if (p_bitmap_region)
1416     {
1417         p_bitmap_region->p_next = p_spu->p_region;
1418         p_spu->p_region = p_bitmap_region;
1419     }
1420
1421     return p_spu;
1422 }
1423
1424 /*****************************************************************************
1425  * ParseKateComments:
1426  *****************************************************************************/
1427 static void ParseKateComments( decoder_t *p_dec )
1428 {
1429     char *psz_name, *psz_value, *psz_comment;
1430     int i = 0;
1431
1432     while ( i < p_dec->p_sys->kc.comments )
1433     {
1434         psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1435         if( !psz_comment )
1436             break;
1437         psz_name = psz_comment;
1438         psz_value = strchr( psz_comment, '=' );
1439         if( psz_value )
1440         {
1441             *psz_value = '\0';
1442             psz_value++;
1443
1444             if( !p_dec->p_description )
1445                 p_dec->p_description = vlc_meta_New();
1446             if( p_dec->p_description )
1447                 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1448         }
1449         free( psz_comment );
1450         i++;
1451     }
1452 }
1453
1454 /*****************************************************************************
1455  * CloseDecoder: clean up the decoder
1456  *****************************************************************************/
1457 static void CloseDecoder( vlc_object_t *p_this )
1458 {
1459     decoder_t *p_dec = (decoder_t *)p_this;
1460     size_t     i_index;
1461
1462     /* remove the decoder from the global list */
1463     vlc_mutex_lock( &kate_decoder_list_mutex );
1464     for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1465     {
1466         if( kate_decoder_list[ i_index ] == p_dec )
1467         {
1468             kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1469             break;
1470         }
1471     }
1472     vlc_mutex_unlock( &kate_decoder_list_mutex );
1473
1474     msg_Dbg( p_dec, "Closing Kate decoder" );
1475     DecSysRelease( p_dec->p_sys );
1476 }
1477
1478 static void DecSysHold( decoder_sys_t *p_sys )
1479 {
1480     vlc_mutex_lock( &p_sys->lock );
1481     p_sys->i_refcount++;
1482     vlc_mutex_unlock( &p_sys->lock );
1483 }
1484
1485 static void DecSysRelease( decoder_sys_t *p_sys )
1486 {
1487     vlc_mutex_lock( &p_sys->lock );
1488     p_sys->i_refcount--;
1489     if( p_sys->i_refcount > 0)
1490     {
1491         vlc_mutex_unlock( &p_sys->lock );
1492         return;
1493     }
1494
1495     vlc_mutex_unlock( &p_sys->lock );
1496     vlc_mutex_destroy( &p_sys->lock );
1497
1498 #ifdef HAVE_TIGER
1499     if( p_sys->p_tr )
1500         tiger_renderer_destroy( p_sys->p_tr );
1501     if( p_sys->psz_tiger_default_font_desc )
1502         free( p_sys->psz_tiger_default_font_desc );
1503 #endif
1504
1505     if (p_sys->b_ready)
1506         kate_clear( &p_sys->k );
1507     kate_info_clear( &p_sys->ki );
1508     kate_comment_clear( &p_sys->kc );
1509
1510     free( p_sys );
1511 }
1512