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