Qt: synchronization: subtitles duration parameter
[vlc/vlc-skelet.git] / modules / codec / kate.c
blob49177da9c82947b1df87c1fbe8af3759e09fa506
1 /*****************************************************************************
2 * kate.c : a decoder for the kate bitstream format
3 *****************************************************************************
4 * Copyright (C) 2000-2008 the VideoLAN team
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
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 /*****************************************************************************
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 subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block );
160 static int ProcessHeaders( decoder_t *p_dec );
161 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
162 block_t **pp_block );
163 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp,
164 block_t *p_block );
165 static void ParseKateComments( decoder_t * );
166 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
167 const kate_event *ev );
168 static void DecSysRelease( decoder_sys_t *p_sys );
169 static void DecSysHold( decoder_sys_t *p_sys );
170 #ifdef HAVE_TIGER
171 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix );
172 static char *GetTigerString( decoder_t *p_dec, const char *psz_name );
173 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name );
174 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name );
175 static void UpdateTigerFontColor( decoder_t *p_dec );
176 static void UpdateTigerBackgroundColor( decoder_t *p_dec );
177 static void UpdateTigerFontEffect( decoder_t *p_dec );
178 static void UpdateTigerQuality( decoder_t *p_dec );
179 static void UpdateTigerFontDesc( decoder_t *p_dec );
180 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
181 vlc_value_t oldvar, vlc_value_t newval,
182 void *p_data );
183 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
184 vlc_value_t oldval, vlc_value_t newval);
185 #endif
187 #define DEFAULT_NAME "Default"
188 #define MAX_LINE 8192
190 /*****************************************************************************
191 * Module descriptor.
192 *****************************************************************************/
194 #define FORMAT_TEXT N_("Formatted Subtitles")
195 #define FORMAT_LONGTEXT N_("Kate streams allow for text formatting. " \
196 "VLC partly implements this, but you can choose to disable all formatting." \
197 "Note that this has no effect is rendering via Tiger is enabled.")
199 #ifdef HAVE_TIGER
201 static const tiger_font_effect pi_font_effects[] = { tiger_font_plain, tiger_font_shadow, tiger_font_outline };
202 static const char * const ppsz_font_effect_names[] = { N_("None"), N_("Shadow"), N_("Outline") };
204 /* nicked off freetype.c */
205 static const int pi_color_values[] = {
206 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000,
207 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080,
208 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF };
209 static const char *const ppsz_color_descriptions[] = {
210 N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"),
211 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"),
212 N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") };
214 #define TIGER_TEXT N_("Use Tiger for rendering")
215 #define TIGER_LONGTEXT N_("Kate streams can be rendered using the Tiger library. " \
216 "Disabling this will only render static text and bitmap based streams.")
218 #define TIGER_QUALITY_DEFAULT 1.0
219 #define TIGER_QUALITY_TEXT N_("Rendering quality")
220 #define TIGER_QUALITY_LONGTEXT N_("Select rendering quality, at the expense of speed. " \
221 "0 is fastest, 1 is highest quality.")
223 #define TIGER_DEFAULT_FONT_EFFECT_DEFAULT 0
224 #define TIGER_DEFAULT_FONT_EFFECT_TEXT N_("Default font effect")
225 #define TIGER_DEFAULT_FONT_EFFECT_LONGTEXT N_("Add a font effect to text to improve readability " \
226 "against different backgrounds.")
228 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT 0.5
229 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT N_("Default font effect strength")
230 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT N_("How pronounced to make the chosen font effect " \
231 "(effect dependent).")
233 #define TIGER_DEFAULT_FONT_DESC_DEFAULT ""
234 #define TIGER_DEFAULT_FONT_DESC_TEXT N_("Default font description")
235 #define TIGER_DEFAULT_FONT_DESC_LONGTEXT N_("Which font description to use if the Kate stream " \
236 "does not specify particular font parameters (name, size, etc) to use. " \
237 "A blank name will let Tiger choose font parameters where appropriate.")
239 #define TIGER_DEFAULT_FONT_COLOR_DEFAULT 0x00ffffff
240 #define TIGER_DEFAULT_FONT_COLOR_TEXT N_("Default font color")
241 #define TIGER_DEFAULT_FONT_COLOR_LONGTEXT N_("Default font color to use if the Kate stream " \
242 "does not specify a particular font color to use.")
244 #define TIGER_DEFAULT_FONT_ALPHA_DEFAULT 0xff
245 #define TIGER_DEFAULT_FONT_ALPHA_TEXT N_("Default font alpha")
246 #define TIGER_DEFAULT_FONT_ALPHA_LONGTEXT N_("Transparency of the default font color if the Kate stream " \
247 "does not specify a particular font color to use.")
249 #define TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT 0x00ffffff
250 #define TIGER_DEFAULT_BACKGROUND_COLOR_TEXT N_("Default background color")
251 #define TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT N_("Default background color if the Kate stream " \
252 "does not specify a background color to use.")
254 #define TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT 0
255 #define TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT N_("Default background alpha")
256 #define TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT N_("Transparency of the default background color if the Kate stream " \
257 "does not specify a particular background color to use.")
259 #endif
261 #define HELP_TEXT N_( \
262 "Kate is a codec for text and image based overlays.\n" \
263 "The Tiger rendering library is needed to render complex Kate streams, " \
264 "but VLC can still render static text and image based subtitles if " \
265 "it is not available.\n" \
266 "Note that changing settings below will not take effect until a new stream is played. " \
267 "This will hopefully be fixed soon." \
270 vlc_module_begin ()
271 set_shortname( N_("Kate"))
272 set_description( N_("Kate overlay decoder") )
273 set_help( HELP_TEXT )
274 set_capability( "decoder", 50 )
275 set_callbacks( OpenDecoder, CloseDecoder )
276 set_category( CAT_INPUT )
277 set_subcategory( SUBCAT_INPUT_SCODEC )
278 add_shortcut( "kate" )
280 add_bool( "kate-formatted", true, FORMAT_TEXT, FORMAT_LONGTEXT,
281 true )
283 #ifdef HAVE_TIGER
284 add_bool( "kate-use-tiger", true, TIGER_TEXT, TIGER_LONGTEXT,
285 true )
286 add_float_with_range( "kate-tiger-quality",
287 TIGER_QUALITY_DEFAULT, 0.0f, 1.0f,
288 TIGER_QUALITY_TEXT, TIGER_QUALITY_LONGTEXT,
289 true )
291 set_section( N_("Tiger rendering defaults"), NULL );
292 add_string( "kate-tiger-default-font-desc", TIGER_DEFAULT_FONT_DESC_DEFAULT,
293 TIGER_DEFAULT_FONT_DESC_TEXT, TIGER_DEFAULT_FONT_DESC_LONGTEXT, true);
294 add_integer_with_range( "kate-tiger-default-font-effect",
295 TIGER_DEFAULT_FONT_EFFECT_DEFAULT,
296 0, sizeof(pi_font_effects)/sizeof(pi_font_effects[0])-1,
297 TIGER_DEFAULT_FONT_EFFECT_TEXT, TIGER_DEFAULT_FONT_EFFECT_LONGTEXT,
298 true )
299 change_integer_list( pi_font_effects, ppsz_font_effect_names );
300 add_float_with_range( "kate-tiger-default-font-effect-strength",
301 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT, 0.0f, 1.0f,
302 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT, TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT,
303 true )
304 add_integer_with_range( "kate-tiger-default-font-color",
305 TIGER_DEFAULT_FONT_COLOR_DEFAULT, 0, 0x00ffffff,
306 TIGER_DEFAULT_FONT_COLOR_TEXT, TIGER_DEFAULT_FONT_COLOR_LONGTEXT,
307 true);
308 change_integer_list( pi_color_values, ppsz_color_descriptions );
309 add_integer_with_range( "kate-tiger-default-font-alpha",
310 TIGER_DEFAULT_FONT_ALPHA_DEFAULT, 0, 255,
311 TIGER_DEFAULT_FONT_ALPHA_TEXT, TIGER_DEFAULT_FONT_ALPHA_LONGTEXT,
312 true);
313 add_integer_with_range( "kate-tiger-default-background-color",
314 TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT, 0, 0x00ffffff,
315 TIGER_DEFAULT_BACKGROUND_COLOR_TEXT, TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT,
316 true);
317 change_integer_list( pi_color_values, ppsz_color_descriptions );
318 add_integer_with_range( "kate-tiger-default-background-alpha",
319 TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT, 0, 255,
320 TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT, TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT,
321 true);
322 #endif
324 #ifdef ENABLE_PACKETIZER
325 add_submodule ()
326 set_description( N_("Kate text subtitles packetizer") )
327 set_capability( "packetizer", 100 )
328 set_callbacks( OpenPacketizer, CloseDecoder )
329 add_shortcut( "kate" )
330 #endif
332 vlc_module_end ()
334 /*****************************************************************************
335 * OpenDecoder: probe the decoder and return score
336 *****************************************************************************
337 * Tries to launch a decoder and return score so that the interface is able
338 * to chose.
339 *****************************************************************************/
340 static int OpenDecoder( vlc_object_t *p_this )
342 decoder_t *p_dec = (decoder_t*)p_this;
343 decoder_sys_t *p_sys;
345 if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
347 return VLC_EGENERIC;
350 msg_Dbg( p_dec, "kate: OpenDecoder");
352 /* Set callbacks */
353 p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
354 DecodeBlock;
355 p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **))
356 DecodeBlock;
358 /* Allocate the memory needed to store the decoder's structure */
359 if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
360 return VLC_ENOMEM;
362 vlc_mutex_init( &p_sys->lock );
363 p_sys->i_refcount = 0;
364 DecSysHold( p_sys );
366 /* init of p_sys */
367 #ifdef ENABLE_PACKETIZER
368 p_sys->b_packetizer = false;
369 #endif
370 p_sys->b_ready = false;
371 p_sys->i_pts =
372 p_sys->i_max_stop = VLC_TS_INVALID;
374 kate_comment_init( &p_sys->kc );
375 kate_info_init( &p_sys->ki );
377 p_sys->b_has_headers = false;
379 /* retrieve options */
380 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
382 vlc_mutex_lock( &kate_decoder_list_mutex );
384 #ifdef HAVE_TIGER
386 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
388 p_sys->p_tr = NULL;
390 /* get initial value of configuration */
391 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
392 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
393 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
394 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
395 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
396 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
398 if( p_sys->b_use_tiger )
400 int i_ret = tiger_renderer_create( &p_sys->p_tr );
401 if( i_ret < 0 )
403 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
404 p_sys->p_tr = NULL;
405 p_sys->b_use_tiger = false;
408 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
410 UpdateTigerFontEffect( p_dec );
411 UpdateTigerFontColor( p_dec );
412 UpdateTigerBackgroundColor( p_dec );
413 UpdateTigerQuality( p_dec );
414 UpdateTigerFontDesc( p_dec );
417 #else
419 p_sys->b_use_tiger = false;
421 #endif
423 es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );
425 /* add the decoder to the global list */
426 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
427 if( list )
429 list[ kate_decoder_list_size++ ] = p_dec;
430 kate_decoder_list = list;
433 vlc_mutex_unlock( &kate_decoder_list_mutex );
435 return VLC_SUCCESS;
438 #ifdef ENABLE_PACKETIZER
439 static int OpenPacketizer( vlc_object_t *p_this )
441 decoder_t *p_dec = (decoder_t*)p_this;
443 int i_ret = OpenDecoder( p_this );
445 if( i_ret == VLC_SUCCESS )
447 p_dec->p_sys->b_packetizer = true;
448 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
451 return i_ret;
453 #endif
455 /****************************************************************************
456 * DecodeBlock: the whole thing
457 ****************************************************************************
458 * This function must be fed with kate packets.
459 ****************************************************************************/
460 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
462 decoder_sys_t *p_sys = p_dec->p_sys;
463 block_t *p_block;
464 kate_packet kp;
466 if( !pp_block || !*pp_block )
467 return NULL;
469 p_block = *pp_block;
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 p_sys->i_max_stop = VLC_TS_INVALID;
483 block_Release( p_block );
484 return NULL;
487 /* Block to Kate packet */
488 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
490 if( !p_sys->b_has_headers )
492 if( ProcessHeaders( p_dec ) )
494 block_Release( *pp_block );
495 return NULL;
497 p_sys->b_has_headers = true;
500 return ProcessPacket( p_dec, &kp, pp_block );
503 /*****************************************************************************
504 * ProcessHeaders: process Kate headers.
505 *****************************************************************************/
506 static int ProcessHeaders( decoder_t *p_dec )
508 decoder_sys_t *p_sys = p_dec->p_sys;
509 kate_packet kp;
511 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
512 void *pp_data[XIPH_MAX_HEADER_COUNT];
513 unsigned i_count;
514 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
515 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
516 return VLC_EGENERIC;
517 int i_ret = VLC_SUCCESS;
518 if( i_count < 1 )
520 i_ret = VLC_EGENERIC;
521 goto end;
524 /* Take care of the initial Kate header */
525 kp.nbytes = pi_size[0];
526 kp.data = pp_data[0];
527 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
528 if( i_ret < 0 )
530 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
531 goto end;
534 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
535 p_sys->ki.language, p_sys->ki.category,
536 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
537 p_sys->ki.granule_shift);
539 /* parse all remaining header packets */
540 for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
542 kp.nbytes = pi_size[i_headeridx];
543 kp.data = pp_data[i_headeridx];
544 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
545 if( i_ret < 0 )
547 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
548 goto end;
551 /* header 1 is comments */
552 if( i_headeridx == 1 )
554 ParseKateComments( p_dec );
558 #ifdef ENABLE_PACKETIZER
559 if( !p_sys->b_packetizer )
560 #endif
562 /* We have all the headers, initialize decoder */
563 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
564 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
565 if (i_ret < 0)
567 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
568 return VLC_EGENERIC;
570 p_sys->b_ready = true;
572 #ifdef ENABLE_PACKETIZER
573 else
575 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
576 p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
577 p_dec->fmt_out.i_extra );
578 memcpy( p_dec->fmt_out.p_extra,
579 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
581 #endif
583 end:
584 for( unsigned i = 0; i < i_count; i++ )
585 free( pp_data[i] );
586 return i_ret < 0 ? VLC_EGENERIC : VLC_SUCCESS;
589 /*****************************************************************************
590 * ProcessPacket: processes a kate packet.
591 *****************************************************************************/
592 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
593 block_t **pp_block )
595 decoder_sys_t *p_sys = p_dec->p_sys;
596 block_t *p_block = *pp_block;
597 subpicture_t *p_buf = NULL;
599 /* Date management */
600 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
602 p_sys->i_pts = p_block->i_pts;
605 *pp_block = NULL; /* To avoid being fed the same packet again */
607 #ifdef ENABLE_PACKETIZER
608 if( p_sys->b_packetizer )
610 /* Date management */
611 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
613 if( p_sys->i_headers >= p_sys->i_num_headers )
614 p_block->i_length = p_sys->i_pts - p_block->i_pts;
615 else
616 p_block->i_length = 0;
618 p_buf = p_block;
620 else
621 #endif
623 p_buf = DecodePacket( p_dec, p_kp, p_block );
625 if( p_block )
626 block_Release( p_block );
629 return p_buf;
632 /* nicked off blend.c */
633 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
634 int r, int g, int b )
636 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
637 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
638 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
642 This retrieves the size of the video.
643 The best case is when the original video size is known, as we can then
644 scale images to match. In this case, since VLC autoscales, we want to
645 return the original size and let VLC scale everything.
646 if the original size is not known, then VLC can't resize, so we return
647 the size of the incoming video. If sizes in the Kate stream are in
648 relative units, it works fine. If they are absolute, you get what you
649 ask for. Images aren't rescaled.
651 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
653 /* searching for vout to get its size is frowned upon, so we don't and
654 use a default size if the original canvas size is not specified. */
655 decoder_sys_t *p_sys = p_dec->p_sys;
656 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
658 *w = p_sys->ki.original_canvas_width;
659 *h = p_sys->ki.original_canvas_height;
660 msg_Dbg( p_dec, "original canvas %zu %zu",
661 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
663 else
665 /* nothing, leave defaults */
666 msg_Dbg( p_dec, "original canvas size unknown");
670 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
672 size_t y;
674 for( y=0; y<bitmap->height; ++y )
676 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
677 const uint8_t *src = bitmap->pixels+y*bitmap->width;
678 memcpy( dest, src, bitmap->width );
682 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
684 size_t n;
686 fmt_palette->i_entries = palette->ncolors;
687 for( n=0; n<palette->ncolors; ++n )
689 rgb_to_yuv(
690 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
691 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
693 fmt_palette->palette[n][3] = palette->colors[n].a;
697 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
699 decoder_sys_t *p_sys = p_dec->p_sys;
701 if( ev->text_encoding != kate_utf8 )
703 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
704 return;
707 switch( ev->text_markup_type )
709 case kate_markup_none:
710 p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
711 break;
712 case kate_markup_simple:
713 if( p_sys->b_formatted )
715 /* the HTML renderer expects a top level text tag pair */
716 char *buffer = NULL;
717 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
719 p_spu->p_region->psz_html = buffer;
721 break;
723 /* if not formatted, we fall through */
724 default:
725 /* we don't know about this one, so remove markup and display as text */
727 char *copy = strdup( ev->text );
728 size_t len0 = strlen( copy ) + 1;
729 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
730 p_spu->p_region->psz_text = copy;
732 break;
736 #ifdef HAVE_TIGER
738 static void TigerDestroySubpicture( subpicture_t *p_subpic )
740 DecSysRelease( p_subpic->updater.p_sys->p_dec_sys );
741 free( p_subpic->updater.p_sys );
744 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
745 * alpha to avoid double multiply (and thus thinner text than we should)).
746 * Best would be to have VLC be able to handle premultiplied alpha, as it
747 * would be faster to blend as well.
749 * Also, we flip color components around for big endian machines, as Tiger
750 * outputs ARGB or ABGR (the one we selected here) in host endianness.
752 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
754 PROFILE_START( tiger_renderer_postprocess );
755 int y;
756 for( y=0; y<p_plane->i_lines; ++y )
758 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
759 unsigned int x;
760 for( x=0; x<i_width; ++x )
762 uint8_t *p_pixel = p_line+x*4;
763 #ifdef WORDS_BIGENDIAN
764 uint8_t a = p_pixel[0];
765 #else
766 uint8_t a = p_pixel[3];
767 #endif
768 if( a )
770 #ifdef WORDS_BIGENDIAN
771 uint8_t tmp = p_pixel[2];
772 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
773 p_pixel[3] = a;
774 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
775 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
776 #else
777 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
778 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
779 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
780 #endif
782 else
784 p_pixel[0] = 0;
785 p_pixel[1] = 0;
786 p_pixel[2] = 0;
787 p_pixel[3] = 0;
791 PROFILE_STOP( tiger_renderer_postprocess );
794 static int TigerValidateSubpicture( subpicture_t *p_subpic,
795 bool b_fmt_src, const video_format_t *p_fmt_src,
796 bool b_fmt_dst, const video_format_t *p_fmt_dst,
797 mtime_t ts )
799 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
801 if( b_fmt_src || b_fmt_dst )
802 return VLC_EGENERIC;
804 PROFILE_START( TigerValidateSubpicture );
806 /* time in seconds from the start of the stream */
807 kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
809 /* it is likely that the current region (if any) can be kept as is; test for this */
810 vlc_mutex_lock( &p_sys->lock );
811 int i_ret;
812 if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
814 i_ret = VLC_EGENERIC;
815 goto exit;
817 if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
818 tiger_renderer_is_dirty( p_sys->p_tr ) )
820 i_ret = VLC_EGENERIC;
821 goto exit;
824 i_ret = VLC_SUCCESS;
825 exit:
826 vlc_mutex_unlock( &p_sys->lock );
827 PROFILE_STOP( TigerValidateSubpicture );
828 return i_ret;
831 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
832 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
833 Looks good with white though since it's all luma. Hopefully that will be the
834 common case. */
835 static void TigerUpdateSubpicture( subpicture_t *p_subpic,
836 const video_format_t *p_fmt_src,
837 const video_format_t *p_fmt_dst,
838 mtime_t ts )
840 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
841 plane_t *p_plane;
842 kate_float t;
843 int i_ret;
846 /* time in seconds from the start of the stream */
847 t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
849 PROFILE_START( TigerUpdateSubpicture );
851 /* create a full frame region - this will also tell Tiger the size of the frame */
852 video_format_t fmt = *p_fmt_dst;
853 fmt.i_chroma = VLC_CODEC_RGBA;
854 fmt.i_bits_per_pixel = 0;
855 fmt.i_width =
856 fmt.i_visible_width = p_fmt_src->i_width;
857 fmt.i_height =
858 fmt.i_visible_height = p_fmt_src->i_height;
859 fmt.i_x_offset = fmt.i_y_offset = 0;
861 subpicture_region_t *p_r = subpicture_region_New( &fmt );
862 if( !p_r )
863 return;
865 p_r->i_x = 0;
866 p_r->i_y = 0;
867 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
869 vlc_mutex_lock( &p_sys->lock );
871 p_plane = &p_r->p_picture->p[0];
872 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 );
873 if( i_ret < 0 )
875 goto failure;
878 PROFILE_START( tiger_renderer_update );
879 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
880 if( i_ret < 0 )
882 goto failure;
884 PROFILE_STOP( tiger_renderer_update );
886 PROFILE_START( tiger_renderer_render );
887 i_ret = tiger_renderer_render( p_sys->p_tr );
888 if( i_ret < 0 )
890 goto failure;
892 PROFILE_STOP( tiger_renderer_render );
894 PostprocessTigerImage( p_plane, fmt.i_width );
895 p_subpic->p_region = p_r;
896 p_sys->b_dirty = false;
898 PROFILE_STOP( TigerUpdateSubpicture );
900 vlc_mutex_unlock( &p_sys->lock );
902 return;
904 failure:
905 vlc_mutex_unlock( &p_sys->lock );
906 subpicture_region_ChainDelete( p_r );
909 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
911 char *psz_tmp;
912 uint32_t i_color = 0;
914 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
916 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
917 var_Destroy( p_dec, psz_tmp );
918 free( psz_tmp );
919 i_color |= i_rgb;
922 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
924 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
925 var_Destroy( p_dec, psz_tmp );
926 free( psz_tmp );
927 i_color |= (i_alpha << 24);
930 return i_color;
933 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
935 char *psz_value = var_CreateGetString( p_dec, psz_name );
936 if( psz_value)
938 psz_value = strdup( psz_value );
940 var_Destroy( p_dec, psz_name );
941 return psz_value;
944 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
946 int i_value = var_CreateGetInteger( p_dec, psz_name );
947 var_Destroy( p_dec, psz_name );
948 return i_value;
951 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
953 double f_value = var_CreateGetFloat( p_dec, psz_name );
954 var_Destroy( p_dec, psz_name );
955 return f_value;
958 static void UpdateTigerQuality( decoder_t *p_dec )
960 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
961 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
962 p_sys->b_dirty = true;
965 static void UpdateTigerFontDesc( decoder_t *p_dec )
967 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
968 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
969 p_sys->b_dirty = true;
972 static void UpdateTigerFontColor( decoder_t *p_dec )
974 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
975 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
976 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
977 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
978 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
979 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
980 p_sys->b_dirty = true;
983 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
985 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
986 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
987 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
988 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
989 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
990 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
991 p_sys->b_dirty = true;
994 static void UpdateTigerFontEffect( decoder_t *p_dec )
996 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
997 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
998 p_sys->e_tiger_default_font_effect,
999 p_sys->f_tiger_default_font_effect_strength ) );
1000 p_sys->b_dirty = true;
1003 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1004 vlc_value_t oldval, vlc_value_t newval )
1006 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1008 VLC_UNUSED( oldval );
1010 vlc_mutex_lock( &p_sys->lock );
1012 msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1014 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1016 vlc_mutex_unlock( &p_sys->lock );
1017 return VLC_SUCCESS;
1020 #define TEST_TIGER_VAR( name ) \
1021 if( !strcmp( name, psz_var ) )
1023 TEST_TIGER_VAR( "kate-tiger-quality" )
1025 p_sys->f_tiger_quality = newval.f_float;
1026 UpdateTigerQuality( p_dec );
1029 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1031 if( p_sys->psz_tiger_default_font_desc )
1033 free( p_sys->psz_tiger_default_font_desc );
1034 p_sys->psz_tiger_default_font_desc = NULL;
1036 if( newval.psz_string )
1038 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1040 UpdateTigerFontDesc( p_dec );
1043 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1045 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1046 UpdateTigerFontColor( p_dec );
1049 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1051 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1052 UpdateTigerFontColor( p_dec );
1055 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1057 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1058 UpdateTigerBackgroundColor( p_dec );
1061 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1063 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1064 UpdateTigerBackgroundColor( p_dec );
1067 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1069 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1070 UpdateTigerFontEffect( p_dec );
1073 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1075 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1076 UpdateTigerFontEffect( p_dec );
1079 #undef TEST_TIGER_VAR
1081 vlc_mutex_unlock( &p_sys->lock );
1083 return VLC_SUCCESS;
1086 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1087 vlc_value_t oldval, vlc_value_t newval,
1088 void *p_data )
1090 size_t i_idx;
1092 VLC_UNUSED( p_this );
1093 VLC_UNUSED( oldval );
1094 VLC_UNUSED( newval );
1095 VLC_UNUSED( p_data );
1097 vlc_mutex_lock( &kate_decoder_list_mutex );
1099 /* Update all existing decoders from the global user prefs */
1100 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1102 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1103 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1106 vlc_mutex_unlock( &kate_decoder_list_mutex );
1108 return VLC_SUCCESS;
1111 #endif
1113 /*****************************************************************************
1114 * DecodePacket: decodes a Kate packet.
1115 *****************************************************************************/
1116 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1118 decoder_sys_t *p_sys = p_dec->p_sys;
1119 const kate_event *ev = NULL;
1120 subpicture_t *p_spu = NULL;
1121 int i_ret;
1123 if( !p_sys->b_ready )
1125 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1126 return NULL;
1129 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1130 if( i_ret < 0 )
1132 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1133 return NULL;
1136 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1137 if( i_ret < 0 )
1139 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1140 return NULL;
1142 if( i_ret > 0 )
1144 /* no event to go with this packet, this is normal */
1145 return NULL;
1148 /* we have an event */
1150 /* Get a new spu */
1151 subpicture_updater_sys_t *p_spu_sys = NULL;
1152 if( p_sys->b_use_tiger)
1154 p_spu_sys = malloc( sizeof(*p_spu_sys) );
1155 if( !p_spu_sys )
1156 return NULL;
1158 subpicture_updater_t updater = {
1159 #ifdef HAVE_TIGER
1160 .pf_validate = TigerValidateSubpicture,
1161 .pf_update = TigerUpdateSubpicture,
1162 .pf_destroy = TigerDestroySubpicture,
1163 #endif
1164 .p_sys = p_spu_sys,
1166 p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1167 if( !p_spu )
1169 free( p_spu_sys );
1170 /* this will happen for lyrics as there is no vout - so no error */
1171 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1172 return NULL;
1175 p_spu->i_start = p_block->i_pts;
1176 p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1177 p_spu->b_ephemer = false;
1178 p_spu->b_absolute = false;
1180 #ifdef HAVE_TIGER
1181 if( p_sys->b_use_tiger)
1183 p_spu_sys->p_dec_sys = p_sys;
1184 p_spu_sys->i_start = p_block->i_pts;
1185 DecSysHold( p_sys );
1187 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1188 p_spu->b_ephemer = true;
1189 p_spu->b_absolute = true;
1191 /* add the event to tiger */
1192 vlc_mutex_lock( &p_sys->lock );
1193 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1194 vlc_mutex_unlock( &p_sys->lock );
1196 else
1197 #endif
1199 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1202 return p_spu;
1205 /*****************************************************************************
1206 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1207 *****************************************************************************/
1208 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1209 const kate_event *ev )
1211 decoder_sys_t *p_sys = p_dec->p_sys;
1212 video_format_t fmt;
1213 subpicture_region_t *p_bitmap_region = NULL;
1214 video_palette_t palette;
1215 kate_tracker kin;
1216 bool b_tracker_valid = false;
1217 int i_ret;
1219 /* these may be 0 for "not specified" */
1220 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1221 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1223 /* Create a new subpicture region */
1224 memset( &fmt, 0, sizeof(video_format_t) );
1226 if (p_sys->b_formatted)
1228 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1229 if( i_ret < 0)
1231 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1233 else
1235 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1236 GetVideoSize(p_dec, &w, &h);
1237 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1238 if( i_ret < 0)
1240 kate_tracker_clear(&kin);
1241 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1243 else
1245 // TODO: parse tracker and set style, init fmt
1246 b_tracker_valid = true;
1251 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1253 /* create a separate region for the bitmap */
1254 memset( &fmt, 0, sizeof(video_format_t) );
1255 fmt.i_chroma = VLC_CODEC_YUVP;
1256 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1257 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1258 fmt.i_x_offset = fmt.i_y_offset = 0;
1259 fmt.p_palette = &palette;
1260 CreateKatePalette( fmt.p_palette, ev->palette );
1262 p_bitmap_region = subpicture_region_New( &fmt );
1263 if( !p_bitmap_region )
1265 msg_Err( p_dec, "cannot allocate SPU region" );
1266 decoder_DeleteSubpicture( p_dec, p_spu );
1267 return NULL;
1270 /* create the bitmap */
1271 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1273 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1276 /* text region */
1277 fmt.i_chroma = VLC_CODEC_TEXT;
1278 fmt.i_sar_num = 0;
1279 fmt.i_sar_den = 1;
1280 fmt.i_width = fmt.i_height = 0;
1281 fmt.i_x_offset = fmt.i_y_offset = 0;
1282 p_spu->p_region = subpicture_region_New( &fmt );
1283 if( !p_spu->p_region )
1285 msg_Err( p_dec, "cannot allocate SPU region" );
1286 decoder_DeleteSubpicture( p_dec, p_spu );
1287 return NULL;
1290 SetupText( p_dec, p_spu, ev );
1292 /* default positioning */
1293 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1294 if (p_bitmap_region)
1296 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1298 p_spu->p_region->i_x = 0;
1299 p_spu->p_region->i_y = 10;
1301 /* override if tracker info present */
1302 if (b_tracker_valid)
1304 if (kin.has.region)
1306 p_spu->p_region->i_x = kin.region_x;
1307 p_spu->p_region->i_y = kin.region_y;
1308 if (p_bitmap_region)
1310 p_bitmap_region->i_x = kin.region_x;
1311 p_bitmap_region->i_y = kin.region_y;
1313 p_spu->b_absolute = true;
1316 kate_tracker_clear(&kin);
1319 /* if we have a bitmap, chain it before the text */
1320 if (p_bitmap_region)
1322 p_bitmap_region->p_next = p_spu->p_region;
1323 p_spu->p_region = p_bitmap_region;
1326 return p_spu;
1329 /*****************************************************************************
1330 * ParseKateComments:
1331 *****************************************************************************/
1332 static void ParseKateComments( decoder_t *p_dec )
1334 char *psz_name, *psz_value, *psz_comment;
1335 int i = 0;
1337 while ( i < p_dec->p_sys->kc.comments )
1339 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1340 if( !psz_comment )
1341 break;
1342 psz_name = psz_comment;
1343 psz_value = strchr( psz_comment, '=' );
1344 if( psz_value )
1346 *psz_value = '\0';
1347 psz_value++;
1349 if( !p_dec->p_description )
1350 p_dec->p_description = vlc_meta_New();
1351 if( p_dec->p_description )
1352 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1354 free( psz_comment );
1355 i++;
1359 /*****************************************************************************
1360 * CloseDecoder: clean up the decoder
1361 *****************************************************************************/
1362 static void CloseDecoder( vlc_object_t *p_this )
1364 decoder_t *p_dec = (decoder_t *)p_this;
1365 size_t i_index;
1367 /* remove the decoder from the global list */
1368 vlc_mutex_lock( &kate_decoder_list_mutex );
1369 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1371 if( kate_decoder_list[ i_index ] == p_dec )
1373 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1374 break;
1377 vlc_mutex_unlock( &kate_decoder_list_mutex );
1379 msg_Dbg( p_dec, "Closing Kate decoder" );
1380 DecSysRelease( p_dec->p_sys );
1383 static void DecSysHold( decoder_sys_t *p_sys )
1385 vlc_mutex_lock( &p_sys->lock );
1386 p_sys->i_refcount++;
1387 vlc_mutex_unlock( &p_sys->lock );
1390 static void DecSysRelease( decoder_sys_t *p_sys )
1392 vlc_mutex_lock( &p_sys->lock );
1393 p_sys->i_refcount--;
1394 if( p_sys->i_refcount > 0)
1396 vlc_mutex_unlock( &p_sys->lock );
1397 return;
1400 vlc_mutex_unlock( &p_sys->lock );
1401 vlc_mutex_destroy( &p_sys->lock );
1403 #ifdef HAVE_TIGER
1404 if( p_sys->p_tr )
1405 tiger_renderer_destroy( p_sys->p_tr );
1406 free( p_sys->psz_tiger_default_font_desc );
1407 #endif
1409 if (p_sys->b_ready)
1410 kate_clear( &p_sys->k );
1411 kate_info_clear( &p_sys->ki );
1412 kate_comment_clear( &p_sys->kc );
1414 free( p_sys );