Revert "codec: don't drop discontinue blocks"
[vlc.git] / modules / codec / kate.c
blob73c5bce4a4aec2391ee3f8058866b64789dcac8f
1 /*****************************************************************************
2 * kate.c : a decoder for the kate bitstream format
3 *****************************************************************************
4 * Copyright (C) 2000-2008 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_input.h>
34 #include <vlc_codec.h>
35 #include "../demux/xiph.h"
37 #include <kate/kate.h>
38 #ifdef HAVE_TIGER
39 # include <tiger/tiger.h>
40 #endif
42 /* #define ENABLE_PACKETIZER */
43 /* #define ENABLE_PROFILE */
45 #ifdef ENABLE_PROFILE
46 # define PROFILE_START(name) int64_t profile_start_##name = mdate()
47 # define PROFILE_STOP(name) fprintf( stderr, #name ": %f ms\n", (mdate() - profile_start_##name)/1000.0f )
48 #else
49 # define PROFILE_START(name) ((void)0)
50 # define PROFILE_STOP(name) ((void)0)
51 #endif
53 #define CHECK_TIGER_RET( statement ) \
54 do \
55 { \
56 int i_ret = (statement); \
57 if( i_ret < 0 ) \
58 { \
59 msg_Dbg( p_dec, "Error in " #statement ": %d", i_ret ); \
60 } \
61 } while( 0 )
63 /*****************************************************************************
64 * decoder_sys_t : decoder descriptor
65 *****************************************************************************/
66 struct decoder_sys_t
68 #ifdef ENABLE_PACKETIZER
69 /* Module mode */
70 bool b_packetizer;
71 #endif
74 * Input properties
76 bool b_has_headers;
79 * Kate properties
81 bool b_ready;
82 kate_info ki;
83 kate_comment kc;
84 kate_state k;
87 * Common properties
89 mtime_t i_pts;
90 mtime_t i_max_stop;
92 /* decoder_sys_t is shared between decoder and spu units */
93 vlc_mutex_t lock;
94 int i_refcount;
96 #ifdef HAVE_TIGER
98 * Tiger properties
100 tiger_renderer *p_tr;
101 bool b_dirty;
103 uint32_t i_tiger_default_font_color;
104 uint32_t i_tiger_default_background_color;
105 tiger_font_effect e_tiger_default_font_effect;
106 double f_tiger_default_font_effect_strength;
107 char *psz_tiger_default_font_desc;
108 double f_tiger_quality;
109 #endif
112 * Options
114 bool b_formatted;
115 bool b_use_tiger;
118 struct subpicture_updater_sys_t
120 decoder_sys_t *p_dec_sys;
121 mtime_t i_start;
126 * This is a global list of existing decoders.
127 * The reason for this list is that:
128 * - I want to be able to reconfigure Tiger when user prefs change
129 * - User prefs are variables which are not specific to a decoder (eg, if
130 * there are several decoders, there will still be one set of variables)
131 * - A callback set on those will not be passed a pointer to the decoder
132 * (as the decoder isn't known, and there could be multiple ones)
133 * - Creating variables in the decoder will create different ones, with
134 * values copied from the relevant user pref, so a callback on those
135 * won't be called when the user pref is changed
136 * Therefore, each decoder will register/unregister itself with this list,
137 * callbacks will be set for the user prefs, and these will in turn walk
138 * through this list and tell each decoder to update the relevant variable.
139 * HOWEVER.
140 * VLC's variable system is still in my way as I can't get the value of
141 * the user pref variables at decoder start *unless* I create my own vars
142 * which inherit from the user ones, but those are utterly useless after
143 * that first use, since they'll be detached from the ones the user can
144 * change. So, I create them, read their values, and then destroy them.
146 static vlc_mutex_t kate_decoder_list_mutex = VLC_STATIC_MUTEX;
147 static size_t kate_decoder_list_size = 0;
148 static decoder_t **kate_decoder_list = NULL;
150 /*****************************************************************************
151 * Local prototypes
152 *****************************************************************************/
153 static int OpenDecoder ( vlc_object_t * );
154 static void CloseDecoder ( vlc_object_t * );
155 #ifdef ENABLE_PACKETIZER
156 static int OpenPacketizer( vlc_object_t *p_this );
157 #endif
159 static 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;
407 else {
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 );
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;
519 if( i_count < 1 )
520 return VLC_EGENERIC;
522 /* Take care of the initial Kate header */
523 kp.nbytes = pi_size[0];
524 kp.data = pp_data[0];
525 int i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
526 if( i_ret < 0 )
528 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
529 return VLC_EGENERIC;
532 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
533 p_sys->ki.language, p_sys->ki.category,
534 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
535 p_sys->ki.granule_shift);
537 /* parse all remaining header packets */
538 for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
540 kp.nbytes = pi_size[i_headeridx];
541 kp.data = pp_data[i_headeridx];
542 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
543 if( i_ret < 0 )
545 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
546 return VLC_EGENERIC;
549 /* header 1 is comments */
550 if( i_headeridx == 1 )
552 ParseKateComments( p_dec );
556 #ifdef ENABLE_PACKETIZER
557 if( !p_sys->b_packetizer )
558 #endif
560 /* We have all the headers, initialize decoder */
561 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
562 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
563 if (i_ret < 0)
565 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
566 return VLC_EGENERIC;
568 p_sys->b_ready = true;
570 #ifdef ENABLE_PACKETIZER
571 else
573 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
574 p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
575 p_dec->fmt_out.i_extra );
576 memcpy( p_dec->fmt_out.p_extra,
577 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
579 #endif
581 return VLC_SUCCESS;
584 /*****************************************************************************
585 * ProcessPacket: processes a kate packet.
586 *****************************************************************************/
587 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
588 block_t **pp_block )
590 decoder_sys_t *p_sys = p_dec->p_sys;
591 block_t *p_block = *pp_block;
592 subpicture_t *p_buf = NULL;
594 /* Date management */
595 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
597 p_sys->i_pts = p_block->i_pts;
600 *pp_block = NULL; /* To avoid being fed the same packet again */
602 #ifdef ENABLE_PACKETIZER
603 if( p_sys->b_packetizer )
605 /* Date management */
606 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
608 if( p_sys->i_headers >= p_sys->i_num_headers )
609 p_block->i_length = p_sys->i_pts - p_block->i_pts;
610 else
611 p_block->i_length = 0;
613 p_buf = p_block;
615 else
616 #endif
618 p_buf = DecodePacket( p_dec, p_kp, p_block );
620 if( p_block )
621 block_Release( p_block );
624 return p_buf;
627 /* nicked off blend.c */
628 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
629 int r, int g, int b )
631 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
632 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
633 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
637 This retrieves the size of the video.
638 The best case is when the original video size is known, as we can then
639 scale images to match. In this case, since VLC autoscales, we want to
640 return the original size and let VLC scale everything.
641 if the original size is not known, then VLC can't resize, so we return
642 the size of the incoming video. If sizes in the Kate stream are in
643 relative units, it works fine. If they are absolute, you get what you
644 ask for. Images aren't rescaled.
646 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
648 /* searching for vout to get its size is frowned upon, so we don't and
649 use a default size if the original canvas size is not specified. */
650 decoder_sys_t *p_sys = p_dec->p_sys;
651 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
653 *w = p_sys->ki.original_canvas_width;
654 *h = p_sys->ki.original_canvas_height;
655 msg_Dbg( p_dec, "original canvas %zu %zu",
656 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
658 else
660 /* nothing, leave defaults */
661 msg_Dbg( p_dec, "original canvas size unknown");
665 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
667 size_t y;
669 for( y=0; y<bitmap->height; ++y )
671 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
672 const uint8_t *src = bitmap->pixels+y*bitmap->width;
673 memcpy( dest, src, bitmap->width );
677 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
679 size_t n;
681 fmt_palette->i_entries = palette->ncolors;
682 for( n=0; n<palette->ncolors; ++n )
684 rgb_to_yuv(
685 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
686 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
688 fmt_palette->palette[n][3] = palette->colors[n].a;
692 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
694 decoder_sys_t *p_sys = p_dec->p_sys;
696 if( ev->text_encoding != kate_utf8 )
698 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
699 return;
702 switch( ev->text_markup_type )
704 case kate_markup_none:
705 case kate_markup_simple:
706 if( p_sys->b_formatted )
707 // p_spu->p_region->p_text = ParseSubtitles(&p_spu->p_region->i_align, ev->text );
708 ;//FIXME
709 else
710 p_spu->p_region->p_text = text_segment_New( ev->text ); /* no leak, this actually gets killed by the core */
711 break;
712 default:
713 /* we don't know about this one, so remove markup and display as text */
715 char *copy = strdup( ev->text );
716 size_t len0 = strlen( copy ) + 1;
717 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
718 p_spu->p_region->p_text = text_segment_New( copy );
719 free( copy );
721 break;
725 #ifdef HAVE_TIGER
727 static void TigerDestroySubpicture( subpicture_t *p_subpic )
729 DecSysRelease( p_subpic->updater.p_sys->p_dec_sys );
730 free( p_subpic->updater.p_sys );
733 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
734 * alpha to avoid double multiply (and thus thinner text than we should)).
735 * Best would be to have VLC be able to handle premultiplied alpha, as it
736 * would be faster to blend as well.
738 * Also, we flip color components around for big endian machines, as Tiger
739 * outputs ARGB or ABGR (the one we selected here) in host endianness.
741 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
743 PROFILE_START( tiger_renderer_postprocess );
744 int y;
745 for( y=0; y<p_plane->i_lines; ++y )
747 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
748 unsigned int x;
749 for( x=0; x<i_width; ++x )
751 uint8_t *p_pixel = p_line+x*4;
752 #ifdef WORDS_BIGENDIAN
753 uint8_t a = p_pixel[0];
754 #else
755 uint8_t a = p_pixel[3];
756 #endif
757 if( a )
759 #ifdef WORDS_BIGENDIAN
760 uint8_t tmp = p_pixel[2];
761 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
762 p_pixel[3] = a;
763 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
764 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
765 #else
766 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
767 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
768 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
769 #endif
771 else
773 p_pixel[0] = 0;
774 p_pixel[1] = 0;
775 p_pixel[2] = 0;
776 p_pixel[3] = 0;
780 PROFILE_STOP( tiger_renderer_postprocess );
783 static int TigerValidateSubpicture( subpicture_t *p_subpic,
784 bool b_fmt_src, const video_format_t *p_fmt_src,
785 bool b_fmt_dst, const video_format_t *p_fmt_dst,
786 mtime_t ts )
788 VLC_UNUSED(p_fmt_src); VLC_UNUSED(p_fmt_dst);
790 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
792 if( b_fmt_src || b_fmt_dst )
793 return VLC_EGENERIC;
795 PROFILE_START( TigerValidateSubpicture );
797 /* time in seconds from the start of the stream */
798 kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
800 /* it is likely that the current region (if any) can be kept as is; test for this */
801 vlc_mutex_lock( &p_sys->lock );
802 int i_ret;
803 if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
805 i_ret = VLC_EGENERIC;
806 goto exit;
808 if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
809 tiger_renderer_is_dirty( p_sys->p_tr ) )
811 i_ret = VLC_EGENERIC;
812 goto exit;
815 i_ret = VLC_SUCCESS;
816 exit:
817 vlc_mutex_unlock( &p_sys->lock );
818 PROFILE_STOP( TigerValidateSubpicture );
819 return i_ret;
822 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
823 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
824 Looks good with white though since it's all luma. Hopefully that will be the
825 common case. */
826 static void TigerUpdateSubpicture( subpicture_t *p_subpic,
827 const video_format_t *p_fmt_src,
828 const video_format_t *p_fmt_dst,
829 mtime_t ts )
831 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
832 plane_t *p_plane;
833 kate_float t;
834 int i_ret;
837 /* time in seconds from the start of the stream */
838 t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
840 PROFILE_START( TigerUpdateSubpicture );
842 /* create a full frame region - this will also tell Tiger the size of the frame */
843 video_format_t fmt = *p_fmt_dst;
844 fmt.i_chroma = VLC_CODEC_RGBA;
845 fmt.i_bits_per_pixel = 0;
846 fmt.i_width =
847 fmt.i_visible_width = p_fmt_src->i_width;
848 fmt.i_height =
849 fmt.i_visible_height = p_fmt_src->i_height;
850 fmt.i_x_offset = fmt.i_y_offset = 0;
852 subpicture_region_t *p_r = subpicture_region_New( &fmt );
853 if( !p_r )
854 return;
856 p_r->i_x = 0;
857 p_r->i_y = 0;
858 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
860 vlc_mutex_lock( &p_sys->lock );
862 p_plane = &p_r->p_picture->p[0];
863 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 );
864 if( i_ret < 0 )
866 goto failure;
869 PROFILE_START( tiger_renderer_update );
870 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
871 if( i_ret < 0 )
873 goto failure;
875 PROFILE_STOP( tiger_renderer_update );
877 PROFILE_START( tiger_renderer_render );
878 i_ret = tiger_renderer_render( p_sys->p_tr );
879 if( i_ret < 0 )
881 goto failure;
883 PROFILE_STOP( tiger_renderer_render );
885 PostprocessTigerImage( p_plane, fmt.i_width );
886 p_subpic->p_region = p_r;
887 p_sys->b_dirty = false;
889 PROFILE_STOP( TigerUpdateSubpicture );
891 vlc_mutex_unlock( &p_sys->lock );
893 return;
895 failure:
896 vlc_mutex_unlock( &p_sys->lock );
897 subpicture_region_ChainDelete( p_r );
900 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
902 char *psz_tmp;
903 uint32_t i_color = 0;
905 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
907 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
908 var_Destroy( p_dec, psz_tmp );
909 free( psz_tmp );
910 i_color |= i_rgb;
913 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
915 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
916 var_Destroy( p_dec, psz_tmp );
917 free( psz_tmp );
918 i_color |= (i_alpha << 24);
921 return i_color;
924 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
926 char *psz_value = var_CreateGetString( p_dec, psz_name );
927 if( psz_value)
929 psz_value = strdup( psz_value );
931 var_Destroy( p_dec, psz_name );
932 return psz_value;
935 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
937 int i_value = var_CreateGetInteger( p_dec, psz_name );
938 var_Destroy( p_dec, psz_name );
939 return i_value;
942 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
944 double f_value = var_CreateGetFloat( p_dec, psz_name );
945 var_Destroy( p_dec, psz_name );
946 return f_value;
949 static void UpdateTigerQuality( decoder_t *p_dec )
951 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
952 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
953 p_sys->b_dirty = true;
956 static void UpdateTigerFontDesc( decoder_t *p_dec )
958 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
959 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
960 p_sys->b_dirty = true;
963 static void UpdateTigerFontColor( decoder_t *p_dec )
965 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
966 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
967 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
968 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
969 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
970 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
971 p_sys->b_dirty = true;
974 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
976 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
977 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
978 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
979 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
980 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
981 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
982 p_sys->b_dirty = true;
985 static void UpdateTigerFontEffect( decoder_t *p_dec )
987 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
988 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
989 p_sys->e_tiger_default_font_effect,
990 p_sys->f_tiger_default_font_effect_strength ) );
991 p_sys->b_dirty = true;
994 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
995 vlc_value_t oldval, vlc_value_t newval )
997 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
999 VLC_UNUSED( oldval );
1001 vlc_mutex_lock( &p_sys->lock );
1003 msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1005 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1007 vlc_mutex_unlock( &p_sys->lock );
1008 return VLC_SUCCESS;
1011 #define TEST_TIGER_VAR( name ) \
1012 if( !strcmp( name, psz_var ) )
1014 TEST_TIGER_VAR( "kate-tiger-quality" )
1016 p_sys->f_tiger_quality = newval.f_float;
1017 UpdateTigerQuality( p_dec );
1020 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1022 if( p_sys->psz_tiger_default_font_desc )
1024 free( p_sys->psz_tiger_default_font_desc );
1025 p_sys->psz_tiger_default_font_desc = NULL;
1027 if( newval.psz_string )
1029 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1031 UpdateTigerFontDesc( p_dec );
1034 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1036 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1037 UpdateTigerFontColor( p_dec );
1040 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1042 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1043 UpdateTigerFontColor( p_dec );
1046 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1048 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1049 UpdateTigerBackgroundColor( p_dec );
1052 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1054 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1055 UpdateTigerBackgroundColor( p_dec );
1058 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1060 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1061 UpdateTigerFontEffect( p_dec );
1064 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1066 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1067 UpdateTigerFontEffect( p_dec );
1070 #undef TEST_TIGER_VAR
1072 vlc_mutex_unlock( &p_sys->lock );
1074 return VLC_SUCCESS;
1077 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1078 vlc_value_t oldval, vlc_value_t newval,
1079 void *p_data )
1081 size_t i_idx;
1083 VLC_UNUSED( p_this );
1084 VLC_UNUSED( oldval );
1085 VLC_UNUSED( newval );
1086 VLC_UNUSED( p_data );
1088 vlc_mutex_lock( &kate_decoder_list_mutex );
1090 /* Update all existing decoders from the global user prefs */
1091 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1093 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1094 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1097 vlc_mutex_unlock( &kate_decoder_list_mutex );
1099 return VLC_SUCCESS;
1102 #endif
1104 /*****************************************************************************
1105 * DecodePacket: decodes a Kate packet.
1106 *****************************************************************************/
1107 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1109 decoder_sys_t *p_sys = p_dec->p_sys;
1110 const kate_event *ev = NULL;
1111 subpicture_t *p_spu = NULL;
1112 int i_ret;
1114 if( !p_sys->b_ready )
1116 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1117 return NULL;
1120 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1121 if( i_ret < 0 )
1123 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1124 return NULL;
1127 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1128 if( i_ret < 0 )
1130 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1131 return NULL;
1133 if( i_ret > 0 )
1135 /* no event to go with this packet, this is normal */
1136 return NULL;
1139 /* we have an event */
1141 /* Get a new spu */
1142 subpicture_updater_sys_t *p_spu_sys = NULL;
1143 if( p_sys->b_use_tiger)
1145 p_spu_sys = malloc( sizeof(*p_spu_sys) );
1146 if( !p_spu_sys )
1147 return NULL;
1149 subpicture_updater_t updater = {
1150 #ifdef HAVE_TIGER
1151 .pf_validate = TigerValidateSubpicture,
1152 .pf_update = TigerUpdateSubpicture,
1153 .pf_destroy = TigerDestroySubpicture,
1154 #endif
1155 .p_sys = p_spu_sys,
1157 p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1158 if( !p_spu )
1160 free( p_spu_sys );
1161 /* this will happen for lyrics as there is no vout - so no error */
1162 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1163 return NULL;
1166 p_spu->i_start = p_block->i_pts;
1167 p_spu->i_stop = p_block->i_pts + CLOCK_FREQ *
1168 ev->duration * p_sys->ki.gps_denominator / p_sys->ki.gps_numerator;
1169 p_spu->b_ephemer = false;
1170 p_spu->b_absolute = false;
1172 #ifdef HAVE_TIGER
1173 if( p_sys->b_use_tiger)
1175 p_spu_sys->p_dec_sys = p_sys;
1176 p_spu_sys->i_start = p_block->i_pts;
1177 DecSysHold( p_sys );
1179 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1180 p_spu->b_ephemer = true;
1181 p_spu->b_absolute = true;
1183 /* add the event to tiger */
1184 vlc_mutex_lock( &p_sys->lock );
1185 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1186 vlc_mutex_unlock( &p_sys->lock );
1188 else
1189 #endif
1191 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1194 return p_spu;
1197 /*****************************************************************************
1198 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1199 *****************************************************************************/
1200 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1201 const kate_event *ev )
1203 decoder_sys_t *p_sys = p_dec->p_sys;
1204 video_format_t fmt;
1205 subpicture_region_t *p_bitmap_region = NULL;
1206 video_palette_t palette;
1207 kate_tracker kin;
1208 bool b_tracker_valid = false;
1209 int i_ret;
1211 /* these may be 0 for "not specified" */
1212 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1213 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1215 /* Create a new subpicture region */
1216 memset( &fmt, 0, sizeof(video_format_t) );
1218 if (p_sys->b_formatted)
1220 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1221 if( i_ret < 0)
1223 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1225 else
1227 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1228 GetVideoSize(p_dec, &w, &h);
1229 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1230 if( i_ret < 0)
1232 kate_tracker_clear(&kin);
1233 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1235 else
1237 // TODO: parse tracker and set style, init fmt
1238 b_tracker_valid = true;
1243 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1245 /* create a separate region for the bitmap */
1246 memset( &fmt, 0, sizeof(video_format_t) );
1247 fmt.i_chroma = VLC_CODEC_YUVP;
1248 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1249 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1250 fmt.i_x_offset = fmt.i_y_offset = 0;
1251 fmt.p_palette = &palette;
1252 CreateKatePalette( fmt.p_palette, ev->palette );
1254 p_bitmap_region = subpicture_region_New( &fmt );
1255 if( !p_bitmap_region )
1257 msg_Err( p_dec, "cannot allocate SPU region" );
1258 subpicture_Delete( p_spu );
1259 return NULL;
1262 /* create the bitmap */
1263 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1265 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1268 /* text region */
1269 fmt.i_chroma = VLC_CODEC_TEXT;
1270 fmt.i_sar_num = 0;
1271 fmt.i_sar_den = 1;
1272 fmt.i_width = fmt.i_height = 0;
1273 fmt.i_x_offset = fmt.i_y_offset = 0;
1274 p_spu->p_region = subpicture_region_New( &fmt );
1275 if( !p_spu->p_region )
1277 msg_Err( p_dec, "cannot allocate SPU region" );
1278 if( p_bitmap_region )
1279 subpicture_region_Delete( p_bitmap_region );
1280 subpicture_Delete( p_spu );
1281 return NULL;
1284 SetupText( p_dec, p_spu, ev );
1286 /* default positioning */
1287 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1288 if (p_bitmap_region)
1290 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1292 p_spu->p_region->i_x = 0;
1293 p_spu->p_region->i_y = 10;
1295 /* override if tracker info present */
1296 if (b_tracker_valid)
1298 if (kin.has.region)
1300 p_spu->p_region->i_x = kin.region_x;
1301 p_spu->p_region->i_y = kin.region_y;
1302 if (p_bitmap_region)
1304 p_bitmap_region->i_x = kin.region_x;
1305 p_bitmap_region->i_y = kin.region_y;
1307 p_spu->b_absolute = true;
1310 kate_tracker_clear(&kin);
1313 /* if we have a bitmap, chain it before the text */
1314 if (p_bitmap_region)
1316 p_bitmap_region->p_next = p_spu->p_region;
1317 p_spu->p_region = p_bitmap_region;
1320 return p_spu;
1323 /*****************************************************************************
1324 * ParseKateComments:
1325 *****************************************************************************/
1326 static void ParseKateComments( decoder_t *p_dec )
1328 char *psz_name, *psz_value, *psz_comment;
1329 int i = 0;
1331 while ( i < p_dec->p_sys->kc.comments )
1333 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1334 if( !psz_comment )
1335 break;
1336 psz_name = psz_comment;
1337 psz_value = strchr( psz_comment, '=' );
1338 if( psz_value )
1340 *psz_value = '\0';
1341 psz_value++;
1343 if( !p_dec->p_description )
1344 p_dec->p_description = vlc_meta_New();
1345 if( p_dec->p_description )
1346 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1348 free( psz_comment );
1349 i++;
1353 /*****************************************************************************
1354 * CloseDecoder: clean up the decoder
1355 *****************************************************************************/
1356 static void CloseDecoder( vlc_object_t *p_this )
1358 decoder_t *p_dec = (decoder_t *)p_this;
1359 size_t i_index;
1361 /* remove the decoder from the global list */
1362 vlc_mutex_lock( &kate_decoder_list_mutex );
1363 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1365 if( kate_decoder_list[ i_index ] == p_dec )
1367 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1368 break;
1371 vlc_mutex_unlock( &kate_decoder_list_mutex );
1373 msg_Dbg( p_dec, "Closing Kate decoder" );
1374 DecSysRelease( p_dec->p_sys );
1377 static void DecSysHold( decoder_sys_t *p_sys )
1379 vlc_mutex_lock( &p_sys->lock );
1380 p_sys->i_refcount++;
1381 vlc_mutex_unlock( &p_sys->lock );
1384 static void DecSysRelease( decoder_sys_t *p_sys )
1386 vlc_mutex_lock( &p_sys->lock );
1387 p_sys->i_refcount--;
1388 if( p_sys->i_refcount > 0)
1390 vlc_mutex_unlock( &p_sys->lock );
1391 return;
1394 vlc_mutex_unlock( &p_sys->lock );
1395 vlc_mutex_destroy( &p_sys->lock );
1397 #ifdef HAVE_TIGER
1398 if( p_sys->p_tr )
1399 tiger_renderer_destroy( p_sys->p_tr );
1400 free( p_sys->psz_tiger_default_font_desc );
1401 #endif
1403 if (p_sys->b_ready)
1404 kate_clear( &p_sys->k );
1405 kate_info_clear( &p_sys->ki );
1406 kate_comment_clear( &p_sys->kc );
1408 free( p_sys );