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>
36 #include "../demux/xiph.h"
38 #include <kate/kate.h>
40 # include <tiger/tiger.h>
43 /* #define ENABLE_PACKETIZER */
44 /* #define ENABLE_PROFILE */
47 # define PROFILE_START(name) int64_t profile_start_##name = mdate()
48 # define PROFILE_STOP(name) fprintf( stderr, #name ": %f ms\n", (mdate() - profile_start_##name)/1000.0f )
50 # define PROFILE_START(name) ((void)0)
51 # define PROFILE_STOP(name) ((void)0)
54 #define CHECK_TIGER_RET( statement ) \
57 int i_ret = (statement); \
60 msg_Dbg( p_dec, "Error in " #statement ": %d", i_ret ); \
64 /*****************************************************************************
65 * decoder_sys_t : decoder descriptor
66 *****************************************************************************/
69 #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->b_has_headers = false;
382 /* retrieve options */
383 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
385 vlc_mutex_lock( &kate_decoder_list_mutex );
389 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
392 p_sys->last_render_ts = 0;
394 /* get initial value of configuration */
395 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
396 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
397 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
398 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
399 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
400 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
402 if( p_sys->b_use_tiger )
404 int i_ret = tiger_renderer_create( &p_sys->p_tr );
407 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
409 p_sys->b_use_tiger = false;
412 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
414 UpdateTigerFontEffect( p_dec );
415 UpdateTigerFontColor( p_dec );
416 UpdateTigerBackgroundColor( p_dec );
417 UpdateTigerQuality( p_dec );
418 UpdateTigerFontDesc( p_dec );
423 p_sys->b_use_tiger = false;
427 es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );
429 /* add the decoder to the global list */
430 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
433 list[ kate_decoder_list_size++ ] = p_dec;
434 kate_decoder_list = list;
437 vlc_mutex_unlock( &kate_decoder_list_mutex );
442 #ifdef ENABLE_PACKETIZER
443 static int OpenPacketizer( vlc_object_t *p_this )
445 decoder_t *p_dec = (decoder_t*)p_this;
447 int i_ret = OpenDecoder( p_this );
449 if( i_ret == VLC_SUCCESS )
451 p_dec->p_sys->b_packetizer = true;
452 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
459 /****************************************************************************
460 * DecodeBlock: the whole thing
461 ****************************************************************************
462 * This function must be fed with kate packets.
463 ****************************************************************************/
464 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
466 decoder_sys_t *p_sys = p_dec->p_sys;
470 if( !pp_block || !*pp_block )
475 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
478 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
480 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
481 vlc_mutex_lock( &p_sys->lock );
482 tiger_renderer_seek( p_sys->p_tr, 0 );
483 vlc_mutex_unlock( &p_sys->lock );
486 p_sys->i_max_stop = VLC_TS_INVALID;
487 block_Release( p_block );
491 /* Block to Kate packet */
492 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
494 if( !p_sys->b_has_headers )
496 if( ProcessHeaders( p_dec ) )
498 block_Release( *pp_block );
501 p_sys->b_has_headers = true;
504 return ProcessPacket( p_dec, &kp, pp_block );
507 /*****************************************************************************
508 * ProcessHeaders: process Kate headers.
509 *****************************************************************************/
510 static int ProcessHeaders( decoder_t *p_dec )
512 decoder_sys_t *p_sys = p_dec->p_sys;
515 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
516 void *pp_data[XIPH_MAX_HEADER_COUNT];
518 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
519 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
521 int i_ret = VLC_SUCCESS;
524 i_ret = VLC_EGENERIC;
528 /* Take care of the initial Kate header */
529 kp.nbytes = pi_size[0];
530 kp.data = pp_data[0];
531 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
534 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
538 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
539 p_sys->ki.language, p_sys->ki.category,
540 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
541 p_sys->ki.granule_shift);
543 /* parse all remaining header packets */
544 for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
546 kp.nbytes = pi_size[i_headeridx];
547 kp.data = pp_data[i_headeridx];
548 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
551 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
555 /* header 1 is comments */
556 if( i_headeridx == 1 )
558 ParseKateComments( p_dec );
562 #ifdef ENABLE_PACKETIZER
563 if( !p_sys->b_packetizer )
566 /* We have all the headers, initialize decoder */
567 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
568 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
571 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
574 p_sys->b_ready = true;
576 #ifdef ENABLE_PACKETIZER
579 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
580 p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
581 p_dec->fmt_out.i_extra );
582 memcpy( p_dec->fmt_out.p_extra,
583 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
588 for( unsigned i = 0; i < i_count; i++ )
590 return i_ret < 0 ? VLC_EGENERIC : VLC_SUCCESS;
593 /*****************************************************************************
594 * ProcessPacket: processes a kate packet.
595 *****************************************************************************/
596 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
599 decoder_sys_t *p_sys = p_dec->p_sys;
600 block_t *p_block = *pp_block;
601 subpicture_t *p_buf = NULL;
603 /* Date management */
604 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
606 p_sys->i_pts = p_block->i_pts;
609 *pp_block = NULL; /* To avoid being fed the same packet again */
611 #ifdef ENABLE_PACKETIZER
612 if( p_sys->b_packetizer )
614 /* Date management */
615 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
617 if( p_sys->i_headers >= p_sys->i_num_headers )
618 p_block->i_length = p_sys->i_pts - p_block->i_pts;
620 p_block->i_length = 0;
627 p_buf = DecodePacket( p_dec, p_kp, p_block );
630 block_Release( p_block );
636 /* nicked off blend.c */
637 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
638 int r, int g, int b )
640 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
641 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
642 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
646 This retrieves the size of the video.
647 The best case is when the original video size is known, as we can then
648 scale images to match. In this case, since VLC autoscales, we want to
649 return the original size and let VLC scale everything.
650 if the original size is not known, then VLC can't resize, so we return
651 the size of the incoming video. If sizes in the Kate stream are in
652 relative units, it works fine. If they are absolute, you get what you
653 ask for. Images aren't rescaled.
655 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
657 /* searching for vout to get its size is frowned upon, so we don't and
658 use a default size if the original canvas size is not specified. */
660 decoder_sys_t *p_sys = p_dec->p_sys;
661 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
663 *w = p_sys->ki.original_canvas_width;
664 *h = p_sys->ki.original_canvas_height;
665 msg_Dbg( p_dec, "original canvas %zu %zu",
666 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
670 /* nothing, leave defaults */
671 msg_Dbg( p_dec, "original canvas size unknown");
674 /* keep this just in case it might be allowed one day ;) */
675 vout_thread_t *p_vout;
676 p_vout = vlc_object_find( (vlc_object_t*)p_dec, VLC_OBJECT_VOUT, FIND_CHILD );
679 decoder_sys_t *p_sys = p_dec->p_sys;
680 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
682 *w = p_sys->ki.original_canvas_width;
683 *h = p_sys->ki.original_canvas_height;
687 *w = p_vout->fmt_in.i_width;
688 *h = p_vout->fmt_in.i_height;
690 msg_Dbg( p_dec, "video: in %d %d, out %d %d, original canvas %zu %zu",
691 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
692 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
693 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
694 vlc_object_release( p_vout );
699 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
703 for( y=0; y<bitmap->height; ++y )
705 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
706 const uint8_t *src = bitmap->pixels+y*bitmap->width;
707 memcpy( dest, src, bitmap->width );
711 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
715 fmt_palette->i_entries = palette->ncolors;
716 for( n=0; n<palette->ncolors; ++n )
719 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
720 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
722 fmt_palette->palette[n][3] = palette->colors[n].a;
726 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
728 decoder_sys_t *p_sys = p_dec->p_sys;
730 if( ev->text_encoding != kate_utf8 )
732 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
736 switch( ev->text_markup_type )
738 case kate_markup_none:
739 p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
741 case kate_markup_simple:
742 if( p_sys->b_formatted )
744 /* the HTML renderer expects a top level text tag pair */
746 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
748 p_spu->p_region->psz_html = buffer;
752 /* if not formatted, we fall through */
754 /* we don't know about this one, so remove markup and display as text */
756 char *copy = strdup( ev->text );
757 size_t len0 = strlen( copy ) + 1;
758 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
759 p_spu->p_region->psz_text = copy;
767 static void TigerDestroySubpicture( subpicture_t *p_subpic )
769 DecSysRelease( p_subpic->p_sys->p_dec_sys );
772 static void SubpictureReleaseRegions( subpicture_t *p_subpic )
774 if( p_subpic->p_region)
776 subpicture_region_ChainDelete( p_subpic->p_region );
777 p_subpic->p_region = NULL;
782 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
783 * alpha to avoid double multiply (and thus thinner text than we should)).
784 * Best would be to have VLC be able to handle premultiplied alpha, as it
785 * would be faster to blend as well.
787 * Also, we flip color components around for big endian machines, as Tiger
788 * outputs ARGB or ABGR (the one we selected here) in host endianness.
790 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
792 PROFILE_START( tiger_renderer_postprocess );
794 for( y=0; y<p_plane->i_lines; ++y )
796 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
798 for( x=0; x<i_width; ++x )
800 uint8_t *p_pixel = p_line+x*4;
801 #ifdef WORDS_BIGENDIAN
802 uint8_t a = p_pixel[0];
804 uint8_t a = p_pixel[3];
808 #ifdef WORDS_BIGENDIAN
809 uint8_t tmp = p_pixel[2];
810 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
812 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
813 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
815 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
816 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
817 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
829 PROFILE_STOP( tiger_renderer_postprocess );
832 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
833 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
834 Looks good with white though since it's all luma. Hopefully that will be the
836 static void TigerUpdateRegions( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt, mtime_t ts )
838 decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys;
839 subpicture_region_t *p_r;
847 PROFILE_START( TigerUpdateRegions );
849 /* do not render more than once per frame, libtiger renders all events at once */
850 if (ts <= p_sys->last_render_ts)
852 SubpictureReleaseRegions( p_subpic );
856 /* remember what frame we've rendered already */
857 p_sys->last_render_ts = ts;
859 /* time in seconds from the start of the stream */
860 t = (p_subpic->p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
862 /* it is likely that the current region (if any) can be kept as is; test for this */
863 vlc_mutex_lock( &p_sys->lock );
864 if( p_subpic->p_region && !p_sys->b_dirty && !tiger_renderer_is_dirty( p_sys->p_tr ))
866 PROFILE_START( tiger_renderer_update1 );
867 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
868 PROFILE_STOP( tiger_renderer_update1 );
871 SubpictureReleaseRegions( p_subpic );
872 vlc_mutex_unlock( &p_sys->lock );
876 if( !tiger_renderer_is_dirty( p_sys->p_tr ) )
878 /* we can keep the current region list */
879 PROFILE_STOP( TigerUpdateRegions );
880 vlc_mutex_unlock( &p_sys->lock );
884 vlc_mutex_unlock( &p_sys->lock );
886 /* we have to render again, reset current region list */
887 SubpictureReleaseRegions( p_subpic );
889 /* create a full frame region - this will also tell Tiger the size of the frame */
891 fmt.i_chroma = VLC_CODEC_RGBA;
892 fmt.i_width = fmt.i_visible_width;
893 fmt.i_height = fmt.i_visible_height;
894 fmt.i_bits_per_pixel = 0;
895 fmt.i_x_offset = fmt.i_y_offset = 0;
897 p_r = subpicture_region_New( &fmt );
905 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
907 vlc_mutex_lock( &p_sys->lock );
909 p_plane = &p_r->p_picture->p[0];
910 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 );
916 PROFILE_START( tiger_renderer_update );
917 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
922 PROFILE_STOP( tiger_renderer_update );
924 PROFILE_START( tiger_renderer_render );
925 i_ret = tiger_renderer_render( p_sys->p_tr );
930 PROFILE_STOP( tiger_renderer_render );
932 PostprocessTigerImage( p_plane, fmt.i_width );
933 p_subpic->p_region = p_r;
934 p_sys->b_dirty = false;
936 PROFILE_STOP( TigerUpdateRegions );
938 vlc_mutex_unlock( &p_sys->lock );
943 vlc_mutex_unlock( &p_sys->lock );
944 subpicture_region_ChainDelete( p_r );
947 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
950 uint32_t i_color = 0;
952 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
954 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
955 var_Destroy( p_dec, psz_tmp );
960 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
962 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
963 var_Destroy( p_dec, psz_tmp );
965 i_color |= (i_alpha << 24);
971 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
973 char *psz_value = var_CreateGetString( p_dec, psz_name );
976 psz_value = strdup( psz_value );
978 var_Destroy( p_dec, psz_name );
982 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
984 int i_value = var_CreateGetInteger( p_dec, psz_name );
985 var_Destroy( p_dec, psz_name );
989 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
991 double f_value = var_CreateGetFloat( p_dec, psz_name );
992 var_Destroy( p_dec, psz_name );
996 static void UpdateTigerQuality( decoder_t *p_dec )
998 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
999 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
1000 p_sys->b_dirty = true;
1003 static void UpdateTigerFontDesc( decoder_t *p_dec )
1005 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1006 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
1007 p_sys->b_dirty = true;
1010 static void UpdateTigerFontColor( decoder_t *p_dec )
1012 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1013 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
1014 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
1015 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
1016 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
1017 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1018 p_sys->b_dirty = true;
1021 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
1023 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1024 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
1025 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1026 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1027 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1028 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1029 p_sys->b_dirty = true;
1032 static void UpdateTigerFontEffect( decoder_t *p_dec )
1034 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1035 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1036 p_sys->e_tiger_default_font_effect,
1037 p_sys->f_tiger_default_font_effect_strength ) );
1038 p_sys->b_dirty = true;
1041 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1042 vlc_value_t oldval, vlc_value_t newval )
1044 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1046 VLC_UNUSED( oldval );
1048 vlc_mutex_lock( &p_sys->lock );
1050 msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1052 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1054 vlc_mutex_unlock( &p_sys->lock );
1058 #define TEST_TIGER_VAR( name ) \
1059 if( !strcmp( name, psz_var ) )
1061 TEST_TIGER_VAR( "kate-tiger-quality" )
1063 p_sys->f_tiger_quality = newval.f_float;
1064 UpdateTigerQuality( p_dec );
1067 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1069 if( p_sys->psz_tiger_default_font_desc )
1071 free( p_sys->psz_tiger_default_font_desc );
1072 p_sys->psz_tiger_default_font_desc = NULL;
1074 if( newval.psz_string )
1076 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1078 UpdateTigerFontDesc( p_dec );
1081 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1083 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1084 UpdateTigerFontColor( p_dec );
1087 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1089 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1090 UpdateTigerFontColor( p_dec );
1093 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1095 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1096 UpdateTigerBackgroundColor( p_dec );
1099 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1101 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1102 UpdateTigerBackgroundColor( p_dec );
1105 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1107 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1108 UpdateTigerFontEffect( p_dec );
1111 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1113 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1114 UpdateTigerFontEffect( p_dec );
1117 #undef TEST_TIGER_VAR
1119 vlc_mutex_unlock( &p_sys->lock );
1124 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1125 vlc_value_t oldval, vlc_value_t newval,
1130 VLC_UNUSED( p_this );
1131 VLC_UNUSED( oldval );
1132 VLC_UNUSED( newval );
1133 VLC_UNUSED( p_data );
1135 vlc_mutex_lock( &kate_decoder_list_mutex );
1137 /* Update all existing decoders from the global user prefs */
1138 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1140 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1141 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1144 vlc_mutex_unlock( &kate_decoder_list_mutex );
1151 /*****************************************************************************
1152 * DecodePacket: decodes a Kate packet.
1153 *****************************************************************************/
1154 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1156 decoder_sys_t *p_sys = p_dec->p_sys;
1157 const kate_event *ev = NULL;
1158 subpicture_t *p_spu = NULL;
1161 if( !p_sys->b_ready )
1163 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1167 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1170 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1174 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1177 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1182 /* no event to go with this packet, this is normal */
1186 /* we have an event */
1189 p_spu = decoder_NewSubpicture( p_dec );
1192 /* this will happen for lyrics as there is no vout - so no error */
1193 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1197 p_spu->i_start = p_block->i_pts;
1198 p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1199 p_spu->b_ephemer = false;
1200 p_spu->b_absolute = false;
1203 if( p_sys->b_use_tiger)
1205 /* setup the structure to get our decoder struct back */
1206 p_spu->p_sys = malloc( sizeof( subpicture_sys_t ));
1209 decoder_DeleteSubpicture( p_dec, p_spu );
1212 p_spu->p_sys->p_dec_sys = p_sys;
1213 p_spu->p_sys->i_start = p_block->i_pts;
1214 DecSysHold( p_sys );
1216 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1217 p_spu->b_ephemer = true;
1218 p_spu->b_absolute = true;
1220 /* add the event to tiger */
1221 vlc_mutex_lock( &p_sys->lock );
1222 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1223 vlc_mutex_unlock( &p_sys->lock );
1225 /* hookup render/update routines */
1226 p_spu->pf_update_regions = TigerUpdateRegions;
1227 p_spu->pf_destroy = TigerDestroySubpicture;
1232 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1238 /*****************************************************************************
1239 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1240 *****************************************************************************/
1241 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1242 const kate_event *ev )
1244 decoder_sys_t *p_sys = p_dec->p_sys;
1246 subpicture_region_t *p_bitmap_region = NULL;
1247 video_palette_t palette;
1249 bool b_tracker_valid = false;
1252 /* these may be 0 for "not specified" */
1253 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1254 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1256 /* Create a new subpicture region */
1257 memset( &fmt, 0, sizeof(video_format_t) );
1259 if (p_sys->b_formatted)
1261 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1264 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1268 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1269 GetVideoSize(p_dec, &w, &h);
1270 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1273 kate_tracker_clear(&kin);
1274 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1278 // TODO: parse tracker and set style, init fmt
1279 b_tracker_valid = true;
1284 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1286 /* create a separate region for the bitmap */
1287 memset( &fmt, 0, sizeof(video_format_t) );
1288 fmt.i_chroma = VLC_CODEC_YUVP;
1289 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1290 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1291 fmt.i_x_offset = fmt.i_y_offset = 0;
1292 fmt.p_palette = &palette;
1293 CreateKatePalette( fmt.p_palette, ev->palette );
1295 p_bitmap_region = subpicture_region_New( &fmt );
1296 if( !p_bitmap_region )
1298 msg_Err( p_dec, "cannot allocate SPU region" );
1299 decoder_DeleteSubpicture( p_dec, p_spu );
1303 /* create the bitmap */
1304 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1306 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1310 fmt.i_chroma = VLC_CODEC_TEXT;
1313 fmt.i_width = fmt.i_height = 0;
1314 fmt.i_x_offset = fmt.i_y_offset = 0;
1315 p_spu->p_region = subpicture_region_New( &fmt );
1316 if( !p_spu->p_region )
1318 msg_Err( p_dec, "cannot allocate SPU region" );
1319 decoder_DeleteSubpicture( p_dec, p_spu );
1323 SetupText( p_dec, p_spu, ev );
1325 /* default positioning */
1326 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1327 if (p_bitmap_region)
1329 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1331 p_spu->p_region->i_x = 0;
1332 p_spu->p_region->i_y = 10;
1334 /* override if tracker info present */
1335 if (b_tracker_valid)
1339 p_spu->p_region->i_x = kin.region_x;
1340 p_spu->p_region->i_y = kin.region_y;
1341 if (p_bitmap_region)
1343 p_bitmap_region->i_x = kin.region_x;
1344 p_bitmap_region->i_y = kin.region_y;
1346 p_spu->b_absolute = true;
1349 kate_tracker_clear(&kin);
1352 /* if we have a bitmap, chain it before the text */
1353 if (p_bitmap_region)
1355 p_bitmap_region->p_next = p_spu->p_region;
1356 p_spu->p_region = p_bitmap_region;
1362 /*****************************************************************************
1363 * ParseKateComments:
1364 *****************************************************************************/
1365 static void ParseKateComments( decoder_t *p_dec )
1367 char *psz_name, *psz_value, *psz_comment;
1370 while ( i < p_dec->p_sys->kc.comments )
1372 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1375 psz_name = psz_comment;
1376 psz_value = strchr( psz_comment, '=' );
1382 if( !p_dec->p_description )
1383 p_dec->p_description = vlc_meta_New();
1384 if( p_dec->p_description )
1385 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1387 free( psz_comment );
1392 /*****************************************************************************
1393 * CloseDecoder: clean up the decoder
1394 *****************************************************************************/
1395 static void CloseDecoder( vlc_object_t *p_this )
1397 decoder_t *p_dec = (decoder_t *)p_this;
1400 /* remove the decoder from the global list */
1401 vlc_mutex_lock( &kate_decoder_list_mutex );
1402 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1404 if( kate_decoder_list[ i_index ] == p_dec )
1406 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1410 vlc_mutex_unlock( &kate_decoder_list_mutex );
1412 msg_Dbg( p_dec, "Closing Kate decoder" );
1413 DecSysRelease( p_dec->p_sys );
1416 static void DecSysHold( decoder_sys_t *p_sys )
1418 vlc_mutex_lock( &p_sys->lock );
1419 p_sys->i_refcount++;
1420 vlc_mutex_unlock( &p_sys->lock );
1423 static void DecSysRelease( decoder_sys_t *p_sys )
1425 vlc_mutex_lock( &p_sys->lock );
1426 p_sys->i_refcount--;
1427 if( p_sys->i_refcount > 0)
1429 vlc_mutex_unlock( &p_sys->lock );
1433 vlc_mutex_unlock( &p_sys->lock );
1434 vlc_mutex_destroy( &p_sys->lock );
1438 tiger_renderer_destroy( p_sys->p_tr );
1439 free( p_sys->psz_tiger_default_font_desc );
1443 kate_clear( &p_sys->k );
1444 kate_info_clear( &p_sys->ki );
1445 kate_comment_clear( &p_sys->kc );