access_http: use the user agent provided by the user: fix #4162
[vlc/asuraparaju-public.git] / modules / codec / kate.c
blob7f697bdf8759d288bae5a1b60e8ccffd00cd6baf
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, NULL, FORMAT_TEXT, FORMAT_LONGTEXT,
281 true )
283 #ifdef HAVE_TIGER
284 add_bool( "kate-use-tiger", true, NULL, TIGER_TEXT, TIGER_LONGTEXT,
285 true )
286 add_float_with_range( "kate-tiger-quality",
287 TIGER_QUALITY_DEFAULT, 0.0f, 1.0f, TigerConfigurationCallback,
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",
293 TIGER_DEFAULT_FONT_DESC_DEFAULT, TigerConfigurationCallback,
294 TIGER_DEFAULT_FONT_DESC_TEXT, TIGER_DEFAULT_FONT_DESC_LONGTEXT, true);
295 add_integer_with_range( "kate-tiger-default-font-effect",
296 TIGER_DEFAULT_FONT_EFFECT_DEFAULT,
297 0, sizeof(pi_font_effects)/sizeof(pi_font_effects[0])-1, TigerConfigurationCallback,
298 TIGER_DEFAULT_FONT_EFFECT_TEXT, TIGER_DEFAULT_FONT_EFFECT_LONGTEXT,
299 true )
300 change_integer_list( pi_font_effects, ppsz_font_effect_names, NULL );
301 add_float_with_range( "kate-tiger-default-font-effect-strength",
302 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT, 0.0f, 1.0f, TigerConfigurationCallback,
303 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT, TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT,
304 true )
305 add_integer_with_range( "kate-tiger-default-font-color",
306 TIGER_DEFAULT_FONT_COLOR_DEFAULT, 0, 0x00ffffff, TigerConfigurationCallback,
307 TIGER_DEFAULT_FONT_COLOR_TEXT, TIGER_DEFAULT_FONT_COLOR_LONGTEXT,
308 true);
309 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
310 add_integer_with_range( "kate-tiger-default-font-alpha",
311 TIGER_DEFAULT_FONT_ALPHA_DEFAULT, 0, 255, TigerConfigurationCallback,
312 TIGER_DEFAULT_FONT_ALPHA_TEXT, TIGER_DEFAULT_FONT_ALPHA_LONGTEXT,
313 true);
314 add_integer_with_range( "kate-tiger-default-background-color",
315 TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT, 0, 0x00ffffff, TigerConfigurationCallback,
316 TIGER_DEFAULT_BACKGROUND_COLOR_TEXT, TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT,
317 true);
318 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
319 add_integer_with_range( "kate-tiger-default-background-alpha",
320 TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT, 0, 255, TigerConfigurationCallback,
321 TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT, TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT,
322 true);
323 #endif
325 #ifdef ENABLE_PACKETIZER
326 add_submodule ()
327 set_description( N_("Kate text subtitles packetizer") )
328 set_capability( "packetizer", 100 )
329 set_callbacks( OpenPacketizer, CloseDecoder )
330 add_shortcut( "kate" )
331 #endif
333 vlc_module_end ()
335 /*****************************************************************************
336 * OpenDecoder: probe the decoder and return score
337 *****************************************************************************
338 * Tries to launch a decoder and return score so that the interface is able
339 * to chose.
340 *****************************************************************************/
341 static int OpenDecoder( vlc_object_t *p_this )
343 decoder_t *p_dec = (decoder_t*)p_this;
344 decoder_sys_t *p_sys;
346 if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
348 return VLC_EGENERIC;
351 msg_Dbg( p_dec, "kate: OpenDecoder");
353 /* Set callbacks */
354 p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
355 DecodeBlock;
356 p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **))
357 DecodeBlock;
359 /* Allocate the memory needed to store the decoder's structure */
360 if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
361 return VLC_ENOMEM;
363 vlc_mutex_init( &p_sys->lock );
364 p_sys->i_refcount = 0;
365 DecSysHold( p_sys );
367 /* init of p_sys */
368 #ifdef ENABLE_PACKETIZER
369 p_sys->b_packetizer = false;
370 #endif
371 p_sys->b_ready = false;
372 p_sys->i_pts =
373 p_sys->i_max_stop = VLC_TS_INVALID;
375 kate_comment_init( &p_sys->kc );
376 kate_info_init( &p_sys->ki );
378 p_sys->b_has_headers = false;
380 /* retrieve options */
381 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
383 vlc_mutex_lock( &kate_decoder_list_mutex );
385 #ifdef HAVE_TIGER
387 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
389 p_sys->p_tr = NULL;
391 /* get initial value of configuration */
392 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
393 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
394 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
395 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
396 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
397 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
399 if( p_sys->b_use_tiger )
401 int i_ret = tiger_renderer_create( &p_sys->p_tr );
402 if( i_ret < 0 )
404 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
405 p_sys->p_tr = NULL;
406 p_sys->b_use_tiger = false;
409 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
411 UpdateTigerFontEffect( p_dec );
412 UpdateTigerFontColor( p_dec );
413 UpdateTigerBackgroundColor( p_dec );
414 UpdateTigerQuality( p_dec );
415 UpdateTigerFontDesc( p_dec );
418 #else
420 p_sys->b_use_tiger = false;
422 #endif
424 es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );
426 /* add the decoder to the global list */
427 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
428 if( list )
430 list[ kate_decoder_list_size++ ] = p_dec;
431 kate_decoder_list = list;
434 vlc_mutex_unlock( &kate_decoder_list_mutex );
436 return VLC_SUCCESS;
439 #ifdef ENABLE_PACKETIZER
440 static int OpenPacketizer( vlc_object_t *p_this )
442 decoder_t *p_dec = (decoder_t*)p_this;
444 int i_ret = OpenDecoder( p_this );
446 if( i_ret == VLC_SUCCESS )
448 p_dec->p_sys->b_packetizer = true;
449 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
452 return i_ret;
454 #endif
456 /****************************************************************************
457 * DecodeBlock: the whole thing
458 ****************************************************************************
459 * This function must be fed with kate packets.
460 ****************************************************************************/
461 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
463 decoder_sys_t *p_sys = p_dec->p_sys;
464 block_t *p_block;
465 kate_packet kp;
467 if( !pp_block || !*pp_block )
468 return NULL;
470 p_block = *pp_block;
472 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
474 #ifdef HAVE_TIGER
475 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
477 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
478 vlc_mutex_lock( &p_sys->lock );
479 tiger_renderer_seek( p_sys->p_tr, 0 );
480 vlc_mutex_unlock( &p_sys->lock );
482 #endif
483 p_sys->i_max_stop = VLC_TS_INVALID;
484 block_Release( p_block );
485 return NULL;
488 /* Block to Kate packet */
489 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
491 if( !p_sys->b_has_headers )
493 if( ProcessHeaders( p_dec ) )
495 block_Release( *pp_block );
496 return NULL;
498 p_sys->b_has_headers = true;
501 return ProcessPacket( p_dec, &kp, pp_block );
504 /*****************************************************************************
505 * ProcessHeaders: process Kate headers.
506 *****************************************************************************/
507 static int ProcessHeaders( decoder_t *p_dec )
509 decoder_sys_t *p_sys = p_dec->p_sys;
510 kate_packet kp;
512 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
513 void *pp_data[XIPH_MAX_HEADER_COUNT];
514 unsigned i_count;
515 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
516 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
517 return VLC_EGENERIC;
518 int i_ret = VLC_SUCCESS;
519 if( i_count < 1 )
521 i_ret = VLC_EGENERIC;
522 goto end;
525 /* Take care of the initial Kate header */
526 kp.nbytes = pi_size[0];
527 kp.data = pp_data[0];
528 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
529 if( i_ret < 0 )
531 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
532 goto end;
535 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
536 p_sys->ki.language, p_sys->ki.category,
537 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
538 p_sys->ki.granule_shift);
540 /* parse all remaining header packets */
541 for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
543 kp.nbytes = pi_size[i_headeridx];
544 kp.data = pp_data[i_headeridx];
545 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
546 if( i_ret < 0 )
548 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
549 goto end;
552 /* header 1 is comments */
553 if( i_headeridx == 1 )
555 ParseKateComments( p_dec );
559 #ifdef ENABLE_PACKETIZER
560 if( !p_sys->b_packetizer )
561 #endif
563 /* We have all the headers, initialize decoder */
564 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
565 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
566 if (i_ret < 0)
568 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
569 return VLC_EGENERIC;
571 p_sys->b_ready = true;
573 #ifdef ENABLE_PACKETIZER
574 else
576 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
577 p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
578 p_dec->fmt_out.i_extra );
579 memcpy( p_dec->fmt_out.p_extra,
580 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
582 #endif
584 end:
585 for( unsigned i = 0; i < i_count; i++ )
586 free( pp_data[i] );
587 return i_ret < 0 ? VLC_EGENERIC : VLC_SUCCESS;
590 /*****************************************************************************
591 * ProcessPacket: processes a kate packet.
592 *****************************************************************************/
593 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
594 block_t **pp_block )
596 decoder_sys_t *p_sys = p_dec->p_sys;
597 block_t *p_block = *pp_block;
598 subpicture_t *p_buf = NULL;
600 /* Date management */
601 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
603 p_sys->i_pts = p_block->i_pts;
606 *pp_block = NULL; /* To avoid being fed the same packet again */
608 #ifdef ENABLE_PACKETIZER
609 if( p_sys->b_packetizer )
611 /* Date management */
612 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
614 if( p_sys->i_headers >= p_sys->i_num_headers )
615 p_block->i_length = p_sys->i_pts - p_block->i_pts;
616 else
617 p_block->i_length = 0;
619 p_buf = p_block;
621 else
622 #endif
624 p_buf = DecodePacket( p_dec, p_kp, p_block );
626 if( p_block )
627 block_Release( p_block );
630 return p_buf;
633 /* nicked off blend.c */
634 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
635 int r, int g, int b )
637 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
638 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
639 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
643 This retrieves the size of the video.
644 The best case is when the original video size is known, as we can then
645 scale images to match. In this case, since VLC autoscales, we want to
646 return the original size and let VLC scale everything.
647 if the original size is not known, then VLC can't resize, so we return
648 the size of the incoming video. If sizes in the Kate stream are in
649 relative units, it works fine. If they are absolute, you get what you
650 ask for. Images aren't rescaled.
652 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
654 /* searching for vout to get its size is frowned upon, so we don't and
655 use a default size if the original canvas size is not specified. */
656 #if 1
657 decoder_sys_t *p_sys = p_dec->p_sys;
658 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
660 *w = p_sys->ki.original_canvas_width;
661 *h = p_sys->ki.original_canvas_height;
662 msg_Dbg( p_dec, "original canvas %zu %zu",
663 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
665 else
667 /* nothing, leave defaults */
668 msg_Dbg( p_dec, "original canvas size unknown");
670 #else
671 /* keep this just in case it might be allowed one day ;) */
672 vout_thread_t *p_vout;
673 p_vout = vlc_object_find( (vlc_object_t*)p_dec, VLC_OBJECT_VOUT, FIND_CHILD );
674 if( p_vout )
676 decoder_sys_t *p_sys = p_dec->p_sys;
677 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
679 *w = p_sys->ki.original_canvas_width;
680 *h = p_sys->ki.original_canvas_height;
682 else
684 *w = p_vout->fmt_in.i_width;
685 *h = p_vout->fmt_in.i_height;
687 msg_Dbg( p_dec, "video: in %d %d, out %d %d, original canvas %zu %zu",
688 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
689 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
690 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
691 vlc_object_release( p_vout );
693 #endif
696 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
698 size_t y;
700 for( y=0; y<bitmap->height; ++y )
702 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
703 const uint8_t *src = bitmap->pixels+y*bitmap->width;
704 memcpy( dest, src, bitmap->width );
708 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
710 size_t n;
712 fmt_palette->i_entries = palette->ncolors;
713 for( n=0; n<palette->ncolors; ++n )
715 rgb_to_yuv(
716 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
717 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
719 fmt_palette->palette[n][3] = palette->colors[n].a;
723 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
725 decoder_sys_t *p_sys = p_dec->p_sys;
727 if( ev->text_encoding != kate_utf8 )
729 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
730 return;
733 switch( ev->text_markup_type )
735 case kate_markup_none:
736 p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
737 break;
738 case kate_markup_simple:
739 if( p_sys->b_formatted )
741 /* the HTML renderer expects a top level text tag pair */
742 char *buffer = NULL;
743 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
745 p_spu->p_region->psz_html = buffer;
747 break;
749 /* if not formatted, we fall through */
750 default:
751 /* we don't know about this one, so remove markup and display as text */
753 char *copy = strdup( ev->text );
754 size_t len0 = strlen( copy ) + 1;
755 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
756 p_spu->p_region->psz_text = copy;
758 break;
762 #ifdef HAVE_TIGER
764 static void TigerDestroySubpicture( subpicture_t *p_subpic )
766 DecSysRelease( p_subpic->updater.p_sys->p_dec_sys );
767 free( p_subpic->updater.p_sys );
770 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
771 * alpha to avoid double multiply (and thus thinner text than we should)).
772 * Best would be to have VLC be able to handle premultiplied alpha, as it
773 * would be faster to blend as well.
775 * Also, we flip color components around for big endian machines, as Tiger
776 * outputs ARGB or ABGR (the one we selected here) in host endianness.
778 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
780 PROFILE_START( tiger_renderer_postprocess );
781 int y;
782 for( y=0; y<p_plane->i_lines; ++y )
784 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
785 unsigned int x;
786 for( x=0; x<i_width; ++x )
788 uint8_t *p_pixel = p_line+x*4;
789 #ifdef WORDS_BIGENDIAN
790 uint8_t a = p_pixel[0];
791 #else
792 uint8_t a = p_pixel[3];
793 #endif
794 if( a )
796 #ifdef WORDS_BIGENDIAN
797 uint8_t tmp = p_pixel[2];
798 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
799 p_pixel[3] = a;
800 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
801 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
802 #else
803 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
804 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
805 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
806 #endif
808 else
810 p_pixel[0] = 0;
811 p_pixel[1] = 0;
812 p_pixel[2] = 0;
813 p_pixel[3] = 0;
817 PROFILE_STOP( tiger_renderer_postprocess );
820 static int TigerValidateSubpicture( subpicture_t *p_subpic,
821 bool b_fmt_src, const video_format_t *p_fmt_src,
822 bool b_fmt_dst, const video_format_t *p_fmt_dst,
823 mtime_t ts )
825 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
827 if( b_fmt_src || b_fmt_dst )
828 return VLC_EGENERIC;
830 PROFILE_START( TigerValidateSubpicture );
832 /* time in seconds from the start of the stream */
833 kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
835 /* it is likely that the current region (if any) can be kept as is; test for this */
836 vlc_mutex_lock( &p_sys->lock );
837 int i_ret;
838 if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
840 i_ret = VLC_EGENERIC;
841 goto exit;
843 if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
844 tiger_renderer_is_dirty( p_sys->p_tr ) )
846 i_ret = VLC_EGENERIC;
847 goto exit;
850 i_ret = VLC_SUCCESS;
851 exit:
852 vlc_mutex_unlock( &p_sys->lock );
853 PROFILE_STOP( TigerValidateSubpicture );
854 return i_ret;
857 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
858 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
859 Looks good with white though since it's all luma. Hopefully that will be the
860 common case. */
861 static void TigerUpdateSubpicture( subpicture_t *p_subpic,
862 const video_format_t *p_fmt_src,
863 const video_format_t *p_fmt_dst,
864 mtime_t ts )
866 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
867 plane_t *p_plane;
868 kate_float t;
869 int i_ret;
872 /* time in seconds from the start of the stream */
873 t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
875 PROFILE_START( TigerUpdateSubpicture );
877 /* create a full frame region - this will also tell Tiger the size of the frame */
878 video_format_t fmt = *p_fmt_dst;
879 fmt.i_chroma = VLC_CODEC_RGBA;
880 fmt.i_bits_per_pixel = 0;
881 fmt.i_width =
882 fmt.i_visible_width = p_fmt_src->i_width;
883 fmt.i_height =
884 fmt.i_visible_height = p_fmt_src->i_height;
885 fmt.i_x_offset = fmt.i_y_offset = 0;
887 subpicture_region_t *p_r = subpicture_region_New( &fmt );
888 if( !p_r )
889 return;
891 p_r->i_x = 0;
892 p_r->i_y = 0;
893 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
895 vlc_mutex_lock( &p_sys->lock );
897 p_plane = &p_r->p_picture->p[0];
898 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 );
899 if( i_ret < 0 )
901 goto failure;
904 PROFILE_START( tiger_renderer_update );
905 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
906 if( i_ret < 0 )
908 goto failure;
910 PROFILE_STOP( tiger_renderer_update );
912 PROFILE_START( tiger_renderer_render );
913 i_ret = tiger_renderer_render( p_sys->p_tr );
914 if( i_ret < 0 )
916 goto failure;
918 PROFILE_STOP( tiger_renderer_render );
920 PostprocessTigerImage( p_plane, fmt.i_width );
921 p_subpic->p_region = p_r;
922 p_sys->b_dirty = false;
924 PROFILE_STOP( TigerUpdateSubpicture );
926 vlc_mutex_unlock( &p_sys->lock );
928 return;
930 failure:
931 vlc_mutex_unlock( &p_sys->lock );
932 subpicture_region_ChainDelete( p_r );
935 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
937 char *psz_tmp;
938 uint32_t i_color = 0;
940 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
942 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
943 var_Destroy( p_dec, psz_tmp );
944 free( psz_tmp );
945 i_color |= i_rgb;
948 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
950 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
951 var_Destroy( p_dec, psz_tmp );
952 free( psz_tmp );
953 i_color |= (i_alpha << 24);
956 return i_color;
959 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
961 char *psz_value = var_CreateGetString( p_dec, psz_name );
962 if( psz_value)
964 psz_value = strdup( psz_value );
966 var_Destroy( p_dec, psz_name );
967 return psz_value;
970 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
972 int i_value = var_CreateGetInteger( p_dec, psz_name );
973 var_Destroy( p_dec, psz_name );
974 return i_value;
977 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
979 double f_value = var_CreateGetFloat( p_dec, psz_name );
980 var_Destroy( p_dec, psz_name );
981 return f_value;
984 static void UpdateTigerQuality( decoder_t *p_dec )
986 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
987 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
988 p_sys->b_dirty = true;
991 static void UpdateTigerFontDesc( decoder_t *p_dec )
993 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
994 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
995 p_sys->b_dirty = true;
998 static void UpdateTigerFontColor( 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_font_color >> 24) & 0xff) / 255.0;
1002 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
1003 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
1004 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
1005 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1006 p_sys->b_dirty = true;
1009 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
1011 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1012 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
1013 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1014 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1015 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1016 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1017 p_sys->b_dirty = true;
1020 static void UpdateTigerFontEffect( decoder_t *p_dec )
1022 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1023 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1024 p_sys->e_tiger_default_font_effect,
1025 p_sys->f_tiger_default_font_effect_strength ) );
1026 p_sys->b_dirty = true;
1029 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1030 vlc_value_t oldval, vlc_value_t newval )
1032 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1034 VLC_UNUSED( oldval );
1036 vlc_mutex_lock( &p_sys->lock );
1038 msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1040 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1042 vlc_mutex_unlock( &p_sys->lock );
1043 return VLC_SUCCESS;
1046 #define TEST_TIGER_VAR( name ) \
1047 if( !strcmp( name, psz_var ) )
1049 TEST_TIGER_VAR( "kate-tiger-quality" )
1051 p_sys->f_tiger_quality = newval.f_float;
1052 UpdateTigerQuality( p_dec );
1055 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1057 if( p_sys->psz_tiger_default_font_desc )
1059 free( p_sys->psz_tiger_default_font_desc );
1060 p_sys->psz_tiger_default_font_desc = NULL;
1062 if( newval.psz_string )
1064 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1066 UpdateTigerFontDesc( p_dec );
1069 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1071 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1072 UpdateTigerFontColor( p_dec );
1075 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1077 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1078 UpdateTigerFontColor( p_dec );
1081 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1083 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1084 UpdateTigerBackgroundColor( p_dec );
1087 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1089 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1090 UpdateTigerBackgroundColor( p_dec );
1093 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1095 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1096 UpdateTigerFontEffect( p_dec );
1099 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1101 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1102 UpdateTigerFontEffect( p_dec );
1105 #undef TEST_TIGER_VAR
1107 vlc_mutex_unlock( &p_sys->lock );
1109 return VLC_SUCCESS;
1112 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1113 vlc_value_t oldval, vlc_value_t newval,
1114 void *p_data )
1116 size_t i_idx;
1118 VLC_UNUSED( p_this );
1119 VLC_UNUSED( oldval );
1120 VLC_UNUSED( newval );
1121 VLC_UNUSED( p_data );
1123 vlc_mutex_lock( &kate_decoder_list_mutex );
1125 /* Update all existing decoders from the global user prefs */
1126 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1128 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1129 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1132 vlc_mutex_unlock( &kate_decoder_list_mutex );
1134 return VLC_SUCCESS;
1137 #endif
1139 /*****************************************************************************
1140 * DecodePacket: decodes a Kate packet.
1141 *****************************************************************************/
1142 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1144 decoder_sys_t *p_sys = p_dec->p_sys;
1145 const kate_event *ev = NULL;
1146 subpicture_t *p_spu = NULL;
1147 int i_ret;
1149 if( !p_sys->b_ready )
1151 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1152 return NULL;
1155 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1156 if( i_ret < 0 )
1158 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1159 return NULL;
1162 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1163 if( i_ret < 0 )
1165 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1166 return NULL;
1168 if( i_ret > 0 )
1170 /* no event to go with this packet, this is normal */
1171 return NULL;
1174 /* we have an event */
1176 /* Get a new spu */
1177 subpicture_updater_sys_t *p_spu_sys = NULL;
1178 if( p_sys->b_use_tiger)
1180 p_spu_sys = malloc( sizeof(*p_spu_sys) );
1181 if( !p_spu_sys )
1182 return NULL;
1184 subpicture_updater_t updater = {
1185 #ifdef HAVE_TIGER
1186 .pf_validate = TigerValidateSubpicture,
1187 .pf_update = TigerUpdateSubpicture,
1188 .pf_destroy = TigerDestroySubpicture,
1189 #endif
1190 .p_sys = p_spu_sys,
1192 p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1193 if( !p_spu )
1195 free( p_spu_sys );
1196 /* this will happen for lyrics as there is no vout - so no error */
1197 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1198 return NULL;
1201 p_spu->i_start = p_block->i_pts;
1202 p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1203 p_spu->b_ephemer = false;
1204 p_spu->b_absolute = false;
1206 #ifdef HAVE_TIGER
1207 if( p_sys->b_use_tiger)
1209 p_spu_sys->p_dec_sys = p_sys;
1210 p_spu_sys->i_start = p_block->i_pts;
1211 DecSysHold( p_sys );
1213 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1214 p_spu->b_ephemer = true;
1215 p_spu->b_absolute = true;
1217 /* add the event to tiger */
1218 vlc_mutex_lock( &p_sys->lock );
1219 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1220 vlc_mutex_unlock( &p_sys->lock );
1222 else
1223 #endif
1225 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1228 return p_spu;
1231 /*****************************************************************************
1232 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1233 *****************************************************************************/
1234 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1235 const kate_event *ev )
1237 decoder_sys_t *p_sys = p_dec->p_sys;
1238 video_format_t fmt;
1239 subpicture_region_t *p_bitmap_region = NULL;
1240 video_palette_t palette;
1241 kate_tracker kin;
1242 bool b_tracker_valid = false;
1243 int i_ret;
1245 /* these may be 0 for "not specified" */
1246 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1247 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1249 /* Create a new subpicture region */
1250 memset( &fmt, 0, sizeof(video_format_t) );
1252 if (p_sys->b_formatted)
1254 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1255 if( i_ret < 0)
1257 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1259 else
1261 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1262 GetVideoSize(p_dec, &w, &h);
1263 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1264 if( i_ret < 0)
1266 kate_tracker_clear(&kin);
1267 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1269 else
1271 // TODO: parse tracker and set style, init fmt
1272 b_tracker_valid = true;
1277 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1279 /* create a separate region for the bitmap */
1280 memset( &fmt, 0, sizeof(video_format_t) );
1281 fmt.i_chroma = VLC_CODEC_YUVP;
1282 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1283 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1284 fmt.i_x_offset = fmt.i_y_offset = 0;
1285 fmt.p_palette = &palette;
1286 CreateKatePalette( fmt.p_palette, ev->palette );
1288 p_bitmap_region = subpicture_region_New( &fmt );
1289 if( !p_bitmap_region )
1291 msg_Err( p_dec, "cannot allocate SPU region" );
1292 decoder_DeleteSubpicture( p_dec, p_spu );
1293 return NULL;
1296 /* create the bitmap */
1297 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1299 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1302 /* text region */
1303 fmt.i_chroma = VLC_CODEC_TEXT;
1304 fmt.i_sar_num = 0;
1305 fmt.i_sar_den = 1;
1306 fmt.i_width = fmt.i_height = 0;
1307 fmt.i_x_offset = fmt.i_y_offset = 0;
1308 p_spu->p_region = subpicture_region_New( &fmt );
1309 if( !p_spu->p_region )
1311 msg_Err( p_dec, "cannot allocate SPU region" );
1312 decoder_DeleteSubpicture( p_dec, p_spu );
1313 return NULL;
1316 SetupText( p_dec, p_spu, ev );
1318 /* default positioning */
1319 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1320 if (p_bitmap_region)
1322 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1324 p_spu->p_region->i_x = 0;
1325 p_spu->p_region->i_y = 10;
1327 /* override if tracker info present */
1328 if (b_tracker_valid)
1330 if (kin.has.region)
1332 p_spu->p_region->i_x = kin.region_x;
1333 p_spu->p_region->i_y = kin.region_y;
1334 if (p_bitmap_region)
1336 p_bitmap_region->i_x = kin.region_x;
1337 p_bitmap_region->i_y = kin.region_y;
1339 p_spu->b_absolute = true;
1342 kate_tracker_clear(&kin);
1345 /* if we have a bitmap, chain it before the text */
1346 if (p_bitmap_region)
1348 p_bitmap_region->p_next = p_spu->p_region;
1349 p_spu->p_region = p_bitmap_region;
1352 return p_spu;
1355 /*****************************************************************************
1356 * ParseKateComments:
1357 *****************************************************************************/
1358 static void ParseKateComments( decoder_t *p_dec )
1360 char *psz_name, *psz_value, *psz_comment;
1361 int i = 0;
1363 while ( i < p_dec->p_sys->kc.comments )
1365 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1366 if( !psz_comment )
1367 break;
1368 psz_name = psz_comment;
1369 psz_value = strchr( psz_comment, '=' );
1370 if( psz_value )
1372 *psz_value = '\0';
1373 psz_value++;
1375 if( !p_dec->p_description )
1376 p_dec->p_description = vlc_meta_New();
1377 if( p_dec->p_description )
1378 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1380 free( psz_comment );
1381 i++;
1385 /*****************************************************************************
1386 * CloseDecoder: clean up the decoder
1387 *****************************************************************************/
1388 static void CloseDecoder( vlc_object_t *p_this )
1390 decoder_t *p_dec = (decoder_t *)p_this;
1391 size_t i_index;
1393 /* remove the decoder from the global list */
1394 vlc_mutex_lock( &kate_decoder_list_mutex );
1395 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1397 if( kate_decoder_list[ i_index ] == p_dec )
1399 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1400 break;
1403 vlc_mutex_unlock( &kate_decoder_list_mutex );
1405 msg_Dbg( p_dec, "Closing Kate decoder" );
1406 DecSysRelease( p_dec->p_sys );
1409 static void DecSysHold( decoder_sys_t *p_sys )
1411 vlc_mutex_lock( &p_sys->lock );
1412 p_sys->i_refcount++;
1413 vlc_mutex_unlock( &p_sys->lock );
1416 static void DecSysRelease( decoder_sys_t *p_sys )
1418 vlc_mutex_lock( &p_sys->lock );
1419 p_sys->i_refcount--;
1420 if( p_sys->i_refcount > 0)
1422 vlc_mutex_unlock( &p_sys->lock );
1423 return;
1426 vlc_mutex_unlock( &p_sys->lock );
1427 vlc_mutex_destroy( &p_sys->lock );
1429 #ifdef HAVE_TIGER
1430 if( p_sys->p_tr )
1431 tiger_renderer_destroy( p_sys->p_tr );
1432 free( p_sys->psz_tiger_default_font_desc );
1433 #endif
1435 if (p_sys->b_ready)
1436 kate_clear( &p_sys->k );
1437 kate_info_clear( &p_sys->ki );
1438 kate_comment_clear( &p_sys->kc );
1440 free( p_sys );