1 /*****************************************************************************
2 * kate.c : a decoder for the kate bitstream format
3 *****************************************************************************
4 * Copyright (C) 2000-2008 the VideoLAN team
7 * Authors: Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_input.h>
34 #include <vlc_codec.h>
37 #include <kate/kate.h>
39 # include <tiger/tiger.h>
42 /* #define ENABLE_PACKETIZER */
43 /* #define 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 )
49 # define PROFILE_START(name) ((void)0)
50 # define PROFILE_STOP(name) ((void)0)
53 #define CHECK_TIGER_RET( statement ) \
56 int i_ret = (statement); \
59 msg_Dbg( p_dec, "Error in " #statement ": %d", i_ret ); \
63 /*****************************************************************************
64 * decoder_sys_t : decoder descriptor
65 *****************************************************************************/
68 #ifdef ENABLE_PACKETIZER
93 /* decoder_sys_t is shared between decoder and spu units */
101 tiger_renderer *p_tr;
102 mtime_t last_render_ts;
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;
120 struct subpicture_sys_t
122 decoder_sys_t *p_dec_sys;
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.
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.
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;
152 /*****************************************************************************
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 );
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,
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 );
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,
185 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
186 vlc_value_t oldval, vlc_value_t newval);
189 #define DEFAULT_NAME "Default"
190 #define MAX_LINE 8192
192 /*****************************************************************************
194 *****************************************************************************/
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.")
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") };
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") };
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.")
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.")
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.")
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).")
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.")
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.")
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.")
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.")
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.")
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." \
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" )
282 add_bool( "kate-formatted", true, NULL, FORMAT_TEXT, FORMAT_LONGTEXT,
286 add_bool( "kate-use-tiger", true, NULL, TIGER_TEXT, TIGER_LONGTEXT,
288 add_float_with_range( "kate-tiger-quality",
289 TIGER_QUALITY_DEFAULT, 0.0f, 1.0f, TigerConfigurationCallback,
290 TIGER_QUALITY_TEXT, TIGER_QUALITY_LONGTEXT,
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,
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,
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,
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,
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,
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,
327 #ifdef ENABLE_PACKETIZER
329 set_description( N_("Kate text subtitles packetizer") )
330 set_capability( "packetizer", 100 )
331 set_callbacks( OpenPacketizer, CloseDecoder )
332 add_shortcut( "kate" )
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
342 *****************************************************************************/
343 static int OpenDecoder( vlc_object_t *p_this )
345 decoder_t *p_dec = (decoder_t*)p_this;
346 decoder_sys_t *p_sys;
349 if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
354 msg_Dbg( p_dec, "kate: OpenDecoder");
357 p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
359 p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **))
362 /* Allocate the memory needed to store the decoder's structure */
363 if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
366 vlc_mutex_init( &p_sys->lock );
367 p_sys->i_refcount = 0;
371 #ifdef ENABLE_PACKETIZER
372 p_sys->b_packetizer = false;
374 p_sys->b_ready = false;
376 p_sys->i_max_stop = VLC_TS_INVALID;
378 kate_comment_init( &p_sys->kc );
379 kate_info_init( &p_sys->ki );
381 p_sys->i_num_headers = 0;
382 p_sys->i_headers = 0;
384 /* retrieve options */
385 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
387 vlc_mutex_lock( &kate_decoder_list_mutex );
391 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
394 p_sys->last_render_ts = 0;
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" );
404 if( p_sys->b_use_tiger )
406 i_ret = tiger_renderer_create( &p_sys->p_tr );
409 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
411 p_sys->b_use_tiger = false;
414 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
416 UpdateTigerFontEffect( p_dec );
417 UpdateTigerFontColor( p_dec );
418 UpdateTigerBackgroundColor( p_dec );
419 UpdateTigerQuality( p_dec );
420 UpdateTigerFontDesc( p_dec );
425 p_sys->b_use_tiger = false;
429 es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );
431 /* add the decoder to the global list */
432 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
435 list[ kate_decoder_list_size++ ] = p_dec;
436 kate_decoder_list = list;
439 vlc_mutex_unlock( &kate_decoder_list_mutex );
444 #ifdef ENABLE_PACKETIZER
445 static int OpenPacketizer( vlc_object_t *p_this )
447 decoder_t *p_dec = (decoder_t*)p_this;
449 int i_ret = OpenDecoder( p_this );
451 if( i_ret == VLC_SUCCESS )
453 p_dec->p_sys->b_packetizer = true;
454 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
461 /****************************************************************************
462 * DecodeBlock: the whole thing
463 ****************************************************************************
464 * This function must be fed with kate packets.
465 ****************************************************************************/
466 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
468 decoder_sys_t *p_sys = p_dec->p_sys;
472 if( !pp_block || !*pp_block )
477 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
480 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
482 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
483 vlc_mutex_lock( &p_sys->lock );
484 tiger_renderer_seek( p_sys->p_tr, 0 );
485 vlc_mutex_unlock( &p_sys->lock );
488 p_sys->i_max_stop = VLC_TS_INVALID;
489 block_Release( p_block );
493 /* Block to Kate packet */
494 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
496 if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
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;
502 else if( kp.nbytes && (p_sys->i_headers==0 || p_sys->i_headers < p_sys->ki.num_headers ))
504 /* Backup headers as extra data */
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;
513 memcpy( p_extra, kp.data, kp.nbytes );
514 p_dec->fmt_in.i_extra += kp.nbytes + 2;
516 block_Release( *pp_block );
517 p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
522 if( p_sys->i_headers == p_sys->i_num_headers && p_sys->i_num_headers>0 )
524 if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
526 p_sys->i_headers = 0;
527 p_dec->fmt_in.i_extra = 0;
528 block_Release( *pp_block );
531 else p_sys->i_headers++;
534 return ProcessPacket( p_dec, &kp, pp_block );
537 /*****************************************************************************
538 * ProcessHeaders: process Kate headers.
539 *****************************************************************************/
540 static int ProcessHeaders( decoder_t *p_dec )
542 decoder_sys_t *p_sys = p_dec->p_sys;
549 if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
551 p_extra = p_dec->fmt_in.p_extra;
552 i_extra = p_dec->fmt_in.i_extra;
554 /* skip number of headers */
558 /* Take care of the initial Kate header */
559 kp.nbytes = *(p_extra++) << 8;
560 kp.nbytes |= (*(p_extra++) & 0xFF);
562 p_extra += kp.nbytes;
563 i_extra -= (kp.nbytes + 2);
566 msg_Err( p_dec, "header data corrupted");
570 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
573 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
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);
582 /* parse all remaining header packets */
583 for( i_headeridx = 1; i_headeridx < p_sys->ki.num_headers; ++i_headeridx )
585 kp.nbytes = *(p_extra++) << 8;
586 kp.nbytes |= (*(p_extra++) & 0xFF);
588 p_extra += kp.nbytes;
589 i_extra -= (kp.nbytes + 2);
592 msg_Err( p_dec, "header %d data corrupted", i_headeridx );
596 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
599 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
603 /* header 1 is comments */
604 if( i_headeridx == 1 )
606 ParseKateComments( p_dec );
610 #ifdef ENABLE_PACKETIZER
611 if( !p_sys->b_packetizer )
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 );
619 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
622 p_sys->b_ready = true;
624 #ifdef ENABLE_PACKETIZER
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 );
638 /*****************************************************************************
639 * ProcessPacket: processes a kate packet.
640 *****************************************************************************/
641 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
644 decoder_sys_t *p_sys = p_dec->p_sys;
645 block_t *p_block = *pp_block;
646 subpicture_t *p_buf = NULL;
648 /* Date management */
649 if( p_block->i_pts > 0 && p_block->i_pts != p_sys->i_pts )
651 p_sys->i_pts = p_block->i_pts;
654 *pp_block = NULL; /* To avoid being fed the same packet again */
656 #ifdef ENABLE_PACKETIZER
657 if( p_sys->b_packetizer )
659 /* Date management */
660 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
662 if( p_sys->i_headers >= p_sys->i_num_headers )
663 p_block->i_length = p_sys->i_pts - p_block->i_pts;
665 p_block->i_length = 0;
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 );
677 if( p_block ) block_Release( p_block );
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 )
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 ;
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.
702 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
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. */
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 )
710 *w = p_sys->ki.original_canvas_width;
711 *h = p_sys->ki.original_canvas_height;
712 msg_Dbg( p_dec, "original canvas %zu %zu",
713 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
717 /* nothing, leave defaults */
718 msg_Dbg( p_dec, "original canvas size unknown");
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 );
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 )
729 *w = p_sys->ki.original_canvas_width;
730 *h = p_sys->ki.original_canvas_height;
734 *w = p_vout->fmt_in.i_width;
735 *h = p_vout->fmt_in.i_height;
737 msg_Dbg( p_dec, "video: in %d %d, out %d %d, original canvas %zu %zu",
738 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
739 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
740 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
741 vlc_object_release( p_vout );
746 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
750 for( y=0; y<bitmap->height; ++y )
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 );
758 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
762 fmt_palette->i_entries = palette->ncolors;
763 for( n=0; n<palette->ncolors; ++n )
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
769 fmt_palette->palette[n][3] = palette->colors[n].a;
773 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
775 decoder_sys_t *p_sys = p_dec->p_sys;
777 if( ev->text_encoding != kate_utf8 )
779 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
783 switch( ev->text_markup_type )
785 case kate_markup_none:
786 p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
788 case kate_markup_simple:
789 if( p_sys->b_formatted )
791 /* the HTML renderer expects a top level text tag pair */
793 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
795 p_spu->p_region->psz_html = buffer;
799 /* if not formatted, we fall through */
801 /* we don't know about this one, so remove markup and display as text */
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;
814 static void TigerDestroySubpicture( subpicture_t *p_subpic )
816 DecSysRelease( p_subpic->p_sys->p_dec_sys );
819 static void SubpictureReleaseRegions( subpicture_t *p_subpic )
821 if( p_subpic->p_region)
823 subpicture_region_ChainDelete( p_subpic->p_region );
824 p_subpic->p_region = NULL;
829 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
830 * alpha to avoid double multiply (and thus thinner text than we should)).
831 * Best would be to have VLC be able to handle premultiplied alpha, as it
832 * would be faster to blend as well.
834 * Also, we flip color components around for big endian machines, as Tiger
835 * outputs ARGB or ABGR (the one we selected here) in host endianness.
837 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
839 PROFILE_START( tiger_renderer_postprocess );
841 for( y=0; y<p_plane->i_lines; ++y )
843 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
845 for( x=0; x<i_width; ++x )
847 uint8_t *p_pixel = p_line+x*4;
848 #ifdef WORDS_BIGENDIAN
849 uint8_t a = p_pixel[0];
851 uint8_t a = p_pixel[3];
855 #ifdef WORDS_BIGENDIAN
856 uint8_t tmp = pixel[2];
857 p_pixel[0] = p_pixel[3] * 255 / a;
859 p_pixel[2] = p_pixel[1] * 255 / a;
860 p_pixel[1] = tmp * 255 / a;
862 p_pixel[0] = p_pixel[0] * 255 / a;
863 p_pixel[1] = p_pixel[1] * 255 / a;
864 p_pixel[2] = p_pixel[2] * 255 / a;
876 PROFILE_STOP( tiger_renderer_postprocess );
879 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
880 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
881 Looks good with white though since it's all luma. Hopefully that will be the
883 static void TigerUpdateRegions( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt, mtime_t ts )
885 decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys;
886 subpicture_region_t *p_r;
894 PROFILE_START( TigerUpdateRegions );
896 /* do not render more than once per frame, libtiger renders all events at once */
897 if (ts <= p_sys->last_render_ts)
899 SubpictureReleaseRegions( p_subpic );
903 /* remember what frame we've rendered already */
904 p_sys->last_render_ts = ts;
906 /* time in seconds from the start of the stream */
907 t = (p_subpic->p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
909 /* it is likely that the current region (if any) can be kept as is; test for this */
910 vlc_mutex_lock( &p_sys->lock );
911 if( p_subpic->p_region && !p_sys->b_dirty && !tiger_renderer_is_dirty( p_sys->p_tr ))
913 PROFILE_START( tiger_renderer_update1 );
914 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
915 PROFILE_STOP( tiger_renderer_update1 );
918 SubpictureReleaseRegions( p_subpic );
919 vlc_mutex_unlock( &p_sys->lock );
923 if( !tiger_renderer_is_dirty( p_sys->p_tr ) )
925 /* we can keep the current region list */
926 PROFILE_STOP( TigerUpdateRegions );
927 vlc_mutex_unlock( &p_sys->lock );
931 vlc_mutex_unlock( &p_sys->lock );
933 /* we have to render again, reset current region list */
934 SubpictureReleaseRegions( p_subpic );
936 /* create a full frame region - this will also tell Tiger the size of the frame */
938 fmt.i_chroma = VLC_CODEC_RGBA;
939 fmt.i_width = fmt.i_visible_width;
940 fmt.i_height = fmt.i_visible_height;
941 fmt.i_bits_per_pixel = 0;
942 fmt.i_x_offset = fmt.i_y_offset = 0;
944 p_r = subpicture_region_New( &fmt );
952 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
954 vlc_mutex_lock( &p_sys->lock );
956 p_plane = &p_r->p_picture->p[0];
957 i_ret = tiger_renderer_set_buffer( p_sys->p_tr, p_plane->p_pixels, fmt.i_width, p_plane->i_lines, p_plane->i_pitch, 1 );
963 PROFILE_START( tiger_renderer_update );
964 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
969 PROFILE_STOP( tiger_renderer_update );
971 PROFILE_START( tiger_renderer_render );
972 i_ret = tiger_renderer_render( p_sys->p_tr );
977 PROFILE_STOP( tiger_renderer_render );
979 PostprocessTigerImage( p_plane, fmt.i_width );
980 p_subpic->p_region = p_r;
981 p_sys->b_dirty = false;
983 PROFILE_STOP( TigerUpdateRegions );
985 vlc_mutex_unlock( &p_sys->lock );
990 vlc_mutex_unlock( &p_sys->lock );
991 subpicture_region_ChainDelete( p_r );
994 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
997 uint32_t i_color = 0;
999 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
1001 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
1002 var_Destroy( p_dec, psz_tmp );
1007 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
1009 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
1010 var_Destroy( p_dec, psz_tmp );
1012 i_color |= (i_alpha << 24);
1018 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
1020 char *psz_value = var_CreateGetString( p_dec, psz_name );
1023 psz_value = strdup( psz_value );
1025 var_Destroy( p_dec, psz_name );
1029 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
1031 int i_value = var_CreateGetInteger( p_dec, psz_name );
1032 var_Destroy( p_dec, psz_name );
1036 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
1038 double f_value = var_CreateGetFloat( p_dec, psz_name );
1039 var_Destroy( p_dec, psz_name );
1043 static void UpdateTigerQuality( decoder_t *p_dec )
1045 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1046 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
1047 p_sys->b_dirty = true;
1050 static void UpdateTigerFontDesc( decoder_t *p_dec )
1052 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1053 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
1054 p_sys->b_dirty = true;
1057 static void UpdateTigerFontColor( decoder_t *p_dec )
1059 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1060 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
1061 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
1062 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
1063 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
1064 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1065 p_sys->b_dirty = true;
1068 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
1070 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1071 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
1072 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1073 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1074 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1075 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1076 p_sys->b_dirty = true;
1079 static void UpdateTigerFontEffect( decoder_t *p_dec )
1081 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1082 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1083 p_sys->e_tiger_default_font_effect,
1084 p_sys->f_tiger_default_font_effect_strength ) );
1085 p_sys->b_dirty = true;
1088 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1089 vlc_value_t oldval, vlc_value_t newval )
1091 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1093 VLC_UNUSED( oldval );
1095 vlc_mutex_lock( &p_sys->lock );
1097 msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1099 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1101 vlc_mutex_unlock( &p_sys->lock );
1105 #define TEST_TIGER_VAR( name ) \
1106 if( !strcmp( name, psz_var ) )
1108 TEST_TIGER_VAR( "kate-tiger-quality" )
1110 p_sys->f_tiger_quality = newval.f_float;
1111 UpdateTigerQuality( p_dec );
1114 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1116 if( p_sys->psz_tiger_default_font_desc )
1118 free( p_sys->psz_tiger_default_font_desc );
1119 p_sys->psz_tiger_default_font_desc = NULL;
1121 if( newval.psz_string )
1123 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1125 UpdateTigerFontDesc( p_dec );
1128 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1130 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1131 UpdateTigerFontColor( p_dec );
1134 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1136 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1137 UpdateTigerFontColor( p_dec );
1140 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1142 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1143 UpdateTigerBackgroundColor( p_dec );
1146 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1148 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1149 UpdateTigerBackgroundColor( p_dec );
1152 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1154 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1155 UpdateTigerFontEffect( p_dec );
1158 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1160 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1161 UpdateTigerFontEffect( p_dec );
1164 #undef TEST_TIGER_VAR
1166 vlc_mutex_unlock( &p_sys->lock );
1171 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1172 vlc_value_t oldval, vlc_value_t newval,
1177 VLC_UNUSED( p_this );
1178 VLC_UNUSED( oldval );
1179 VLC_UNUSED( newval );
1180 VLC_UNUSED( p_data );
1182 vlc_mutex_lock( &kate_decoder_list_mutex );
1184 /* Update all existing decoders from the global user prefs */
1185 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1187 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1188 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1191 vlc_mutex_unlock( &kate_decoder_list_mutex );
1198 /*****************************************************************************
1199 * DecodePacket: decodes a Kate packet.
1200 *****************************************************************************/
1201 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1203 decoder_sys_t *p_sys = p_dec->p_sys;
1204 const kate_event *ev = NULL;
1205 subpicture_t *p_spu = NULL;
1208 if( !p_sys->b_ready )
1210 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1214 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1217 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1221 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1224 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1229 /* no event to go with this packet, this is normal */
1233 /* we have an event */
1236 p_spu = decoder_NewSubpicture( p_dec );
1239 /* this will happen for lyrics as there is no vout - so no error */
1240 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1244 p_spu->i_start = p_block->i_pts;
1245 p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1246 p_spu->b_ephemer = false;
1247 p_spu->b_absolute = false;
1250 if( p_sys->b_use_tiger)
1252 /* setup the structure to get our decoder struct back */
1253 p_spu->p_sys = malloc( sizeof( subpicture_sys_t ));
1256 decoder_DeleteSubpicture( p_dec, p_spu );
1259 p_spu->p_sys->p_dec_sys = p_sys;
1260 p_spu->p_sys->i_start = p_block->i_pts;
1261 DecSysHold( p_sys );
1263 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1264 p_spu->b_ephemer = true;
1265 p_spu->b_absolute = true;
1267 /* add the event to tiger */
1268 vlc_mutex_lock( &p_sys->lock );
1269 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1270 vlc_mutex_unlock( &p_sys->lock );
1272 /* hookup render/update routines */
1273 p_spu->pf_update_regions = TigerUpdateRegions;
1274 p_spu->pf_destroy = TigerDestroySubpicture;
1279 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1285 /*****************************************************************************
1286 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1287 *****************************************************************************/
1288 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1289 const kate_event *ev )
1291 decoder_sys_t *p_sys = p_dec->p_sys;
1293 subpicture_region_t *p_bitmap_region = NULL;
1294 video_palette_t palette;
1296 bool b_tracker_valid = false;
1299 /* these may be 0 for "not specified" */
1300 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1301 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1303 /* Create a new subpicture region */
1304 memset( &fmt, 0, sizeof(video_format_t) );
1306 if (p_sys->b_formatted)
1308 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1311 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1315 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1316 GetVideoSize(p_dec, &w, &h);
1317 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1320 kate_tracker_clear(&kin);
1321 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1325 // TODO: parse tracker and set style, init fmt
1326 b_tracker_valid = true;
1331 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1333 /* create a separate region for the bitmap */
1334 memset( &fmt, 0, sizeof(video_format_t) );
1335 fmt.i_chroma = VLC_CODEC_YUVP;
1337 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1338 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1339 fmt.i_x_offset = fmt.i_y_offset = 0;
1340 fmt.p_palette = &palette;
1341 CreateKatePalette( fmt.p_palette, ev->palette );
1343 p_bitmap_region = subpicture_region_New( &fmt );
1344 if( !p_bitmap_region )
1346 msg_Err( p_dec, "cannot allocate SPU region" );
1347 decoder_DeleteSubpicture( p_dec, p_spu );
1351 /* create the bitmap */
1352 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1354 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1358 fmt.i_chroma = VLC_CODEC_TEXT;
1360 fmt.i_width = fmt.i_height = 0;
1361 fmt.i_x_offset = fmt.i_y_offset = 0;
1362 p_spu->p_region = subpicture_region_New( &fmt );
1363 if( !p_spu->p_region )
1365 msg_Err( p_dec, "cannot allocate SPU region" );
1366 decoder_DeleteSubpicture( p_dec, p_spu );
1370 SetupText( p_dec, p_spu, ev );
1372 /* default positioning */
1373 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1374 if (p_bitmap_region)
1376 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1378 p_spu->p_region->i_x = 0;
1379 p_spu->p_region->i_y = 10;
1381 /* override if tracker info present */
1382 if (b_tracker_valid)
1386 p_spu->p_region->i_x = kin.region_x;
1387 p_spu->p_region->i_y = kin.region_y;
1388 if (p_bitmap_region)
1390 p_bitmap_region->i_x = kin.region_x;
1391 p_bitmap_region->i_y = kin.region_y;
1393 p_spu->b_absolute = true;
1396 kate_tracker_clear(&kin);
1399 /* if we have a bitmap, chain it before the text */
1400 if (p_bitmap_region)
1402 p_bitmap_region->p_next = p_spu->p_region;
1403 p_spu->p_region = p_bitmap_region;
1409 /*****************************************************************************
1410 * ParseKateComments:
1411 *****************************************************************************/
1412 static void ParseKateComments( decoder_t *p_dec )
1414 char *psz_name, *psz_value, *psz_comment;
1417 while ( i < p_dec->p_sys->kc.comments )
1419 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1422 psz_name = psz_comment;
1423 psz_value = strchr( psz_comment, '=' );
1429 if( !p_dec->p_description )
1430 p_dec->p_description = vlc_meta_New();
1431 if( p_dec->p_description )
1432 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1434 free( psz_comment );
1439 /*****************************************************************************
1440 * CloseDecoder: clean up the decoder
1441 *****************************************************************************/
1442 static void CloseDecoder( vlc_object_t *p_this )
1444 decoder_t *p_dec = (decoder_t *)p_this;
1447 /* remove the decoder from the global list */
1448 vlc_mutex_lock( &kate_decoder_list_mutex );
1449 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1451 if( kate_decoder_list[ i_index ] == p_dec )
1453 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1457 vlc_mutex_unlock( &kate_decoder_list_mutex );
1459 msg_Dbg( p_dec, "Closing Kate decoder" );
1460 DecSysRelease( p_dec->p_sys );
1463 static void DecSysHold( decoder_sys_t *p_sys )
1465 vlc_mutex_lock( &p_sys->lock );
1466 p_sys->i_refcount++;
1467 vlc_mutex_unlock( &p_sys->lock );
1470 static void DecSysRelease( decoder_sys_t *p_sys )
1472 vlc_mutex_lock( &p_sys->lock );
1473 p_sys->i_refcount--;
1474 if( p_sys->i_refcount > 0)
1476 vlc_mutex_unlock( &p_sys->lock );
1480 vlc_mutex_unlock( &p_sys->lock );
1481 vlc_mutex_destroy( &p_sys->lock );
1485 tiger_renderer_destroy( p_sys->p_tr );
1486 if( p_sys->psz_tiger_default_font_desc )
1487 free( p_sys->psz_tiger_default_font_desc );
1491 kate_clear( &p_sys->k );
1492 kate_info_clear( &p_sys->ki );
1493 kate_comment_clear( &p_sys->kc );