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