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;
104 uint32_t i_tiger_default_font_color;
105 uint32_t i_tiger_default_background_color;
106 tiger_font_effect e_tiger_default_font_effect;
107 double f_tiger_default_font_effect_strength;
108 char *psz_tiger_default_font_desc;
109 double f_tiger_quality;
119 struct subpicture_updater_sys_t
121 decoder_sys_t *p_dec_sys;
127 * This is a global list of existing decoders.
128 * The reason for this list is that:
129 * - I want to be able to reconfigure Tiger when user prefs change
130 * - User prefs are variables which are not specific to a decoder (eg, if
131 * there are several decoders, there will still be one set of variables)
132 * - A callback set on those will not be passed a pointer to the decoder
133 * (as the decoder isn't known, and there could be multiple ones)
134 * - Creating variables in the decoder will create different ones, with
135 * values copied from the relevant user pref, so a callback on those
136 * won't be called when the user pref is changed
137 * Therefore, each decoder will register/unregister itself with this list,
138 * callbacks will be set for the user prefs, and these will in turn walk
139 * through this list and tell each decoder to update the relevant variable.
141 * VLC's variable system is still in my way as I can't get the value of
142 * the user pref variables at decoder start *unless* I create my own vars
143 * which inherit from the user ones, but those are utterly useless after
144 * that first use, since they'll be detached from the ones the user can
145 * change. So, I create them, read their values, and then destroy them.
147 static vlc_mutex_t kate_decoder_list_mutex = VLC_STATIC_MUTEX;
148 static size_t kate_decoder_list_size = 0;
149 static decoder_t **kate_decoder_list = NULL;
151 /*****************************************************************************
153 *****************************************************************************/
154 static int OpenDecoder ( vlc_object_t * );
155 static void CloseDecoder ( vlc_object_t * );
156 #ifdef ENABLE_PACKETIZER
157 static int OpenPacketizer( vlc_object_t *p_this );
160 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block );
161 static int ProcessHeaders( decoder_t *p_dec );
162 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
163 block_t **pp_block );
164 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp,
166 static void ParseKateComments( decoder_t * );
167 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
168 const kate_event *ev );
169 static void DecSysRelease( decoder_sys_t *p_sys );
170 static void DecSysHold( decoder_sys_t *p_sys );
172 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix );
173 static char *GetTigerString( decoder_t *p_dec, const char *psz_name );
174 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name );
175 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name );
176 static void UpdateTigerFontColor( decoder_t *p_dec );
177 static void UpdateTigerBackgroundColor( decoder_t *p_dec );
178 static void UpdateTigerFontEffect( decoder_t *p_dec );
179 static void UpdateTigerQuality( decoder_t *p_dec );
180 static void UpdateTigerFontDesc( decoder_t *p_dec );
181 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
182 vlc_value_t oldvar, vlc_value_t newval,
184 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
185 vlc_value_t oldval, vlc_value_t newval);
188 #define DEFAULT_NAME "Default"
189 #define MAX_LINE 8192
191 /*****************************************************************************
193 *****************************************************************************/
195 #define FORMAT_TEXT N_("Formatted Subtitles")
196 #define FORMAT_LONGTEXT N_("Kate streams allow for text formatting. " \
197 "VLC partly implements this, but you can choose to disable all formatting." \
198 "Note that this has no effect is rendering via Tiger is enabled.")
202 static const tiger_font_effect pi_font_effects[] = { tiger_font_plain, tiger_font_shadow, tiger_font_outline };
203 static const char * const ppsz_font_effect_names[] = { N_("None"), N_("Shadow"), N_("Outline") };
205 /* nicked off freetype.c */
206 static const int pi_color_values[] = {
207 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000,
208 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080,
209 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF };
210 static const char *const ppsz_color_descriptions[] = {
211 N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"),
212 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"),
213 N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") };
215 #define TIGER_TEXT N_("Use Tiger for rendering")
216 #define TIGER_LONGTEXT N_("Kate streams can be rendered using the Tiger library. " \
217 "Disabling this will only render static text and bitmap based streams.")
219 #define TIGER_QUALITY_DEFAULT 1.0
220 #define TIGER_QUALITY_TEXT N_("Rendering quality")
221 #define TIGER_QUALITY_LONGTEXT N_("Select rendering quality, at the expense of speed. " \
222 "0 is fastest, 1 is highest quality.")
224 #define TIGER_DEFAULT_FONT_EFFECT_DEFAULT 0
225 #define TIGER_DEFAULT_FONT_EFFECT_TEXT N_("Default font effect")
226 #define TIGER_DEFAULT_FONT_EFFECT_LONGTEXT N_("Add a font effect to text to improve readability " \
227 "against different backgrounds.")
229 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT 0.5
230 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT N_("Default font effect strength")
231 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT N_("How pronounced to make the chosen font effect " \
232 "(effect dependent).")
234 #define TIGER_DEFAULT_FONT_DESC_DEFAULT ""
235 #define TIGER_DEFAULT_FONT_DESC_TEXT N_("Default font description")
236 #define TIGER_DEFAULT_FONT_DESC_LONGTEXT N_("Which font description to use if the Kate stream " \
237 "does not specify particular font parameters (name, size, etc) to use. " \
238 "A blank name will let Tiger choose font parameters where appropriate.")
240 #define TIGER_DEFAULT_FONT_COLOR_DEFAULT 0x00ffffff
241 #define TIGER_DEFAULT_FONT_COLOR_TEXT N_("Default font color")
242 #define TIGER_DEFAULT_FONT_COLOR_LONGTEXT N_("Default font color to use if the Kate stream " \
243 "does not specify a particular font color to use.")
245 #define TIGER_DEFAULT_FONT_ALPHA_DEFAULT 0xff
246 #define TIGER_DEFAULT_FONT_ALPHA_TEXT N_("Default font alpha")
247 #define TIGER_DEFAULT_FONT_ALPHA_LONGTEXT N_("Transparency of the default font color if the Kate stream " \
248 "does not specify a particular font color to use.")
250 #define TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT 0x00ffffff
251 #define TIGER_DEFAULT_BACKGROUND_COLOR_TEXT N_("Default background color")
252 #define TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT N_("Default background color if the Kate stream " \
253 "does not specify a background color to use.")
255 #define TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT 0
256 #define TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT N_("Default background alpha")
257 #define TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT N_("Transparency of the default background color if the Kate stream " \
258 "does not specify a particular background color to use.")
262 #define HELP_TEXT N_( \
263 "Kate is a codec for text and image based overlays.\n" \
264 "The Tiger rendering library is needed to render complex Kate streams, " \
265 "but VLC can still render static text and image based subtitles if " \
266 "it is not available.\n" \
267 "Note that changing settings below will not take effect until a new stream is played. " \
268 "This will hopefully be fixed soon." \
272 set_shortname( N_("Kate"))
273 set_description( N_("Kate overlay decoder") )
274 set_help( HELP_TEXT )
275 set_capability( "decoder", 50 )
276 set_callbacks( OpenDecoder, CloseDecoder )
277 set_category( CAT_INPUT )
278 set_subcategory( SUBCAT_INPUT_SCODEC )
279 add_shortcut( "kate" )
281 add_bool( "kate-formatted", true, NULL, FORMAT_TEXT, FORMAT_LONGTEXT,
285 add_bool( "kate-use-tiger", true, NULL, TIGER_TEXT, TIGER_LONGTEXT,
287 add_float_with_range( "kate-tiger-quality",
288 TIGER_QUALITY_DEFAULT, 0.0f, 1.0f, TigerConfigurationCallback,
289 TIGER_QUALITY_TEXT, TIGER_QUALITY_LONGTEXT,
292 set_section( N_("Tiger rendering defaults"), NULL );
293 add_string( "kate-tiger-default-font-desc",
294 TIGER_DEFAULT_FONT_DESC_DEFAULT, TigerConfigurationCallback,
295 TIGER_DEFAULT_FONT_DESC_TEXT, TIGER_DEFAULT_FONT_DESC_LONGTEXT, true);
296 add_integer_with_range( "kate-tiger-default-font-effect",
297 TIGER_DEFAULT_FONT_EFFECT_DEFAULT,
298 0, sizeof(pi_font_effects)/sizeof(pi_font_effects[0])-1, TigerConfigurationCallback,
299 TIGER_DEFAULT_FONT_EFFECT_TEXT, TIGER_DEFAULT_FONT_EFFECT_LONGTEXT,
301 change_integer_list( pi_font_effects, ppsz_font_effect_names, NULL );
302 add_float_with_range( "kate-tiger-default-font-effect-strength",
303 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT, 0.0f, 1.0f, TigerConfigurationCallback,
304 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT, TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT,
306 add_integer_with_range( "kate-tiger-default-font-color",
307 TIGER_DEFAULT_FONT_COLOR_DEFAULT, 0, 0x00ffffff, TigerConfigurationCallback,
308 TIGER_DEFAULT_FONT_COLOR_TEXT, TIGER_DEFAULT_FONT_COLOR_LONGTEXT,
310 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
311 add_integer_with_range( "kate-tiger-default-font-alpha",
312 TIGER_DEFAULT_FONT_ALPHA_DEFAULT, 0, 255, TigerConfigurationCallback,
313 TIGER_DEFAULT_FONT_ALPHA_TEXT, TIGER_DEFAULT_FONT_ALPHA_LONGTEXT,
315 add_integer_with_range( "kate-tiger-default-background-color",
316 TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT, 0, 0x00ffffff, TigerConfigurationCallback,
317 TIGER_DEFAULT_BACKGROUND_COLOR_TEXT, TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT,
319 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
320 add_integer_with_range( "kate-tiger-default-background-alpha",
321 TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT, 0, 255, TigerConfigurationCallback,
322 TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT, TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT,
326 #ifdef ENABLE_PACKETIZER
328 set_description( N_("Kate text subtitles packetizer") )
329 set_capability( "packetizer", 100 )
330 set_callbacks( OpenPacketizer, CloseDecoder )
331 add_shortcut( "kate" )
336 /*****************************************************************************
337 * OpenDecoder: probe the decoder and return score
338 *****************************************************************************
339 * Tries to launch a decoder and return score so that the interface is able
341 *****************************************************************************/
342 static int OpenDecoder( vlc_object_t *p_this )
344 decoder_t *p_dec = (decoder_t*)p_this;
345 decoder_sys_t *p_sys;
347 if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
352 msg_Dbg( p_dec, "kate: OpenDecoder");
355 p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
357 p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **))
360 /* Allocate the memory needed to store the decoder's structure */
361 if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
364 vlc_mutex_init( &p_sys->lock );
365 p_sys->i_refcount = 0;
369 #ifdef ENABLE_PACKETIZER
370 p_sys->b_packetizer = false;
372 p_sys->b_ready = false;
374 p_sys->i_max_stop = VLC_TS_INVALID;
376 kate_comment_init( &p_sys->kc );
377 kate_info_init( &p_sys->ki );
379 p_sys->b_has_headers = false;
381 /* retrieve options */
382 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
384 vlc_mutex_lock( &kate_decoder_list_mutex );
388 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
392 /* get initial value of configuration */
393 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
394 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
395 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
396 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
397 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
398 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
400 if( p_sys->b_use_tiger )
402 int i_ret = tiger_renderer_create( &p_sys->p_tr );
405 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
407 p_sys->b_use_tiger = false;
410 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
412 UpdateTigerFontEffect( p_dec );
413 UpdateTigerFontColor( p_dec );
414 UpdateTigerBackgroundColor( p_dec );
415 UpdateTigerQuality( p_dec );
416 UpdateTigerFontDesc( p_dec );
421 p_sys->b_use_tiger = false;
425 es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );
427 /* add the decoder to the global list */
428 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
431 list[ kate_decoder_list_size++ ] = p_dec;
432 kate_decoder_list = list;
435 vlc_mutex_unlock( &kate_decoder_list_mutex );
440 #ifdef ENABLE_PACKETIZER
441 static int OpenPacketizer( vlc_object_t *p_this )
443 decoder_t *p_dec = (decoder_t*)p_this;
445 int i_ret = OpenDecoder( p_this );
447 if( i_ret == VLC_SUCCESS )
449 p_dec->p_sys->b_packetizer = true;
450 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
457 /****************************************************************************
458 * DecodeBlock: the whole thing
459 ****************************************************************************
460 * This function must be fed with kate packets.
461 ****************************************************************************/
462 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
464 decoder_sys_t *p_sys = p_dec->p_sys;
468 if( !pp_block || !*pp_block )
473 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
476 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
478 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
479 vlc_mutex_lock( &p_sys->lock );
480 tiger_renderer_seek( p_sys->p_tr, 0 );
481 vlc_mutex_unlock( &p_sys->lock );
484 p_sys->i_max_stop = VLC_TS_INVALID;
485 block_Release( p_block );
489 /* Block to Kate packet */
490 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
492 if( !p_sys->b_has_headers )
494 if( ProcessHeaders( p_dec ) )
496 block_Release( *pp_block );
499 p_sys->b_has_headers = true;
502 return ProcessPacket( p_dec, &kp, pp_block );
505 /*****************************************************************************
506 * ProcessHeaders: process Kate headers.
507 *****************************************************************************/
508 static int ProcessHeaders( decoder_t *p_dec )
510 decoder_sys_t *p_sys = p_dec->p_sys;
513 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
514 void *pp_data[XIPH_MAX_HEADER_COUNT];
516 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
517 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
519 int i_ret = VLC_SUCCESS;
522 i_ret = VLC_EGENERIC;
526 /* Take care of the initial Kate header */
527 kp.nbytes = pi_size[0];
528 kp.data = pp_data[0];
529 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
532 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
536 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
537 p_sys->ki.language, p_sys->ki.category,
538 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
539 p_sys->ki.granule_shift);
541 /* parse all remaining header packets */
542 for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
544 kp.nbytes = pi_size[i_headeridx];
545 kp.data = pp_data[i_headeridx];
546 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
549 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
553 /* header 1 is comments */
554 if( i_headeridx == 1 )
556 ParseKateComments( p_dec );
560 #ifdef ENABLE_PACKETIZER
561 if( !p_sys->b_packetizer )
564 /* We have all the headers, initialize decoder */
565 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
566 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
569 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
572 p_sys->b_ready = true;
574 #ifdef ENABLE_PACKETIZER
577 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
578 p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
579 p_dec->fmt_out.i_extra );
580 memcpy( p_dec->fmt_out.p_extra,
581 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
586 for( unsigned i = 0; i < i_count; i++ )
588 return i_ret < 0 ? VLC_EGENERIC : VLC_SUCCESS;
591 /*****************************************************************************
592 * ProcessPacket: processes a kate packet.
593 *****************************************************************************/
594 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
597 decoder_sys_t *p_sys = p_dec->p_sys;
598 block_t *p_block = *pp_block;
599 subpicture_t *p_buf = NULL;
601 /* Date management */
602 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
604 p_sys->i_pts = p_block->i_pts;
607 *pp_block = NULL; /* To avoid being fed the same packet again */
609 #ifdef ENABLE_PACKETIZER
610 if( p_sys->b_packetizer )
612 /* Date management */
613 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
615 if( p_sys->i_headers >= p_sys->i_num_headers )
616 p_block->i_length = p_sys->i_pts - p_block->i_pts;
618 p_block->i_length = 0;
625 p_buf = DecodePacket( p_dec, p_kp, p_block );
628 block_Release( p_block );
634 /* nicked off blend.c */
635 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
636 int r, int g, int b )
638 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
639 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
640 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
644 This retrieves the size of the video.
645 The best case is when the original video size is known, as we can then
646 scale images to match. In this case, since VLC autoscales, we want to
647 return the original size and let VLC scale everything.
648 if the original size is not known, then VLC can't resize, so we return
649 the size of the incoming video. If sizes in the Kate stream are in
650 relative units, it works fine. If they are absolute, you get what you
651 ask for. Images aren't rescaled.
653 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
655 /* searching for vout to get its size is frowned upon, so we don't and
656 use a default size if the original canvas size is not specified. */
658 decoder_sys_t *p_sys = p_dec->p_sys;
659 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
661 *w = p_sys->ki.original_canvas_width;
662 *h = p_sys->ki.original_canvas_height;
663 msg_Dbg( p_dec, "original canvas %zu %zu",
664 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
668 /* nothing, leave defaults */
669 msg_Dbg( p_dec, "original canvas size unknown");
672 /* keep this just in case it might be allowed one day ;) */
673 vout_thread_t *p_vout;
674 p_vout = vlc_object_find( (vlc_object_t*)p_dec, VLC_OBJECT_VOUT, FIND_CHILD );
677 decoder_sys_t *p_sys = p_dec->p_sys;
678 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
680 *w = p_sys->ki.original_canvas_width;
681 *h = p_sys->ki.original_canvas_height;
685 *w = p_vout->fmt_in.i_width;
686 *h = p_vout->fmt_in.i_height;
688 msg_Dbg( p_dec, "video: in %d %d, out %d %d, original canvas %zu %zu",
689 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
690 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
691 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
692 vlc_object_release( p_vout );
697 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
701 for( y=0; y<bitmap->height; ++y )
703 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
704 const uint8_t *src = bitmap->pixels+y*bitmap->width;
705 memcpy( dest, src, bitmap->width );
709 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
713 fmt_palette->i_entries = palette->ncolors;
714 for( n=0; n<palette->ncolors; ++n )
717 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
718 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
720 fmt_palette->palette[n][3] = palette->colors[n].a;
724 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
726 decoder_sys_t *p_sys = p_dec->p_sys;
728 if( ev->text_encoding != kate_utf8 )
730 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
734 switch( ev->text_markup_type )
736 case kate_markup_none:
737 p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
739 case kate_markup_simple:
740 if( p_sys->b_formatted )
742 /* the HTML renderer expects a top level text tag pair */
744 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
746 p_spu->p_region->psz_html = buffer;
750 /* if not formatted, we fall through */
752 /* we don't know about this one, so remove markup and display as text */
754 char *copy = strdup( ev->text );
755 size_t len0 = strlen( copy ) + 1;
756 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
757 p_spu->p_region->psz_text = copy;
765 static void TigerDestroySubpicture( subpicture_t *p_subpic )
767 DecSysRelease( p_subpic->updater.p_sys->p_dec_sys );
768 free( p_subpic->updater.p_sys );
771 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
772 * alpha to avoid double multiply (and thus thinner text than we should)).
773 * Best would be to have VLC be able to handle premultiplied alpha, as it
774 * would be faster to blend as well.
776 * Also, we flip color components around for big endian machines, as Tiger
777 * outputs ARGB or ABGR (the one we selected here) in host endianness.
779 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
781 PROFILE_START( tiger_renderer_postprocess );
783 for( y=0; y<p_plane->i_lines; ++y )
785 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
787 for( x=0; x<i_width; ++x )
789 uint8_t *p_pixel = p_line+x*4;
790 #ifdef WORDS_BIGENDIAN
791 uint8_t a = p_pixel[0];
793 uint8_t a = p_pixel[3];
797 #ifdef WORDS_BIGENDIAN
798 uint8_t tmp = p_pixel[2];
799 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
801 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
802 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
804 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
805 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
806 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
818 PROFILE_STOP( tiger_renderer_postprocess );
821 static int TigerValidateSubpicture( subpicture_t *p_subpic,
822 bool b_fmt_src, const video_format_t *p_fmt_src,
823 bool b_fmt_dst, const video_format_t *p_fmt_dst,
826 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
828 if( b_fmt_src || b_fmt_dst )
831 PROFILE_START( TigerValidateSubpicture );
833 /* time in seconds from the start of the stream */
834 kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
836 /* it is likely that the current region (if any) can be kept as is; test for this */
837 vlc_mutex_lock( &p_sys->lock );
839 if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
841 i_ret = VLC_EGENERIC;
844 if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
845 tiger_renderer_is_dirty( p_sys->p_tr ) )
847 i_ret = VLC_EGENERIC;
853 vlc_mutex_unlock( &p_sys->lock );
854 PROFILE_STOP( TigerValidateSubpicture );
858 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
859 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
860 Looks good with white though since it's all luma. Hopefully that will be the
862 static void TigerUpdateSubpicture( subpicture_t *p_subpic,
863 const video_format_t *p_fmt_src,
864 const video_format_t *p_fmt_dst,
867 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
873 /* time in seconds from the start of the stream */
874 t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
876 PROFILE_START( TigerUpdateSubpicture );
878 /* create a full frame region - this will also tell Tiger the size of the frame */
879 video_format_t fmt = *p_fmt_dst;
880 fmt.i_chroma = VLC_CODEC_RGBA;
881 fmt.i_bits_per_pixel = 0;
883 fmt.i_visible_width = p_fmt_src->i_width;
885 fmt.i_visible_height = p_fmt_src->i_height;
886 fmt.i_x_offset = fmt.i_y_offset = 0;
888 subpicture_region_t *p_r = subpicture_region_New( &fmt );
894 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
896 vlc_mutex_lock( &p_sys->lock );
898 p_plane = &p_r->p_picture->p[0];
899 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 );
905 PROFILE_START( tiger_renderer_update );
906 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
911 PROFILE_STOP( tiger_renderer_update );
913 PROFILE_START( tiger_renderer_render );
914 i_ret = tiger_renderer_render( p_sys->p_tr );
919 PROFILE_STOP( tiger_renderer_render );
921 PostprocessTigerImage( p_plane, fmt.i_width );
922 p_subpic->p_region = p_r;
923 p_sys->b_dirty = false;
925 PROFILE_STOP( TigerUpdateSubpicture );
927 vlc_mutex_unlock( &p_sys->lock );
932 vlc_mutex_unlock( &p_sys->lock );
933 subpicture_region_ChainDelete( p_r );
936 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
939 uint32_t i_color = 0;
941 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
943 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
944 var_Destroy( p_dec, psz_tmp );
949 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
951 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
952 var_Destroy( p_dec, psz_tmp );
954 i_color |= (i_alpha << 24);
960 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
962 char *psz_value = var_CreateGetString( p_dec, psz_name );
965 psz_value = strdup( psz_value );
967 var_Destroy( p_dec, psz_name );
971 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
973 int i_value = var_CreateGetInteger( p_dec, psz_name );
974 var_Destroy( p_dec, psz_name );
978 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
980 double f_value = var_CreateGetFloat( p_dec, psz_name );
981 var_Destroy( p_dec, psz_name );
985 static void UpdateTigerQuality( decoder_t *p_dec )
987 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
988 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
989 p_sys->b_dirty = true;
992 static void UpdateTigerFontDesc( decoder_t *p_dec )
994 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
995 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
996 p_sys->b_dirty = true;
999 static void UpdateTigerFontColor( decoder_t *p_dec )
1001 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1002 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
1003 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
1004 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
1005 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
1006 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1007 p_sys->b_dirty = true;
1010 static void UpdateTigerBackgroundColor( 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_background_color >> 24) & 0xff) / 255.0;
1014 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1015 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1016 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1017 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1018 p_sys->b_dirty = true;
1021 static void UpdateTigerFontEffect( decoder_t *p_dec )
1023 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1024 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1025 p_sys->e_tiger_default_font_effect,
1026 p_sys->f_tiger_default_font_effect_strength ) );
1027 p_sys->b_dirty = true;
1030 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1031 vlc_value_t oldval, vlc_value_t newval )
1033 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1035 VLC_UNUSED( oldval );
1037 vlc_mutex_lock( &p_sys->lock );
1039 msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1041 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1043 vlc_mutex_unlock( &p_sys->lock );
1047 #define TEST_TIGER_VAR( name ) \
1048 if( !strcmp( name, psz_var ) )
1050 TEST_TIGER_VAR( "kate-tiger-quality" )
1052 p_sys->f_tiger_quality = newval.f_float;
1053 UpdateTigerQuality( p_dec );
1056 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1058 if( p_sys->psz_tiger_default_font_desc )
1060 free( p_sys->psz_tiger_default_font_desc );
1061 p_sys->psz_tiger_default_font_desc = NULL;
1063 if( newval.psz_string )
1065 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1067 UpdateTigerFontDesc( p_dec );
1070 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1072 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1073 UpdateTigerFontColor( p_dec );
1076 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1078 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1079 UpdateTigerFontColor( p_dec );
1082 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1084 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1085 UpdateTigerBackgroundColor( p_dec );
1088 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1090 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1091 UpdateTigerBackgroundColor( p_dec );
1094 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1096 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1097 UpdateTigerFontEffect( p_dec );
1100 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1102 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1103 UpdateTigerFontEffect( p_dec );
1106 #undef TEST_TIGER_VAR
1108 vlc_mutex_unlock( &p_sys->lock );
1113 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1114 vlc_value_t oldval, vlc_value_t newval,
1119 VLC_UNUSED( p_this );
1120 VLC_UNUSED( oldval );
1121 VLC_UNUSED( newval );
1122 VLC_UNUSED( p_data );
1124 vlc_mutex_lock( &kate_decoder_list_mutex );
1126 /* Update all existing decoders from the global user prefs */
1127 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1129 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1130 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1133 vlc_mutex_unlock( &kate_decoder_list_mutex );
1140 /*****************************************************************************
1141 * DecodePacket: decodes a Kate packet.
1142 *****************************************************************************/
1143 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1145 decoder_sys_t *p_sys = p_dec->p_sys;
1146 const kate_event *ev = NULL;
1147 subpicture_t *p_spu = NULL;
1150 if( !p_sys->b_ready )
1152 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1156 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1159 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1163 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1166 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1171 /* no event to go with this packet, this is normal */
1175 /* we have an event */
1178 subpicture_updater_sys_t *p_spu_sys = NULL;
1179 if( p_sys->b_use_tiger)
1181 p_spu_sys = malloc( sizeof(*p_spu_sys) );
1185 subpicture_updater_t updater = {
1187 .pf_validate = TigerValidateSubpicture,
1188 .pf_update = TigerUpdateSubpicture,
1189 .pf_destroy = TigerDestroySubpicture,
1193 p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1197 /* this will happen for lyrics as there is no vout - so no error */
1198 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1202 p_spu->i_start = p_block->i_pts;
1203 p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1204 p_spu->b_ephemer = false;
1205 p_spu->b_absolute = false;
1208 if( p_sys->b_use_tiger)
1210 p_spu_sys->p_dec_sys = p_sys;
1211 p_spu_sys->i_start = p_block->i_pts;
1212 DecSysHold( p_sys );
1214 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1215 p_spu->b_ephemer = true;
1216 p_spu->b_absolute = true;
1218 /* add the event to tiger */
1219 vlc_mutex_lock( &p_sys->lock );
1220 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1221 vlc_mutex_unlock( &p_sys->lock );
1226 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1232 /*****************************************************************************
1233 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1234 *****************************************************************************/
1235 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1236 const kate_event *ev )
1238 decoder_sys_t *p_sys = p_dec->p_sys;
1240 subpicture_region_t *p_bitmap_region = NULL;
1241 video_palette_t palette;
1243 bool b_tracker_valid = false;
1246 /* these may be 0 for "not specified" */
1247 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1248 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1250 /* Create a new subpicture region */
1251 memset( &fmt, 0, sizeof(video_format_t) );
1253 if (p_sys->b_formatted)
1255 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1258 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1262 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1263 GetVideoSize(p_dec, &w, &h);
1264 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1267 kate_tracker_clear(&kin);
1268 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1272 // TODO: parse tracker and set style, init fmt
1273 b_tracker_valid = true;
1278 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1280 /* create a separate region for the bitmap */
1281 memset( &fmt, 0, sizeof(video_format_t) );
1282 fmt.i_chroma = VLC_CODEC_YUVP;
1283 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1284 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1285 fmt.i_x_offset = fmt.i_y_offset = 0;
1286 fmt.p_palette = &palette;
1287 CreateKatePalette( fmt.p_palette, ev->palette );
1289 p_bitmap_region = subpicture_region_New( &fmt );
1290 if( !p_bitmap_region )
1292 msg_Err( p_dec, "cannot allocate SPU region" );
1293 decoder_DeleteSubpicture( p_dec, p_spu );
1297 /* create the bitmap */
1298 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1300 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1304 fmt.i_chroma = VLC_CODEC_TEXT;
1307 fmt.i_width = fmt.i_height = 0;
1308 fmt.i_x_offset = fmt.i_y_offset = 0;
1309 p_spu->p_region = subpicture_region_New( &fmt );
1310 if( !p_spu->p_region )
1312 msg_Err( p_dec, "cannot allocate SPU region" );
1313 decoder_DeleteSubpicture( p_dec, p_spu );
1317 SetupText( p_dec, p_spu, ev );
1319 /* default positioning */
1320 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1321 if (p_bitmap_region)
1323 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1325 p_spu->p_region->i_x = 0;
1326 p_spu->p_region->i_y = 10;
1328 /* override if tracker info present */
1329 if (b_tracker_valid)
1333 p_spu->p_region->i_x = kin.region_x;
1334 p_spu->p_region->i_y = kin.region_y;
1335 if (p_bitmap_region)
1337 p_bitmap_region->i_x = kin.region_x;
1338 p_bitmap_region->i_y = kin.region_y;
1340 p_spu->b_absolute = true;
1343 kate_tracker_clear(&kin);
1346 /* if we have a bitmap, chain it before the text */
1347 if (p_bitmap_region)
1349 p_bitmap_region->p_next = p_spu->p_region;
1350 p_spu->p_region = p_bitmap_region;
1356 /*****************************************************************************
1357 * ParseKateComments:
1358 *****************************************************************************/
1359 static void ParseKateComments( decoder_t *p_dec )
1361 char *psz_name, *psz_value, *psz_comment;
1364 while ( i < p_dec->p_sys->kc.comments )
1366 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1369 psz_name = psz_comment;
1370 psz_value = strchr( psz_comment, '=' );
1376 if( !p_dec->p_description )
1377 p_dec->p_description = vlc_meta_New();
1378 if( p_dec->p_description )
1379 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1381 free( psz_comment );
1386 /*****************************************************************************
1387 * CloseDecoder: clean up the decoder
1388 *****************************************************************************/
1389 static void CloseDecoder( vlc_object_t *p_this )
1391 decoder_t *p_dec = (decoder_t *)p_this;
1394 /* remove the decoder from the global list */
1395 vlc_mutex_lock( &kate_decoder_list_mutex );
1396 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1398 if( kate_decoder_list[ i_index ] == p_dec )
1400 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1404 vlc_mutex_unlock( &kate_decoder_list_mutex );
1406 msg_Dbg( p_dec, "Closing Kate decoder" );
1407 DecSysRelease( p_dec->p_sys );
1410 static void DecSysHold( decoder_sys_t *p_sys )
1412 vlc_mutex_lock( &p_sys->lock );
1413 p_sys->i_refcount++;
1414 vlc_mutex_unlock( &p_sys->lock );
1417 static void DecSysRelease( decoder_sys_t *p_sys )
1419 vlc_mutex_lock( &p_sys->lock );
1420 p_sys->i_refcount--;
1421 if( p_sys->i_refcount > 0)
1423 vlc_mutex_unlock( &p_sys->lock );
1427 vlc_mutex_unlock( &p_sys->lock );
1428 vlc_mutex_destroy( &p_sys->lock );
1432 tiger_renderer_destroy( p_sys->p_tr );
1433 free( p_sys->psz_tiger_default_font_desc );
1437 kate_clear( &p_sys->k );
1438 kate_info_clear( &p_sys->ki );
1439 kate_comment_clear( &p_sys->kc );