codec: kate: prepare to put pf_packetize and pf_decode into a union
[vlc.git] / modules / codec / kate.c
blobe9d621584461d35e72082b5e39c0cee6b5ccf7dc
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 typedef struct
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;
116 } decoder_sys_t;
118 typedef struct
120 decoder_sys_t *p_dec_sys;
121 mtime_t i_start;
122 } kate_spu_updater_sys_t;
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( "spu 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 static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
333 decoder_t *p_dec = (decoder_t*)p_this;
334 decoder_sys_t *p_sys;
336 if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
338 return VLC_EGENERIC;
341 msg_Dbg( p_dec, "kate: OpenDecoder");
343 /* Allocate the memory needed to store the decoder's structure */
344 if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
345 return VLC_ENOMEM;
347 if( b_packetizer )
348 p_dec->pf_packetize = Packetize;
349 else
350 p_dec->pf_decode = DecodeSub;
351 p_dec->pf_flush = Flush;
353 vlc_mutex_init( &p_sys->lock );
354 p_sys->i_refcount = 0;
355 DecSysHold( p_sys );
357 /* init of p_sys */
358 #ifdef ENABLE_PACKETIZER
359 p_sys->b_packetizer = b_packetizer;
360 #endif
361 p_sys->b_ready = false;
362 p_sys->i_pts =
363 p_sys->i_max_stop = VLC_TS_INVALID;
365 kate_comment_init( &p_sys->kc );
366 kate_info_init( &p_sys->ki );
368 p_sys->b_has_headers = false;
370 /* retrieve options */
371 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
373 vlc_mutex_lock( &kate_decoder_list_mutex );
375 #ifdef HAVE_TIGER
377 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
379 p_sys->p_tr = NULL;
381 /* get initial value of configuration */
382 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
383 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
384 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
385 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
386 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
387 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
389 if( p_sys->b_use_tiger )
391 int i_ret = tiger_renderer_create( &p_sys->p_tr );
392 if( i_ret < 0 )
394 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
395 p_sys->p_tr = NULL;
396 p_sys->b_use_tiger = false;
398 else {
399 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
401 UpdateTigerFontEffect( p_dec );
402 UpdateTigerFontColor( p_dec );
403 UpdateTigerBackgroundColor( p_dec );
404 UpdateTigerQuality( p_dec );
405 UpdateTigerFontDesc( p_dec );
409 #else
411 p_sys->b_use_tiger = false;
413 #endif
415 if( b_packetizer )
416 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
417 else
418 p_dec->fmt_out.i_codec = 0; // may vary during the stream
420 /* add the decoder to the global list */
421 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
422 if( list )
424 list[ kate_decoder_list_size++ ] = p_dec;
425 kate_decoder_list = list;
428 vlc_mutex_unlock( &kate_decoder_list_mutex );
430 return VLC_SUCCESS;
433 static int OpenDecoder( vlc_object_t *p_this )
435 return OpenCommon( p_this, false );
438 #ifdef ENABLE_PACKETIZER
439 static int OpenPacketizer( vlc_object_t *p_this )
441 return OpenCommon( p_this, true );
443 #endif
445 /*****************************************************************************
446 * Flush:
447 *****************************************************************************/
448 static void Flush( decoder_t *p_dec )
450 decoder_sys_t *p_sys = p_dec->p_sys;
452 #ifdef HAVE_TIGER
453 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
454 vlc_mutex_lock( &p_sys->lock );
455 tiger_renderer_seek( p_sys->p_tr, 0 );
456 vlc_mutex_unlock( &p_sys->lock );
457 #endif
458 p_sys->i_max_stop = VLC_TS_INVALID;
461 /****************************************************************************
462 * DecodeBlock: the whole thing
463 ****************************************************************************
464 * This function must be fed with kate packets.
465 ****************************************************************************/
466 static void *DecodeBlock( decoder_t *p_dec, block_t *p_block )
468 decoder_sys_t *p_sys = p_dec->p_sys;
469 kate_packet kp;
471 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
473 #ifdef HAVE_TIGER
474 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
476 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
477 vlc_mutex_lock( &p_sys->lock );
478 tiger_renderer_seek( p_sys->p_tr, 0 );
479 vlc_mutex_unlock( &p_sys->lock );
481 #endif
482 if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
484 p_sys->i_max_stop = VLC_TS_INVALID;
485 block_Release( p_block );
486 return NULL;
490 /* Block to Kate packet */
491 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
493 if( !p_sys->b_has_headers )
495 if( ProcessHeaders( p_dec ) )
497 block_Release( p_block );
498 return NULL;
500 p_sys->b_has_headers = true;
503 return ProcessPacket( p_dec, &kp, p_block );
506 static int DecodeSub( decoder_t *p_dec, block_t *p_block )
508 if( p_block == NULL ) /* No Drain */
509 return VLCDEC_SUCCESS;
511 subpicture_t *p_spu = DecodeBlock( p_dec, p_block );
512 if( p_spu != NULL )
513 decoder_QueueSub( p_dec, p_spu );
514 return VLCDEC_SUCCESS;
517 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
519 if( pp_block == NULL ) /* No Drain */
520 return NULL;
521 block_t *p_block = *pp_block; *pp_block = NULL;
522 if( p_block == NULL )
523 return NULL;
524 return DecodeBlock( p_dec, p_block );
527 /*****************************************************************************
528 * ProcessHeaders: process Kate headers.
529 *****************************************************************************/
530 static int ProcessHeaders( decoder_t *p_dec )
532 decoder_sys_t *p_sys = p_dec->p_sys;
533 kate_packet kp;
535 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
536 void *pp_data[XIPH_MAX_HEADER_COUNT];
537 unsigned i_count;
538 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
539 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
540 return VLC_EGENERIC;
542 if( i_count < 1 )
543 return VLC_EGENERIC;
545 /* Take care of the initial Kate header */
546 kp.nbytes = pi_size[0];
547 kp.data = pp_data[0];
548 int i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
549 if( i_ret < 0 )
551 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
552 return VLC_EGENERIC;
555 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
556 p_sys->ki.language, p_sys->ki.category,
557 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
558 p_sys->ki.granule_shift);
560 /* parse all remaining header packets */
561 for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
563 kp.nbytes = pi_size[i_headeridx];
564 kp.data = pp_data[i_headeridx];
565 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
566 if( i_ret < 0 )
568 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
569 return VLC_EGENERIC;
572 /* header 1 is comments */
573 if( i_headeridx == 1 )
575 ParseKateComments( p_dec );
579 #ifdef ENABLE_PACKETIZER
580 if( !p_sys->b_packetizer )
581 #endif
583 /* We have all the headers, initialize decoder */
584 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
585 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
586 if (i_ret < 0)
588 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
589 return VLC_EGENERIC;
591 p_sys->b_ready = true;
593 #ifdef ENABLE_PACKETIZER
594 else
596 void* p_extra = realloc( p_dec->fmt_out.p_extra,
597 p_dec->fmt_in.i_extra );
598 if( unlikely( p_extra == NULL ) )
600 return VLC_ENOMEM;
602 p_dec->fmt_out.p_extra = p_extra;
603 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
604 memcpy( p_dec->fmt_out.p_extra,
605 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
607 #endif
609 return VLC_SUCCESS;
612 /*****************************************************************************
613 * ProcessPacket: processes a kate packet.
614 *****************************************************************************/
615 static void *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
616 block_t *p_block )
618 decoder_sys_t *p_sys = p_dec->p_sys;
620 /* Date management */
621 if( p_block->i_pts != VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
623 p_sys->i_pts = p_block->i_pts;
626 #ifdef ENABLE_PACKETIZER
627 if( p_sys->b_packetizer )
629 /* Date management */
630 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
632 if( p_sys->i_headers >= p_sys->i_num_headers )
633 p_block->i_length = p_sys->i_pts - p_block->i_pts;
634 else
635 p_block->i_length = 0;
636 return p_block;
638 else
639 #endif
641 subpicture_t *p_buf = DecodePacket( p_dec, p_kp, p_block );
643 block_Release( p_block );
644 return p_buf;
648 /* nicked off blend.c */
649 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
650 int r, int g, int b )
652 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
653 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
654 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
658 This retrieves the size of the video.
659 The best case is when the original video size is known, as we can then
660 scale images to match. In this case, since VLC autoscales, we want to
661 return the original size and let VLC scale everything.
662 if the original size is not known, then VLC can't resize, so we return
663 the size of the incoming video. If sizes in the Kate stream are in
664 relative units, it works fine. If they are absolute, you get what you
665 ask for. Images aren't rescaled.
667 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
669 /* searching for vout to get its size is frowned upon, so we don't and
670 use a default size if the original canvas size is not specified. */
671 decoder_sys_t *p_sys = p_dec->p_sys;
672 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
674 *w = p_sys->ki.original_canvas_width;
675 *h = p_sys->ki.original_canvas_height;
676 msg_Dbg( p_dec, "original canvas %zu %zu",
677 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
679 else
681 /* nothing, leave defaults */
682 msg_Dbg( p_dec, "original canvas size unknown");
686 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
688 size_t y;
690 for( y=0; y<bitmap->height; ++y )
692 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
693 const uint8_t *src = bitmap->pixels+y*bitmap->width;
694 memcpy( dest, src, bitmap->width );
698 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
700 size_t n;
702 fmt_palette->i_entries = palette->ncolors;
703 for( n=0; n<palette->ncolors; ++n )
705 rgb_to_yuv(
706 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
707 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
709 fmt_palette->palette[n][3] = palette->colors[n].a;
713 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
715 decoder_sys_t *p_sys = p_dec->p_sys;
717 if( ev->text_encoding != kate_utf8 )
719 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
720 return;
723 switch( ev->text_markup_type )
725 case kate_markup_none:
726 case kate_markup_simple:
727 if( p_sys->b_formatted )
728 // p_spu->p_region->p_text = ParseSubtitles(&p_spu->p_region->i_align, ev->text );
729 ;//FIXME
730 else
731 p_spu->p_region->p_text = text_segment_New( ev->text ); /* no leak, this actually gets killed by the core */
732 break;
733 default:
734 /* we don't know about this one, so remove markup and display as text */
736 char *copy = strdup( ev->text );
737 size_t len0 = strlen( copy ) + 1;
738 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
739 p_spu->p_region->p_text = text_segment_New( copy );
740 free( copy );
742 break;
746 #ifdef HAVE_TIGER
748 static void TigerDestroySubpicture( subpicture_t *p_subpic )
750 kate_spu_updater_sys_t *p_spusys = p_subpic->updater.p_sys;
751 DecSysRelease( p_spusys->p_dec_sys );
752 free( p_spusys );
755 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
756 * alpha to avoid double multiply (and thus thinner text than we should)).
757 * Best would be to have VLC be able to handle premultiplied alpha, as it
758 * would be faster to blend as well.
760 * Also, we flip color components around for big endian machines, as Tiger
761 * outputs ARGB or ABGR (the one we selected here) in host endianness.
763 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
765 PROFILE_START( tiger_renderer_postprocess );
766 int y;
767 for( y=0; y<p_plane->i_lines; ++y )
769 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
770 unsigned int x;
771 for( x=0; x<i_width; ++x )
773 uint8_t *p_pixel = p_line+x*4;
774 #ifdef WORDS_BIGENDIAN
775 uint8_t a = p_pixel[0];
776 #else
777 uint8_t a = p_pixel[3];
778 #endif
779 if( a )
781 #ifdef WORDS_BIGENDIAN
782 uint8_t tmp = p_pixel[2];
783 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
784 p_pixel[3] = a;
785 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
786 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
787 #else
788 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
789 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
790 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
791 #endif
793 else
795 p_pixel[0] = 0;
796 p_pixel[1] = 0;
797 p_pixel[2] = 0;
798 p_pixel[3] = 0;
802 PROFILE_STOP( tiger_renderer_postprocess );
805 static int TigerValidateSubpicture( subpicture_t *p_subpic,
806 bool b_fmt_src, const video_format_t *p_fmt_src,
807 bool b_fmt_dst, const video_format_t *p_fmt_dst,
808 mtime_t ts )
810 VLC_UNUSED(p_fmt_src); VLC_UNUSED(p_fmt_dst);
812 kate_spu_updater_sys_t *p_spusys = p_subpic->updater.p_sys;
813 decoder_sys_t *p_sys = p_spusys->p_dec_sys;
815 if( b_fmt_src || b_fmt_dst )
816 return VLC_EGENERIC;
818 PROFILE_START( TigerValidateSubpicture );
820 /* time in seconds from the start of the stream */
821 kate_float t = (p_spusys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
823 /* it is likely that the current region (if any) can be kept as is; test for this */
824 vlc_mutex_lock( &p_sys->lock );
825 int i_ret;
826 if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
828 i_ret = VLC_EGENERIC;
829 goto exit;
831 if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
832 tiger_renderer_is_dirty( p_sys->p_tr ) )
834 i_ret = VLC_EGENERIC;
835 goto exit;
838 i_ret = VLC_SUCCESS;
839 exit:
840 vlc_mutex_unlock( &p_sys->lock );
841 PROFILE_STOP( TigerValidateSubpicture );
842 return i_ret;
845 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
846 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
847 Looks good with white though since it's all luma. Hopefully that will be the
848 common case. */
849 static void TigerUpdateSubpicture( subpicture_t *p_subpic,
850 const video_format_t *p_fmt_src,
851 const video_format_t *p_fmt_dst,
852 mtime_t ts )
854 kate_spu_updater_sys_t *p_spusys = p_subpic->updater.p_sys;
855 decoder_sys_t *p_sys = p_spusys->p_dec_sys;
856 plane_t *p_plane;
857 kate_float t;
858 int i_ret;
861 /* time in seconds from the start of the stream */
862 t = (p_spusys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
864 PROFILE_START( TigerUpdateSubpicture );
866 /* create a full frame region - this will also tell Tiger the size of the frame */
867 video_format_t fmt = *p_fmt_dst;
868 fmt.i_chroma = VLC_CODEC_RGBA;
869 fmt.i_bits_per_pixel = 0;
870 fmt.i_width =
871 fmt.i_visible_width = p_fmt_src->i_width;
872 fmt.i_height =
873 fmt.i_visible_height = p_fmt_src->i_height;
874 fmt.i_x_offset = fmt.i_y_offset = 0;
876 subpicture_region_t *p_r = subpicture_region_New( &fmt );
877 if( !p_r )
878 return;
880 p_r->i_x = 0;
881 p_r->i_y = 0;
882 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
884 vlc_mutex_lock( &p_sys->lock );
886 p_plane = &p_r->p_picture->p[0];
887 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 );
888 if( i_ret < 0 )
890 goto failure;
893 PROFILE_START( tiger_renderer_update );
894 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
895 if( i_ret < 0 )
897 goto failure;
899 PROFILE_STOP( tiger_renderer_update );
901 PROFILE_START( tiger_renderer_render );
902 i_ret = tiger_renderer_render( p_sys->p_tr );
903 if( i_ret < 0 )
905 goto failure;
907 PROFILE_STOP( tiger_renderer_render );
909 PostprocessTigerImage( p_plane, fmt.i_width );
910 p_subpic->p_region = p_r;
911 p_sys->b_dirty = false;
913 PROFILE_STOP( TigerUpdateSubpicture );
915 vlc_mutex_unlock( &p_sys->lock );
917 return;
919 failure:
920 vlc_mutex_unlock( &p_sys->lock );
921 subpicture_region_ChainDelete( p_r );
924 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
926 char *psz_tmp;
927 uint32_t i_color = 0;
929 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
931 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
932 var_Destroy( p_dec, psz_tmp );
933 free( psz_tmp );
934 i_color |= i_rgb;
937 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
939 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
940 var_Destroy( p_dec, psz_tmp );
941 free( psz_tmp );
942 i_color |= (i_alpha << 24);
945 return i_color;
948 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
950 char *psz_value = var_CreateGetString( p_dec, psz_name );
951 if( psz_value)
953 psz_value = strdup( psz_value );
955 var_Destroy( p_dec, psz_name );
956 return psz_value;
959 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
961 int i_value = var_CreateGetInteger( p_dec, psz_name );
962 var_Destroy( p_dec, psz_name );
963 return i_value;
966 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
968 double f_value = var_CreateGetFloat( p_dec, psz_name );
969 var_Destroy( p_dec, psz_name );
970 return f_value;
973 static void UpdateTigerQuality( decoder_t *p_dec )
975 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
976 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
977 p_sys->b_dirty = true;
980 static void UpdateTigerFontDesc( decoder_t *p_dec )
982 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
983 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
984 p_sys->b_dirty = true;
987 static void UpdateTigerFontColor( decoder_t *p_dec )
989 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
990 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
991 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
992 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
993 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
994 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
995 p_sys->b_dirty = true;
998 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
1000 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1001 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
1002 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1003 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1004 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1005 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1006 p_sys->b_dirty = true;
1009 static void UpdateTigerFontEffect( decoder_t *p_dec )
1011 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1012 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1013 p_sys->e_tiger_default_font_effect,
1014 p_sys->f_tiger_default_font_effect_strength ) );
1015 p_sys->b_dirty = true;
1018 #endif
1020 /*****************************************************************************
1021 * DecodePacket: decodes a Kate packet.
1022 *****************************************************************************/
1023 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1025 decoder_sys_t *p_sys = p_dec->p_sys;
1026 const kate_event *ev = NULL;
1027 subpicture_t *p_spu = NULL;
1028 int i_ret;
1030 if( !p_sys->b_ready )
1032 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1033 return NULL;
1036 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1037 if( i_ret < 0 )
1039 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1040 return NULL;
1043 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1044 if( i_ret < 0 )
1046 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1047 return NULL;
1049 if( i_ret > 0 )
1051 /* no event to go with this packet, this is normal */
1052 return NULL;
1055 /* we have an event */
1057 /* Get a new spu */
1058 kate_spu_updater_sys_t *p_spu_sys = NULL;
1059 if( p_sys->b_use_tiger)
1061 p_spu_sys = malloc( sizeof(*p_spu_sys) );
1062 if( !p_spu_sys )
1063 return NULL;
1065 subpicture_updater_t updater = {
1066 #ifdef HAVE_TIGER
1067 .pf_validate = TigerValidateSubpicture,
1068 .pf_update = TigerUpdateSubpicture,
1069 .pf_destroy = TigerDestroySubpicture,
1070 #endif
1071 .p_sys = p_spu_sys,
1073 p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1074 if( !p_spu )
1076 free( p_spu_sys );
1077 /* this will happen for lyrics as there is no vout - so no error */
1078 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1079 return NULL;
1082 p_spu->i_start = p_block->i_pts;
1083 p_spu->i_stop = p_block->i_pts + CLOCK_FREQ *
1084 ev->duration * p_sys->ki.gps_denominator / p_sys->ki.gps_numerator;
1085 p_spu->b_ephemer = false;
1086 p_spu->b_absolute = false;
1088 #ifdef HAVE_TIGER
1089 if( p_sys->b_use_tiger)
1091 p_spu_sys->p_dec_sys = p_sys;
1092 p_spu_sys->i_start = p_block->i_pts;
1093 DecSysHold( p_sys );
1095 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1096 p_spu->b_ephemer = true;
1097 p_spu->b_absolute = true;
1099 /* add the event to tiger */
1100 vlc_mutex_lock( &p_sys->lock );
1101 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1102 vlc_mutex_unlock( &p_sys->lock );
1104 else
1105 #endif
1107 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1110 return p_spu;
1113 /*****************************************************************************
1114 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1115 *****************************************************************************/
1116 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1117 const kate_event *ev )
1119 decoder_sys_t *p_sys = p_dec->p_sys;
1120 video_format_t fmt;
1121 subpicture_region_t *p_bitmap_region = NULL;
1122 video_palette_t palette;
1123 kate_tracker kin;
1124 bool b_tracker_valid = false;
1125 int i_ret;
1127 /* these may be 0 for "not specified" */
1128 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1129 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1131 /* Create a new subpicture region */
1132 if (p_sys->b_formatted)
1134 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1135 if( i_ret < 0)
1137 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1139 else
1141 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1142 GetVideoSize(p_dec, &w, &h);
1143 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1144 if( i_ret < 0)
1146 kate_tracker_clear(&kin);
1147 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1149 else
1151 // TODO: parse tracker and set style, init fmt
1152 b_tracker_valid = true;
1157 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1159 /* create a separate region for the bitmap */
1160 video_format_Init( &fmt, VLC_CODEC_YUVP );
1161 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1162 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1163 fmt.i_x_offset = fmt.i_y_offset = 0;
1164 fmt.p_palette = &palette;
1165 CreateKatePalette( fmt.p_palette, ev->palette );
1167 p_bitmap_region = subpicture_region_New( &fmt );
1168 video_format_Clean( &fmt );
1169 if( !p_bitmap_region )
1171 msg_Err( p_dec, "cannot allocate SPU region" );
1172 subpicture_Delete( p_spu );
1173 return NULL;
1176 /* create the bitmap */
1177 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1179 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1182 /* text region */
1183 video_format_Init( &fmt, VLC_CODEC_TEXT );
1184 fmt.i_sar_num = 0;
1185 fmt.i_sar_den = 1;
1186 fmt.i_width = fmt.i_height = 0;
1187 fmt.i_x_offset = fmt.i_y_offset = 0;
1188 p_spu->p_region = subpicture_region_New( &fmt );
1189 video_format_Clean( &fmt );
1190 if( !p_spu->p_region )
1192 msg_Err( p_dec, "cannot allocate SPU region" );
1193 if( p_bitmap_region )
1194 subpicture_region_Delete( p_bitmap_region );
1195 subpicture_Delete( p_spu );
1196 return NULL;
1199 SetupText( p_dec, p_spu, ev );
1201 /* default positioning */
1202 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1203 if (p_bitmap_region)
1205 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1207 p_spu->p_region->i_x = 0;
1208 p_spu->p_region->i_y = 10;
1210 /* override if tracker info present */
1211 if (b_tracker_valid)
1213 if (kin.has.region)
1215 p_spu->p_region->i_x = kin.region_x;
1216 p_spu->p_region->i_y = kin.region_y;
1217 if (p_bitmap_region)
1219 p_bitmap_region->i_x = kin.region_x;
1220 p_bitmap_region->i_y = kin.region_y;
1222 p_spu->b_absolute = true;
1225 kate_tracker_clear(&kin);
1228 /* if we have a bitmap, chain it before the text */
1229 if (p_bitmap_region)
1231 p_bitmap_region->p_next = p_spu->p_region;
1232 p_spu->p_region = p_bitmap_region;
1235 return p_spu;
1238 /*****************************************************************************
1239 * ParseKateComments:
1240 *****************************************************************************/
1241 static void ParseKateComments( decoder_t *p_dec )
1243 char *psz_name, *psz_value, *psz_comment;
1244 int i = 0;
1246 decoder_sys_t *p_sys = p_dec->p_sys;
1248 while ( i < p_sys->kc.comments )
1250 psz_comment = strdup( p_sys->kc.user_comments[i] );
1251 if( !psz_comment )
1252 break;
1253 psz_name = psz_comment;
1254 psz_value = strchr( psz_comment, '=' );
1255 if( psz_value )
1257 *psz_value = '\0';
1258 psz_value++;
1260 if( !p_dec->p_description )
1261 p_dec->p_description = vlc_meta_New();
1262 if( p_dec->p_description )
1263 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1265 free( psz_comment );
1266 i++;
1270 /*****************************************************************************
1271 * CloseDecoder: clean up the decoder
1272 *****************************************************************************/
1273 static void CloseDecoder( vlc_object_t *p_this )
1275 decoder_t *p_dec = (decoder_t *)p_this;
1276 size_t i_index;
1278 /* remove the decoder from the global list */
1279 vlc_mutex_lock( &kate_decoder_list_mutex );
1280 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1282 if( kate_decoder_list[ i_index ] == p_dec )
1284 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1285 break;
1288 vlc_mutex_unlock( &kate_decoder_list_mutex );
1290 msg_Dbg( p_dec, "Closing Kate decoder" );
1291 DecSysRelease( p_dec->p_sys );
1294 static void DecSysHold( decoder_sys_t *p_sys )
1296 vlc_mutex_lock( &p_sys->lock );
1297 p_sys->i_refcount++;
1298 vlc_mutex_unlock( &p_sys->lock );
1301 static void DecSysRelease( decoder_sys_t *p_sys )
1303 vlc_mutex_lock( &p_sys->lock );
1304 p_sys->i_refcount--;
1305 if( p_sys->i_refcount > 0)
1307 vlc_mutex_unlock( &p_sys->lock );
1308 return;
1311 vlc_mutex_unlock( &p_sys->lock );
1312 vlc_mutex_destroy( &p_sys->lock );
1314 #ifdef HAVE_TIGER
1315 if( p_sys->p_tr )
1316 tiger_renderer_destroy( p_sys->p_tr );
1317 free( p_sys->psz_tiger_default_font_desc );
1318 #endif
1320 if (p_sys->b_ready)
1321 kate_clear( &p_sys->k );
1322 kate_info_clear( &p_sys->ki );
1323 kate_comment_clear( &p_sys->kc );
1325 free( p_sys );