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;
348 if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
353 msg_Dbg( p_dec, "kate: OpenDecoder");
356 p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
358 p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **))
361 /* Allocate the memory needed to store the decoder's structure */
362 if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
365 vlc_mutex_init( &p_sys->lock );
366 p_sys->i_refcount = 0;
370 #ifdef ENABLE_PACKETIZER
371 p_sys->b_packetizer = false;
373 p_sys->b_ready = false;
375 p_sys->i_max_stop = VLC_TS_INVALID;
377 kate_comment_init( &p_sys->kc );
378 kate_info_init( &p_sys->ki );
380 p_sys->i_num_headers = 0;
381 p_sys->i_headers = 0;
383 /* retrieve options */
384 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
386 vlc_mutex_lock( &kate_decoder_list_mutex );
390 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
393 p_sys->last_render_ts = 0;
395 /* get initial value of configuration */
396 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
397 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
398 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
399 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
400 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
401 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
403 if( p_sys->b_use_tiger )
405 int i_ret = tiger_renderer_create( &p_sys->p_tr );
408 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
410 p_sys->b_use_tiger = false;
413 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
415 UpdateTigerFontEffect( p_dec );
416 UpdateTigerFontColor( p_dec );
417 UpdateTigerBackgroundColor( p_dec );
418 UpdateTigerQuality( p_dec );
419 UpdateTigerFontDesc( p_dec );
424 p_sys->b_use_tiger = false;
428 es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );
430 /* add the decoder to the global list */
431 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
434 list[ kate_decoder_list_size++ ] = p_dec;
435 kate_decoder_list = list;
438 vlc_mutex_unlock( &kate_decoder_list_mutex );
443 #ifdef ENABLE_PACKETIZER
444 static int OpenPacketizer( vlc_object_t *p_this )
446 decoder_t *p_dec = (decoder_t*)p_this;
448 int i_ret = OpenDecoder( p_this );
450 if( i_ret == VLC_SUCCESS )
452 p_dec->p_sys->b_packetizer = true;
453 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
460 /****************************************************************************
461 * DecodeBlock: the whole thing
462 ****************************************************************************
463 * This function must be fed with kate packets.
464 ****************************************************************************/
465 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
467 decoder_sys_t *p_sys = p_dec->p_sys;
471 if( !pp_block || !*pp_block )
476 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
479 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
481 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
482 vlc_mutex_lock( &p_sys->lock );
483 tiger_renderer_seek( p_sys->p_tr, 0 );
484 vlc_mutex_unlock( &p_sys->lock );
487 p_sys->i_max_stop = VLC_TS_INVALID;
488 block_Release( p_block );
492 /* Block to Kate packet */
493 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
495 if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
497 /* Headers already available as extra data */
498 p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
499 p_sys->i_headers = p_sys->i_num_headers;
501 else if( kp.nbytes && (p_sys->i_headers==0 || p_sys->i_headers < p_sys->ki.num_headers ))
503 /* Backup headers as extra data */
506 p_dec->fmt_in.p_extra = xrealloc( p_dec->fmt_in.p_extra,
507 p_dec->fmt_in.i_extra + kp.nbytes + 2 );
508 p_extra = (void*)(((unsigned char*)p_dec->fmt_in.p_extra) + p_dec->fmt_in.i_extra);
509 *(p_extra++) = kp.nbytes >> 8;
510 *(p_extra++) = kp.nbytes & 0xFF;
512 memcpy( p_extra, kp.data, kp.nbytes );
513 p_dec->fmt_in.i_extra += kp.nbytes + 2;
515 block_Release( *pp_block );
516 p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
521 if( p_sys->i_headers == p_sys->i_num_headers && p_sys->i_num_headers>0 )
523 if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
525 p_sys->i_headers = 0;
526 p_dec->fmt_in.i_extra = 0;
527 block_Release( *pp_block );
530 else p_sys->i_headers++;
533 return ProcessPacket( p_dec, &kp, pp_block );
536 /*****************************************************************************
537 * ProcessHeaders: process Kate headers.
538 *****************************************************************************/
539 static int ProcessHeaders( decoder_t *p_dec )
541 decoder_sys_t *p_sys = p_dec->p_sys;
548 if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
550 p_extra = p_dec->fmt_in.p_extra;
551 i_extra = p_dec->fmt_in.i_extra;
553 /* skip number of headers */
557 /* Take care of the initial Kate header */
558 kp.nbytes = *(p_extra++) << 8;
559 kp.nbytes |= (*(p_extra++) & 0xFF);
561 p_extra += kp.nbytes;
562 i_extra -= (kp.nbytes + 2);
565 msg_Err( p_dec, "header data corrupted");
569 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
572 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
576 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
577 p_sys->ki.language, p_sys->ki.category,
578 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
579 p_sys->ki.granule_shift);
581 /* parse all remaining header packets */
582 for( i_headeridx = 1; i_headeridx < p_sys->ki.num_headers; ++i_headeridx )
584 kp.nbytes = *(p_extra++) << 8;
585 kp.nbytes |= (*(p_extra++) & 0xFF);
587 p_extra += kp.nbytes;
588 i_extra -= (kp.nbytes + 2);
591 msg_Err( p_dec, "header %d data corrupted", i_headeridx );
595 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
598 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
602 /* header 1 is comments */
603 if( i_headeridx == 1 )
605 ParseKateComments( p_dec );
609 #ifdef ENABLE_PACKETIZER
610 if( !p_sys->b_packetizer )
613 /* We have all the headers, initialize decoder */
614 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
615 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
618 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
621 p_sys->b_ready = true;
623 #ifdef ENABLE_PACKETIZER
626 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
627 p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
628 p_dec->fmt_out.i_extra );
629 memcpy( p_dec->fmt_out.p_extra,
630 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
637 /*****************************************************************************
638 * ProcessPacket: processes a kate packet.
639 *****************************************************************************/
640 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
643 decoder_sys_t *p_sys = p_dec->p_sys;
644 block_t *p_block = *pp_block;
645 subpicture_t *p_buf = NULL;
647 /* Date management */
648 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
650 p_sys->i_pts = p_block->i_pts;
653 *pp_block = NULL; /* To avoid being fed the same packet again */
655 #ifdef ENABLE_PACKETIZER
656 if( p_sys->b_packetizer )
658 /* Date management */
659 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
661 if( p_sys->i_headers >= p_sys->i_num_headers )
662 p_block->i_length = p_sys->i_pts - p_block->i_pts;
664 p_block->i_length = 0;
671 if( p_sys->i_headers >= p_sys->i_num_headers && p_sys->i_num_headers > 0)
672 p_buf = DecodePacket( p_dec, p_kp, p_block );
676 if( p_block ) block_Release( p_block );
682 /* nicked off blend.c */
683 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
684 int r, int g, int b )
686 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
687 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
688 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
692 This retrieves the size of the video.
693 The best case is when the original video size is known, as we can then
694 scale images to match. In this case, since VLC autoscales, we want to
695 return the original size and let VLC scale everything.
696 if the original size is not known, then VLC can't resize, so we return
697 the size of the incoming video. If sizes in the Kate stream are in
698 relative units, it works fine. If they are absolute, you get what you
699 ask for. Images aren't rescaled.
701 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
703 /* searching for vout to get its size is frowned upon, so we don't and
704 use a default size if the original canvas size is not specified. */
706 decoder_sys_t *p_sys = p_dec->p_sys;
707 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
709 *w = p_sys->ki.original_canvas_width;
710 *h = p_sys->ki.original_canvas_height;
711 msg_Dbg( p_dec, "original canvas %zu %zu",
712 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
716 /* nothing, leave defaults */
717 msg_Dbg( p_dec, "original canvas size unknown");
720 /* keep this just in case it might be allowed one day ;) */
721 vout_thread_t *p_vout;
722 p_vout = vlc_object_find( (vlc_object_t*)p_dec, VLC_OBJECT_VOUT, FIND_CHILD );
725 decoder_sys_t *p_sys = p_dec->p_sys;
726 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
728 *w = p_sys->ki.original_canvas_width;
729 *h = p_sys->ki.original_canvas_height;
733 *w = p_vout->fmt_in.i_width;
734 *h = p_vout->fmt_in.i_height;
736 msg_Dbg( p_dec, "video: in %d %d, out %d %d, original canvas %zu %zu",
737 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
738 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
739 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
740 vlc_object_release( p_vout );
745 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
749 for( y=0; y<bitmap->height; ++y )
751 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
752 const uint8_t *src = bitmap->pixels+y*bitmap->width;
753 memcpy( dest, src, bitmap->width );
757 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
761 fmt_palette->i_entries = palette->ncolors;
762 for( n=0; n<palette->ncolors; ++n )
765 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
766 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
768 fmt_palette->palette[n][3] = palette->colors[n].a;
772 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
774 decoder_sys_t *p_sys = p_dec->p_sys;
776 if( ev->text_encoding != kate_utf8 )
778 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
782 switch( ev->text_markup_type )
784 case kate_markup_none:
785 p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
787 case kate_markup_simple:
788 if( p_sys->b_formatted )
790 /* the HTML renderer expects a top level text tag pair */
792 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
794 p_spu->p_region->psz_html = buffer;
798 /* if not formatted, we fall through */
800 /* we don't know about this one, so remove markup and display as text */
802 char *copy = strdup( ev->text );
803 size_t len0 = strlen( copy ) + 1;
804 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
805 p_spu->p_region->psz_text = copy;
813 static void TigerDestroySubpicture( subpicture_t *p_subpic )
815 DecSysRelease( p_subpic->p_sys->p_dec_sys );
818 static void SubpictureReleaseRegions( subpicture_t *p_subpic )
820 if( p_subpic->p_region)
822 subpicture_region_ChainDelete( p_subpic->p_region );
823 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 = p_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 );
880 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
881 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
882 Looks good with white though since it's all luma. Hopefully that will be the
884 static void TigerUpdateRegions( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt, mtime_t ts )
886 decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys;
887 subpicture_region_t *p_r;
895 PROFILE_START( TigerUpdateRegions );
897 /* do not render more than once per frame, libtiger renders all events at once */
898 if (ts <= p_sys->last_render_ts)
900 SubpictureReleaseRegions( p_subpic );
904 /* remember what frame we've rendered already */
905 p_sys->last_render_ts = ts;
907 /* time in seconds from the start of the stream */
908 t = (p_subpic->p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
910 /* it is likely that the current region (if any) can be kept as is; test for this */
911 vlc_mutex_lock( &p_sys->lock );
912 if( p_subpic->p_region && !p_sys->b_dirty && !tiger_renderer_is_dirty( p_sys->p_tr ))
914 PROFILE_START( tiger_renderer_update1 );
915 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
916 PROFILE_STOP( tiger_renderer_update1 );
919 SubpictureReleaseRegions( p_subpic );
920 vlc_mutex_unlock( &p_sys->lock );
924 if( !tiger_renderer_is_dirty( p_sys->p_tr ) )
926 /* we can keep the current region list */
927 PROFILE_STOP( TigerUpdateRegions );
928 vlc_mutex_unlock( &p_sys->lock );
932 vlc_mutex_unlock( &p_sys->lock );
934 /* we have to render again, reset current region list */
935 SubpictureReleaseRegions( p_subpic );
937 /* create a full frame region - this will also tell Tiger the size of the frame */
939 fmt.i_chroma = VLC_CODEC_RGBA;
940 fmt.i_width = fmt.i_visible_width;
941 fmt.i_height = fmt.i_visible_height;
942 fmt.i_bits_per_pixel = 0;
943 fmt.i_x_offset = fmt.i_y_offset = 0;
945 p_r = subpicture_region_New( &fmt );
953 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
955 vlc_mutex_lock( &p_sys->lock );
957 p_plane = &p_r->p_picture->p[0];
958 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 );
964 PROFILE_START( tiger_renderer_update );
965 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
970 PROFILE_STOP( tiger_renderer_update );
972 PROFILE_START( tiger_renderer_render );
973 i_ret = tiger_renderer_render( p_sys->p_tr );
978 PROFILE_STOP( tiger_renderer_render );
981 PostprocessTigerImage( p_plane, fmt.i_width );
983 p_subpic->p_region = p_r;
984 p_sys->b_dirty = false;
986 PROFILE_STOP( TigerUpdateRegions );
988 vlc_mutex_unlock( &p_sys->lock );
993 vlc_mutex_unlock( &p_sys->lock );
994 subpicture_region_ChainDelete( p_r );
997 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
1000 uint32_t i_color = 0;
1002 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
1004 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
1005 var_Destroy( p_dec, psz_tmp );
1010 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
1012 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
1013 var_Destroy( p_dec, psz_tmp );
1015 i_color |= (i_alpha << 24);
1021 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
1023 char *psz_value = var_CreateGetString( p_dec, psz_name );
1026 psz_value = strdup( psz_value );
1028 var_Destroy( p_dec, psz_name );
1032 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
1034 int i_value = var_CreateGetInteger( p_dec, psz_name );
1035 var_Destroy( p_dec, psz_name );
1039 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
1041 double f_value = var_CreateGetFloat( p_dec, psz_name );
1042 var_Destroy( p_dec, psz_name );
1046 static void UpdateTigerQuality( decoder_t *p_dec )
1048 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1049 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
1050 p_sys->b_dirty = true;
1053 static void UpdateTigerFontDesc( decoder_t *p_dec )
1055 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1056 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
1057 p_sys->b_dirty = true;
1060 static void UpdateTigerFontColor( decoder_t *p_dec )
1062 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1063 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
1064 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
1065 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
1066 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
1067 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1068 p_sys->b_dirty = true;
1071 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
1073 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1074 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
1075 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1076 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1077 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1078 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1079 p_sys->b_dirty = true;
1082 static void UpdateTigerFontEffect( decoder_t *p_dec )
1084 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1085 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1086 p_sys->e_tiger_default_font_effect,
1087 p_sys->f_tiger_default_font_effect_strength ) );
1088 p_sys->b_dirty = true;
1091 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1092 vlc_value_t oldval, vlc_value_t newval )
1094 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1096 VLC_UNUSED( oldval );
1098 vlc_mutex_lock( &p_sys->lock );
1100 msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1102 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1104 vlc_mutex_unlock( &p_sys->lock );
1108 #define TEST_TIGER_VAR( name ) \
1109 if( !strcmp( name, psz_var ) )
1111 TEST_TIGER_VAR( "kate-tiger-quality" )
1113 p_sys->f_tiger_quality = newval.f_float;
1114 UpdateTigerQuality( p_dec );
1117 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1119 if( p_sys->psz_tiger_default_font_desc )
1121 free( p_sys->psz_tiger_default_font_desc );
1122 p_sys->psz_tiger_default_font_desc = NULL;
1124 if( newval.psz_string )
1126 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1128 UpdateTigerFontDesc( p_dec );
1131 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1133 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1134 UpdateTigerFontColor( p_dec );
1137 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1139 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1140 UpdateTigerFontColor( p_dec );
1143 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1145 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1146 UpdateTigerBackgroundColor( p_dec );
1149 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1151 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1152 UpdateTigerBackgroundColor( p_dec );
1155 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1157 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1158 UpdateTigerFontEffect( p_dec );
1161 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1163 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1164 UpdateTigerFontEffect( p_dec );
1167 #undef TEST_TIGER_VAR
1169 vlc_mutex_unlock( &p_sys->lock );
1174 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1175 vlc_value_t oldval, vlc_value_t newval,
1180 VLC_UNUSED( p_this );
1181 VLC_UNUSED( oldval );
1182 VLC_UNUSED( newval );
1183 VLC_UNUSED( p_data );
1185 vlc_mutex_lock( &kate_decoder_list_mutex );
1187 /* Update all existing decoders from the global user prefs */
1188 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1190 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1191 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1194 vlc_mutex_unlock( &kate_decoder_list_mutex );
1201 /*****************************************************************************
1202 * DecodePacket: decodes a Kate packet.
1203 *****************************************************************************/
1204 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1206 decoder_sys_t *p_sys = p_dec->p_sys;
1207 const kate_event *ev = NULL;
1208 subpicture_t *p_spu = NULL;
1211 if( !p_sys->b_ready )
1213 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1217 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1220 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1224 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1227 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1232 /* no event to go with this packet, this is normal */
1236 /* we have an event */
1239 p_spu = decoder_NewSubpicture( p_dec );
1242 /* this will happen for lyrics as there is no vout - so no error */
1243 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1247 p_spu->i_start = p_block->i_pts;
1248 p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1249 p_spu->b_ephemer = false;
1250 p_spu->b_absolute = false;
1253 if( p_sys->b_use_tiger)
1255 /* setup the structure to get our decoder struct back */
1256 p_spu->p_sys = malloc( sizeof( subpicture_sys_t ));
1259 decoder_DeleteSubpicture( p_dec, p_spu );
1262 p_spu->p_sys->p_dec_sys = p_sys;
1263 p_spu->p_sys->i_start = p_block->i_pts;
1264 DecSysHold( p_sys );
1266 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1267 p_spu->b_ephemer = true;
1268 p_spu->b_absolute = true;
1270 /* add the event to tiger */
1271 vlc_mutex_lock( &p_sys->lock );
1272 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1273 vlc_mutex_unlock( &p_sys->lock );
1275 /* hookup render/update routines */
1276 p_spu->pf_update_regions = TigerUpdateRegions;
1277 p_spu->pf_destroy = TigerDestroySubpicture;
1282 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1288 /*****************************************************************************
1289 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1290 *****************************************************************************/
1291 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1292 const kate_event *ev )
1294 decoder_sys_t *p_sys = p_dec->p_sys;
1296 subpicture_region_t *p_bitmap_region = NULL;
1297 video_palette_t palette;
1299 bool b_tracker_valid = false;
1302 /* these may be 0 for "not specified" */
1303 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1304 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1306 /* Create a new subpicture region */
1307 memset( &fmt, 0, sizeof(video_format_t) );
1309 if (p_sys->b_formatted)
1311 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1314 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1318 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1319 GetVideoSize(p_dec, &w, &h);
1320 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1323 kate_tracker_clear(&kin);
1324 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1328 // TODO: parse tracker and set style, init fmt
1329 b_tracker_valid = true;
1334 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1336 /* create a separate region for the bitmap */
1337 memset( &fmt, 0, sizeof(video_format_t) );
1338 fmt.i_chroma = VLC_CODEC_YUVP;
1339 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1340 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1341 fmt.i_x_offset = fmt.i_y_offset = 0;
1342 fmt.p_palette = &palette;
1343 CreateKatePalette( fmt.p_palette, ev->palette );
1345 p_bitmap_region = subpicture_region_New( &fmt );
1346 if( !p_bitmap_region )
1348 msg_Err( p_dec, "cannot allocate SPU region" );
1349 decoder_DeleteSubpicture( p_dec, p_spu );
1353 /* create the bitmap */
1354 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1356 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1360 fmt.i_chroma = VLC_CODEC_TEXT;
1363 fmt.i_width = fmt.i_height = 0;
1364 fmt.i_x_offset = fmt.i_y_offset = 0;
1365 p_spu->p_region = subpicture_region_New( &fmt );
1366 if( !p_spu->p_region )
1368 msg_Err( p_dec, "cannot allocate SPU region" );
1369 decoder_DeleteSubpicture( p_dec, p_spu );
1373 SetupText( p_dec, p_spu, ev );
1375 /* default positioning */
1376 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1377 if (p_bitmap_region)
1379 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1381 p_spu->p_region->i_x = 0;
1382 p_spu->p_region->i_y = 10;
1384 /* override if tracker info present */
1385 if (b_tracker_valid)
1389 p_spu->p_region->i_x = kin.region_x;
1390 p_spu->p_region->i_y = kin.region_y;
1391 if (p_bitmap_region)
1393 p_bitmap_region->i_x = kin.region_x;
1394 p_bitmap_region->i_y = kin.region_y;
1396 p_spu->b_absolute = true;
1399 kate_tracker_clear(&kin);
1402 /* if we have a bitmap, chain it before the text */
1403 if (p_bitmap_region)
1405 p_bitmap_region->p_next = p_spu->p_region;
1406 p_spu->p_region = p_bitmap_region;
1412 /*****************************************************************************
1413 * ParseKateComments:
1414 *****************************************************************************/
1415 static void ParseKateComments( decoder_t *p_dec )
1417 char *psz_name, *psz_value, *psz_comment;
1420 while ( i < p_dec->p_sys->kc.comments )
1422 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1425 psz_name = psz_comment;
1426 psz_value = strchr( psz_comment, '=' );
1432 if( !p_dec->p_description )
1433 p_dec->p_description = vlc_meta_New();
1434 if( p_dec->p_description )
1435 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1437 free( psz_comment );
1442 /*****************************************************************************
1443 * CloseDecoder: clean up the decoder
1444 *****************************************************************************/
1445 static void CloseDecoder( vlc_object_t *p_this )
1447 decoder_t *p_dec = (decoder_t *)p_this;
1450 /* remove the decoder from the global list */
1451 vlc_mutex_lock( &kate_decoder_list_mutex );
1452 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1454 if( kate_decoder_list[ i_index ] == p_dec )
1456 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1460 vlc_mutex_unlock( &kate_decoder_list_mutex );
1462 msg_Dbg( p_dec, "Closing Kate decoder" );
1463 DecSysRelease( p_dec->p_sys );
1466 static void DecSysHold( decoder_sys_t *p_sys )
1468 vlc_mutex_lock( &p_sys->lock );
1469 p_sys->i_refcount++;
1470 vlc_mutex_unlock( &p_sys->lock );
1473 static void DecSysRelease( decoder_sys_t *p_sys )
1475 vlc_mutex_lock( &p_sys->lock );
1476 p_sys->i_refcount--;
1477 if( p_sys->i_refcount > 0)
1479 vlc_mutex_unlock( &p_sys->lock );
1483 vlc_mutex_unlock( &p_sys->lock );
1484 vlc_mutex_destroy( &p_sys->lock );
1488 tiger_renderer_destroy( p_sys->p_tr );
1489 free( p_sys->psz_tiger_default_font_desc );
1493 kate_clear( &p_sys->k );
1494 kate_info_clear( &p_sys->ki );
1495 kate_comment_clear( &p_sys->kc );