remove unndeed variables
[vlc/asuraparaju-public.git] / modules / codec / kate.c
blob0e8a899834f5afb58e0435979ea9793d37cdce22
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 <vlc_osd.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 int i_num_headers;
77 int i_headers;
80 * Kate properties
82 bool b_ready;
83 kate_info ki;
84 kate_comment kc;
85 kate_state k;
88 * Common properties
90 mtime_t i_pts;
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 subpicture_t *p_spu_final;
102 mtime_t last_render_ts;
103 bool b_dirty;
105 uint32_t i_tiger_default_font_color;
106 uint32_t i_tiger_default_background_color;
107 tiger_font_effect e_tiger_default_font_effect;
108 double f_tiger_default_font_effect_strength;
109 char *psz_tiger_default_font_desc;
110 double f_tiger_quality;
111 #endif
114 * Options
116 bool b_formatted;
117 bool b_use_tiger;
120 struct subpicture_sys_t
122 decoder_sys_t *p_dec_sys;
123 mtime_t i_start;
128 * This is a global list of existing decoders.
129 * The reason for this list is that:
130 * - I want to be able to reconfigure Tiger when user prefs change
131 * - User prefs are variables which are not specific to a decoder (eg, if
132 * there are several decoders, there will still be one set of variables)
133 * - A callback set on those will not be passed a pointer to the decoder
134 * (as the decoder isn't known, and there could be multiple ones)
135 * - Creating variables in the decoder will create different ones, with
136 * values copied from the relevant user pref, so a callback on those
137 * won't be called when the user pref is changed
138 * Therefore, each decoder will register/unregister itself with this list,
139 * callbacks will be set for the user prefs, and these will in turn walk
140 * through this list and tell each decoder to update the relevant variable.
141 * HOWEVER.
142 * VLC's variable system is still in my way as I can't get the value of
143 * the user pref variables at decoder start *unless* I create my own vars
144 * which inherit from the user ones, but those are utterly useless after
145 * that first use, since they'll be detached from the ones the user can
146 * change. So, I create them, read their values, and then destroy them.
148 static vlc_mutex_t kate_decoder_list_mutex = VLC_STATIC_MUTEX;
149 static size_t kate_decoder_list_size = 0;
150 static decoder_t **kate_decoder_list = NULL;
152 /*****************************************************************************
153 * Local prototypes
154 *****************************************************************************/
155 static int OpenDecoder ( vlc_object_t * );
156 static void CloseDecoder ( vlc_object_t * );
157 #ifdef ENABLE_PACKETIZER
158 static int OpenPacketizer( vlc_object_t *p_this );
159 #endif
161 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block );
162 static int ProcessHeaders( decoder_t *p_dec );
163 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
164 block_t **pp_block );
165 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp,
166 block_t *p_block );
167 static void ParseKateComments( decoder_t * );
168 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
169 const kate_event *ev );
170 static void DecSysRelease( decoder_sys_t *p_sys );
171 static void DecSysHold( decoder_sys_t *p_sys );
172 #ifdef HAVE_TIGER
173 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix );
174 static char *GetTigerString( decoder_t *p_dec, const char *psz_name );
175 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name );
176 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name );
177 static void UpdateTigerFontColor( decoder_t *p_dec );
178 static void UpdateTigerBackgroundColor( decoder_t *p_dec );
179 static void UpdateTigerFontEffect( decoder_t *p_dec );
180 static void UpdateTigerQuality( decoder_t *p_dec );
181 static void UpdateTigerFontDesc( decoder_t *p_dec );
182 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
183 vlc_value_t oldvar, vlc_value_t newval,
184 void *p_data );
185 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
186 vlc_value_t oldval, vlc_value_t newval);
187 #endif
189 #define DEFAULT_NAME "Default"
190 #define MAX_LINE 8192
192 /*****************************************************************************
193 * Module descriptor.
194 *****************************************************************************/
196 #define FORMAT_TEXT N_("Formatted Subtitles")
197 #define FORMAT_LONGTEXT N_("Kate streams allow for text formatting. " \
198 "VLC partly implements this, but you can choose to disable all formatting." \
199 "Note that this has no effect is rendering via Tiger is enabled.")
201 #ifdef HAVE_TIGER
203 static const tiger_font_effect pi_font_effects[] = { tiger_font_plain, tiger_font_shadow, tiger_font_outline };
204 static const char * const ppsz_font_effect_names[] = { N_("None"), N_("Shadow"), N_("Outline") };
206 /* nicked off freetype.c */
207 static const int pi_color_values[] = {
208 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000,
209 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080,
210 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF };
211 static const char *const ppsz_color_descriptions[] = {
212 N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"),
213 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"),
214 N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") };
216 #define TIGER_TEXT N_("Use Tiger for rendering")
217 #define TIGER_LONGTEXT N_("Kate streams can be rendered using the Tiger library. " \
218 "Disabling this will only render static text and bitmap based streams.")
220 #define TIGER_QUALITY_DEFAULT 1.0
221 #define TIGER_QUALITY_TEXT N_("Rendering quality")
222 #define TIGER_QUALITY_LONGTEXT N_("Select rendering quality, at the expense of speed. " \
223 "0 is fastest, 1 is highest quality.")
225 #define TIGER_DEFAULT_FONT_EFFECT_DEFAULT 0
226 #define TIGER_DEFAULT_FONT_EFFECT_TEXT N_("Default font effect")
227 #define TIGER_DEFAULT_FONT_EFFECT_LONGTEXT N_("Add a font effect to text to improve readability " \
228 "against different backgrounds.")
230 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT 0.5
231 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT N_("Default font effect strength")
232 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT N_("How pronounced to make the chosen font effect " \
233 "(effect dependent).")
235 #define TIGER_DEFAULT_FONT_DESC_DEFAULT ""
236 #define TIGER_DEFAULT_FONT_DESC_TEXT N_("Default font description")
237 #define TIGER_DEFAULT_FONT_DESC_LONGTEXT N_("Which font description to use if the Kate stream " \
238 "does not specify particular font parameters (name, size, etc) to use. " \
239 "A blank name will let Tiger choose font parameters where appropriate.")
241 #define TIGER_DEFAULT_FONT_COLOR_DEFAULT 0x00ffffff
242 #define TIGER_DEFAULT_FONT_COLOR_TEXT N_("Default font color")
243 #define TIGER_DEFAULT_FONT_COLOR_LONGTEXT N_("Default font color to use if the Kate stream " \
244 "does not specify a particular font color to use.")
246 #define TIGER_DEFAULT_FONT_ALPHA_DEFAULT 0xff
247 #define TIGER_DEFAULT_FONT_ALPHA_TEXT N_("Default font alpha")
248 #define TIGER_DEFAULT_FONT_ALPHA_LONGTEXT N_("Transparency of the default font color if the Kate stream " \
249 "does not specify a particular font color to use.")
251 #define TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT 0x00ffffff
252 #define TIGER_DEFAULT_BACKGROUND_COLOR_TEXT N_("Default background color")
253 #define TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT N_("Default background color if the Kate stream " \
254 "does not specify a background color to use.")
256 #define TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT 0
257 #define TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT N_("Default background alpha")
258 #define TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT N_("Transparency of the default background color if the Kate stream " \
259 "does not specify a particular background color to use.")
261 #endif
263 #define HELP_TEXT N_( \
264 "Kate is a codec for text and image based overlays.\n" \
265 "The Tiger rendering library is needed to render complex Kate streams, " \
266 "but VLC can still render static text and image based subtitles if " \
267 "it is not available.\n" \
268 "Note that changing settings below will not take effect until a new stream is played. " \
269 "This will hopefully be fixed soon." \
272 vlc_module_begin ()
273 set_shortname( N_("Kate"))
274 set_description( N_("Kate overlay decoder") )
275 set_help( HELP_TEXT )
276 set_capability( "decoder", 50 )
277 set_callbacks( OpenDecoder, CloseDecoder )
278 set_category( CAT_INPUT )
279 set_subcategory( SUBCAT_INPUT_SCODEC )
280 add_shortcut( "kate" )
282 add_bool( "kate-formatted", true, NULL, FORMAT_TEXT, FORMAT_LONGTEXT,
283 true );
285 #ifdef HAVE_TIGER
286 add_bool( "kate-use-tiger", true, NULL, TIGER_TEXT, TIGER_LONGTEXT,
287 true );
288 add_float_with_range( "kate-tiger-quality",
289 TIGER_QUALITY_DEFAULT, 0.0f, 1.0f, TigerConfigurationCallback,
290 TIGER_QUALITY_TEXT, TIGER_QUALITY_LONGTEXT,
291 true );
293 set_section( N_("Tiger rendering defaults"), NULL );
294 add_string( "kate-tiger-default-font-desc",
295 TIGER_DEFAULT_FONT_DESC_DEFAULT, TigerConfigurationCallback,
296 TIGER_DEFAULT_FONT_DESC_TEXT, TIGER_DEFAULT_FONT_DESC_LONGTEXT, true);
297 add_integer_with_range( "kate-tiger-default-font-effect",
298 TIGER_DEFAULT_FONT_EFFECT_DEFAULT,
299 0, sizeof(pi_font_effects)/sizeof(pi_font_effects[0])-1, TigerConfigurationCallback,
300 TIGER_DEFAULT_FONT_EFFECT_TEXT, TIGER_DEFAULT_FONT_EFFECT_LONGTEXT,
301 true );
302 change_integer_list( pi_font_effects, ppsz_font_effect_names, NULL );
303 add_float_with_range( "kate-tiger-default-font-effect-strength",
304 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT, 0.0f, 1.0f, TigerConfigurationCallback,
305 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT, TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT,
306 true );
307 add_integer_with_range( "kate-tiger-default-font-color",
308 TIGER_DEFAULT_FONT_COLOR_DEFAULT, 0, 0x00ffffff, TigerConfigurationCallback,
309 TIGER_DEFAULT_FONT_COLOR_TEXT, TIGER_DEFAULT_FONT_COLOR_LONGTEXT,
310 true);
311 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
312 add_integer_with_range( "kate-tiger-default-font-alpha",
313 TIGER_DEFAULT_FONT_ALPHA_DEFAULT, 0, 255, TigerConfigurationCallback,
314 TIGER_DEFAULT_FONT_ALPHA_TEXT, TIGER_DEFAULT_FONT_ALPHA_LONGTEXT,
315 true);
316 add_integer_with_range( "kate-tiger-default-background-color",
317 TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT, 0, 0x00ffffff, TigerConfigurationCallback,
318 TIGER_DEFAULT_BACKGROUND_COLOR_TEXT, TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT,
319 true);
320 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL );
321 add_integer_with_range( "kate-tiger-default-background-alpha",
322 TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT, 0, 255, TigerConfigurationCallback,
323 TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT, TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT,
324 true);
325 #endif
327 #ifdef ENABLE_PACKETIZER
328 add_submodule ()
329 set_description( N_("Kate text subtitles packetizer") )
330 set_capability( "packetizer", 100 )
331 set_callbacks( OpenPacketizer, CloseDecoder )
332 add_shortcut( "kate" )
333 #endif
335 vlc_module_end ()
337 /*****************************************************************************
338 * OpenDecoder: probe the decoder and return score
339 *****************************************************************************
340 * Tries to launch a decoder and return score so that the interface is able
341 * to chose.
342 *****************************************************************************/
343 static int OpenDecoder( vlc_object_t *p_this )
345 decoder_t *p_dec = (decoder_t*)p_this;
346 decoder_sys_t *p_sys;
347 int i_ret;
349 msg_Dbg( p_dec, "kate: OpenDecoder");
351 if( p_dec->fmt_in.i_codec != VLC_FOURCC('k','a','t','e') )
353 return VLC_EGENERIC;
356 /* Set callbacks */
357 p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
358 DecodeBlock;
359 p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **))
360 DecodeBlock;
362 /* Allocate the memory needed to store the decoder's structure */
363 if( ( p_dec->p_sys = p_sys =
364 (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
365 return VLC_ENOMEM;
367 vlc_mutex_init( &p_sys->lock );
368 p_sys->i_refcount = 0;
369 DecSysHold( p_sys );
371 /* init of p_sys */
372 #ifdef ENABLE_PACKETIZER
373 p_sys->b_packetizer = false;
374 #endif
375 p_sys->b_ready = false;
376 p_sys->i_pts = 0;
378 kate_comment_init( &p_sys->kc );
379 kate_info_init( &p_sys->ki );
381 p_sys->i_num_headers = 0;
382 p_sys->i_headers = 0;
384 /* retrieve options */
385 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
387 vlc_mutex_lock( &kate_decoder_list_mutex );
389 #ifdef HAVE_TIGER
391 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
393 p_sys->p_tr = NULL;
394 p_sys->last_render_ts = 0;
396 /* get initial value of configuration */
397 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
398 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
399 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
400 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
401 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
402 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
404 if( p_sys->b_use_tiger )
406 i_ret = tiger_renderer_create( &p_sys->p_tr );
407 if( i_ret < 0 )
409 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
410 p_sys->p_tr = NULL;
411 p_sys->b_use_tiger = false;
414 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
416 UpdateTigerFontEffect( p_dec );
417 UpdateTigerFontColor( p_dec );
418 UpdateTigerBackgroundColor( p_dec );
419 UpdateTigerQuality( p_dec );
420 UpdateTigerFontDesc( p_dec );
423 #else
425 p_sys->b_use_tiger = false;
427 #endif
429 /* add the decoder to the global list */
430 decoder_t **list = ( decoder_t** ) realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( decoder_t* ));
431 if( list )
433 list[ kate_decoder_list_size++ ] = p_dec;
434 kate_decoder_list = list;
437 vlc_mutex_unlock( &kate_decoder_list_mutex );
439 return VLC_SUCCESS;
442 #ifdef ENABLE_PACKETIZER
443 static int OpenPacketizer( vlc_object_t *p_this )
445 decoder_t *p_dec = (decoder_t*)p_this;
447 int i_ret = OpenDecoder( p_this );
449 if( i_ret == VLC_SUCCESS )
451 p_dec->p_sys->b_packetizer = true;
452 p_dec->fmt_out.i_codec = VLC_FOURCC( 'k', 'a', 't', 'e' );
455 return i_ret;
457 #endif
459 /****************************************************************************
460 * DecodeBlock: the whole thing
461 ****************************************************************************
462 * This function must be fed with kate packets.
463 ****************************************************************************/
464 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
466 decoder_sys_t *p_sys = p_dec->p_sys;
467 block_t *p_block;
468 kate_packet kp;
470 if( !pp_block || !*pp_block )
471 return NULL;
473 p_block = *pp_block;
475 if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) )
477 block_Release( p_block );
478 return NULL;
481 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY) )
483 #ifdef HAVE_TIGER
484 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
485 vlc_mutex_lock( &p_sys->lock );
486 tiger_renderer_seek( p_sys->p_tr, 0 );
487 vlc_mutex_unlock( &p_sys->lock );
488 #endif
489 block_Release( p_block );
490 return NULL;
493 /* Block to Kate packet */
494 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
496 if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
498 /* Headers already available as extra data */
499 p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
500 p_sys->i_headers = p_sys->i_num_headers;
502 else if( kp.nbytes && (p_sys->i_headers==0 || p_sys->i_headers < p_sys->ki.num_headers ))
504 /* Backup headers as extra data */
505 uint8_t *p_extra;
507 p_dec->fmt_in.p_extra =
508 realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra + kp.nbytes + 2 );
509 p_extra = (void*)(((unsigned char*)p_dec->fmt_in.p_extra) + p_dec->fmt_in.i_extra);
510 *(p_extra++) = kp.nbytes >> 8;
511 *(p_extra++) = kp.nbytes & 0xFF;
513 memcpy( p_extra, kp.data, kp.nbytes );
514 p_dec->fmt_in.i_extra += kp.nbytes + 2;
516 block_Release( *pp_block );
517 p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
518 p_sys->i_headers++;
519 return NULL;
522 if( p_sys->i_headers == p_sys->i_num_headers && p_sys->i_num_headers>0 )
524 if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
526 p_sys->i_headers = 0;
527 p_dec->fmt_in.i_extra = 0;
528 block_Release( *pp_block );
529 return NULL;
531 else p_sys->i_headers++;
534 return ProcessPacket( p_dec, &kp, pp_block );
537 /*****************************************************************************
538 * ProcessHeaders: process Kate headers.
539 *****************************************************************************/
540 static int ProcessHeaders( decoder_t *p_dec )
542 decoder_sys_t *p_sys = p_dec->p_sys;
543 kate_packet kp;
544 uint8_t *p_extra;
545 int i_extra;
546 int i_headeridx;
547 int i_ret;
549 if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
551 p_extra = p_dec->fmt_in.p_extra;
552 i_extra = p_dec->fmt_in.i_extra;
554 /* skip number of headers */
555 ++p_extra;
556 --i_extra;
558 /* Take care of the initial Kate header */
559 kp.nbytes = *(p_extra++) << 8;
560 kp.nbytes |= (*(p_extra++) & 0xFF);
561 kp.data = p_extra;
562 p_extra += kp.nbytes;
563 i_extra -= (kp.nbytes + 2);
564 if( i_extra < 0 )
566 msg_Err( p_dec, "header data corrupted");
567 return VLC_EGENERIC;
570 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
571 if( i_ret < 0 )
573 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
574 return VLC_EGENERIC;
577 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
578 p_sys->ki.language, p_sys->ki.category,
579 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
580 p_sys->ki.granule_shift);
582 /* parse all remaining header packets */
583 for( i_headeridx = 1; i_headeridx < p_sys->ki.num_headers; ++i_headeridx )
585 kp.nbytes = *(p_extra++) << 8;
586 kp.nbytes |= (*(p_extra++) & 0xFF);
587 kp.data = p_extra;
588 p_extra += kp.nbytes;
589 i_extra -= (kp.nbytes + 2);
590 if( i_extra < 0 )
592 msg_Err( p_dec, "header %d data corrupted", i_headeridx );
593 return VLC_EGENERIC;
596 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
597 if( i_ret < 0 )
599 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
600 return VLC_EGENERIC;
603 /* header 1 is comments */
604 if( i_headeridx == 1 )
606 ParseKateComments( p_dec );
610 #ifdef ENABLE_PACKETIZER
611 if( !p_sys->b_packetizer )
612 #endif
614 /* We have all the headers, initialize decoder */
615 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
616 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
617 if (i_ret < 0)
619 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
620 return VLC_EGENERIC;
622 p_sys->b_ready = true;
624 #ifdef ENABLE_PACKETIZER
625 else
627 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
628 p_dec->fmt_out.p_extra =
629 realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
630 memcpy( p_dec->fmt_out.p_extra,
631 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
633 #endif
635 return VLC_SUCCESS;
638 /*****************************************************************************
639 * ProcessPacket: processes a kate packet.
640 *****************************************************************************/
641 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
642 block_t **pp_block )
644 decoder_sys_t *p_sys = p_dec->p_sys;
645 block_t *p_block = *pp_block;
646 subpicture_t *p_buf = NULL;
648 /* Date management */
649 if( p_block->i_pts > 0 && p_block->i_pts != p_sys->i_pts )
651 p_sys->i_pts = p_block->i_pts;
654 *pp_block = NULL; /* To avoid being fed the same packet again */
656 #ifdef ENABLE_PACKETIZER
657 if( p_sys->b_packetizer )
659 /* Date management */
660 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
662 if( p_sys->i_headers >= p_sys->i_num_headers )
663 p_block->i_length = p_sys->i_pts - p_block->i_pts;
664 else
665 p_block->i_length = 0;
667 p_buf = p_block;
669 else
670 #endif
672 if( p_sys->i_headers >= p_sys->i_num_headers && p_sys->i_num_headers > 0)
673 p_buf = DecodePacket( p_dec, p_kp, p_block );
674 else
675 p_buf = NULL;
677 if( p_block ) block_Release( p_block );
680 return p_buf;
683 /* nicked off blend.c */
684 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
685 int r, int g, int b )
687 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
688 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
689 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
693 This retrieves the size of the video.
694 The best case is when the original video size is known, as we can then
695 scale images to match. In this case, since VLC autoscales, we want to
696 return the original size and let VLC scale everything.
697 if the original size is not known, then VLC can't resize, so we return
698 the size of the incoming video. If sizes in the Kate stream are in
699 relative units, it works fine. If they are absolute, you get what you
700 ask for. Images aren't rescaled.
702 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
704 /* searching for vout to get its size is frowned upon, so we don't and
705 use a default size if the original canvas size is not specified. */
706 #if 1
707 decoder_sys_t *p_sys = p_dec->p_sys;
708 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
710 *w = p_sys->ki.original_canvas_width;
711 *h = p_sys->ki.original_canvas_height;
712 msg_Dbg( p_dec, "original canvas %zu %zu\n",
713 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
715 else
717 /* nothing, leave defaults */
718 msg_Dbg( p_dec, "original canvas size unknown\n");
720 #else
721 /* keep this just in case it might be allowed one day ;) */
722 vout_thread_t *p_vout;
723 p_vout = vlc_object_find( (vlc_object_t*)p_dec, VLC_OBJECT_VOUT, FIND_CHILD );
724 if( p_vout )
726 decoder_sys_t *p_sys = p_dec->p_sys;
727 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
729 *w = p_sys->ki.original_canvas_width;
730 *h = p_sys->ki.original_canvas_height;
732 else
734 *w = p_vout->fmt_in.i_width;
735 *h = p_vout->fmt_in.i_height;
737 msg_Dbg( p_dec, "video: in %d %d, out %d %d, original canvas %zu %zu\n",
738 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
739 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
740 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
741 vlc_object_release( p_vout );
743 #endif
746 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
748 size_t y;
750 for( y=0; y<bitmap->height; ++y )
752 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
753 const uint8_t *src = bitmap->pixels+y*bitmap->width;
754 memcpy( dest, src, bitmap->width );
758 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
760 size_t n;
762 fmt_palette->i_entries = palette->ncolors;
763 for( n=0; n<palette->ncolors; ++n )
765 rgb_to_yuv(
766 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
767 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
769 fmt_palette->palette[n][3] = palette->colors[n].a;
773 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
775 decoder_sys_t *p_sys = p_dec->p_sys;
777 if( ev->text_encoding != kate_utf8 )
779 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
780 return;
783 switch( ev->text_markup_type )
785 case kate_markup_none:
786 p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
787 break;
788 case kate_markup_simple:
789 if( p_sys->b_formatted )
791 /* the HTML renderer expects a top level text tag pair */
792 char *buffer = NULL;
793 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
795 p_spu->p_region->psz_html = buffer;
797 break;
799 /* if not formatted, we fall through */
800 default:
801 /* we don't know about this one, so remove markup and display as text */
803 char *copy = strdup( ev->text );
804 size_t len0 = strlen( copy ) + 1;
805 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
806 p_spu->p_region->psz_text = copy;
808 break;
812 #ifdef HAVE_TIGER
814 static void TigerDestroySubpicture( subpicture_t *p_subpic )
816 DecSysRelease( p_subpic->p_sys->p_dec_sys );
819 static void SubpictureReleaseRegions( subpicture_t *p_subpic )
821 if( p_subpic->p_region)
823 subpicture_region_ChainDelete( p_subpic->p_region );
824 p_subpic->p_region = NULL;
828 static void TigerPreRender( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt )
830 decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys;
832 VLC_UNUSED( p_spu );
833 VLC_UNUSED( p_fmt );
835 p_sys->p_spu_final = p_subpic;
839 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
840 * alpha to avoid double multiply (and thus thinner text than we should)).
841 * Best would be to have VLC be able to handle premultiplied alpha, as it
842 * would be faster to blend as well.
844 * Also, we flip color components around for big endian machines, as Tiger
845 * outputs ARGB or ABGR (the one we selected here) in host endianness.
847 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
849 PROFILE_START( tiger_renderer_postprocess );
850 int y;
851 for( y=0; y<p_plane->i_lines; ++y )
853 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
854 unsigned int x;
855 for( x=0; x<i_width; ++x )
857 uint8_t *p_pixel = p_line+x*4;
858 #ifdef WORDS_BIGENDIAN
859 uint8_t a = p_pixel[0];
860 #else
861 uint8_t a = p_pixel[3];
862 #endif
863 if( a )
865 #ifdef WORDS_BIGENDIAN
866 uint8_t tmp = pixel[2];
867 p_pixel[0] = p_pixel[3] * 255 / a;
868 p_pixel[3] = a;
869 p_pixel[2] = p_pixel[1] * 255 / a;
870 p_pixel[1] = tmp * 255 / a;
871 #else
872 p_pixel[0] = p_pixel[0] * 255 / a;
873 p_pixel[1] = p_pixel[1] * 255 / a;
874 p_pixel[2] = p_pixel[2] * 255 / a;
875 #endif
877 else
879 p_pixel[0] = 0;
880 p_pixel[1] = 0;
881 p_pixel[2] = 0;
882 p_pixel[3] = 0;
886 PROFILE_STOP( tiger_renderer_postprocess );
889 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
890 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
891 Looks good with white though since it's all luma. Hopefully that will be the
892 common case. */
893 static void TigerUpdateRegions( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt, mtime_t ts )
895 decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys;
896 subpicture_region_t *p_r;
897 video_format_t fmt;
898 plane_t *p_plane;
899 kate_float t;
900 int i_ret;
902 VLC_UNUSED( p_spu );
904 PROFILE_START( TigerUpdateRegions );
906 /* do not render more than once per frame, libtiger renders all events at once */
907 if (ts <= p_sys->last_render_ts)
909 SubpictureReleaseRegions( p_subpic );
910 return;
913 /* remember what frame we've rendered already */
914 p_sys->last_render_ts = ts;
916 if( p_subpic != p_sys->p_spu_final )
918 SubpictureReleaseRegions( p_subpic );
919 return;
922 /* time in seconds from the start of the stream */
923 t = (p_subpic->p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
925 /* it is likely that the current region (if any) can be kept as is; test for this */
926 vlc_mutex_lock( &p_sys->lock );
927 if( p_subpic->p_region && !p_sys->b_dirty && !tiger_renderer_is_dirty( p_sys->p_tr ))
929 PROFILE_START( tiger_renderer_update1 );
930 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
931 PROFILE_STOP( tiger_renderer_update1 );
932 if( i_ret < 0 )
934 SubpictureReleaseRegions( p_subpic );
935 vlc_mutex_unlock( &p_sys->lock );
936 return;
939 if( !tiger_renderer_is_dirty( p_sys->p_tr ) )
941 /* we can keep the current region list */
942 PROFILE_STOP( TigerUpdateRegions );
943 vlc_mutex_unlock( &p_sys->lock );
944 return;
947 vlc_mutex_unlock( &p_sys->lock );
949 /* we have to render again, reset current region list */
950 SubpictureReleaseRegions( p_subpic );
952 /* create a full frame region - this will also tell Tiger the size of the frame */
953 fmt = *p_fmt;
954 fmt.i_chroma = VLC_FOURCC('R','G','B','A');
955 fmt.i_width = fmt.i_visible_width;
956 fmt.i_height = fmt.i_visible_height;
957 fmt.i_bits_per_pixel = 0;
958 fmt.i_x_offset = fmt.i_y_offset = 0;
960 p_r = subpicture_region_New( &fmt );
961 if( !p_r )
963 return;
966 p_r->i_x = 0;
967 p_r->i_y = 0;
968 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
970 vlc_mutex_lock( &p_sys->lock );
972 p_plane = &p_r->p_picture->p[0];
973 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 );
974 if( i_ret < 0 )
976 goto failure;
979 PROFILE_START( tiger_renderer_update );
980 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
981 if( i_ret < 0 )
983 goto failure;
985 PROFILE_STOP( tiger_renderer_update );
987 PROFILE_START( tiger_renderer_render );
988 i_ret = tiger_renderer_render( p_sys->p_tr );
989 if( i_ret < 0 )
991 goto failure;
993 PROFILE_STOP( tiger_renderer_render );
995 PostprocessTigerImage( p_plane, fmt.i_width );
996 p_subpic->p_region = p_r;
997 p_sys->b_dirty = false;
999 PROFILE_STOP( TigerUpdateRegions );
1001 vlc_mutex_unlock( &p_sys->lock );
1003 return;
1005 failure:
1006 vlc_mutex_unlock( &p_sys->lock );
1007 subpicture_region_ChainDelete( p_r );
1010 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
1012 char *psz_tmp;
1013 uint32_t i_color = 0;
1015 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
1017 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
1018 var_Destroy( p_dec, psz_tmp );
1019 free( psz_tmp );
1020 i_color |= i_rgb;
1023 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
1025 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
1026 var_Destroy( p_dec, psz_tmp );
1027 free( psz_tmp );
1028 i_color |= (i_alpha << 24);
1031 return i_color;
1034 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
1036 char *psz_value = var_CreateGetString( p_dec, psz_name );
1037 if( psz_value)
1039 psz_value = strdup( psz_value );
1041 var_Destroy( p_dec, psz_name );
1042 return psz_value;
1045 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
1047 int i_value = var_CreateGetInteger( p_dec, psz_name );
1048 var_Destroy( p_dec, psz_name );
1049 return i_value;
1052 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
1054 double f_value = var_CreateGetFloat( p_dec, psz_name );
1055 var_Destroy( p_dec, psz_name );
1056 return f_value;
1059 static void UpdateTigerQuality( decoder_t *p_dec )
1061 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1062 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
1063 p_sys->b_dirty = true;
1066 static void UpdateTigerFontDesc( decoder_t *p_dec )
1068 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1069 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
1070 p_sys->b_dirty = true;
1073 static void UpdateTigerFontColor( decoder_t *p_dec )
1075 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1076 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
1077 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
1078 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
1079 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
1080 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1081 p_sys->b_dirty = true;
1084 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
1086 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1087 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
1088 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1089 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1090 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1091 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1092 p_sys->b_dirty = true;
1095 static void UpdateTigerFontEffect( decoder_t *p_dec )
1097 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1098 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1099 p_sys->e_tiger_default_font_effect,
1100 p_sys->f_tiger_default_font_effect_strength ) );
1101 p_sys->b_dirty = true;
1104 static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
1105 vlc_value_t oldval, vlc_value_t newval )
1107 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1109 VLC_UNUSED( oldval );
1111 vlc_mutex_lock( &p_sys->lock );
1113 msg_Dbg( p_dec, "OnConfigurationChanged: %s\n", psz_var );
1115 if( !p_sys->b_use_tiger || !p_sys->p_tr )
1117 vlc_mutex_unlock( &p_sys->lock );
1118 return VLC_SUCCESS;
1121 #define TEST_TIGER_VAR( name ) \
1122 if( !strcmp( name, psz_var ) )
1124 TEST_TIGER_VAR( "kate-tiger-quality" )
1126 p_sys->f_tiger_quality = newval.f_float;
1127 UpdateTigerQuality( p_dec );
1130 TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
1132 if( p_sys->psz_tiger_default_font_desc )
1134 free( p_sys->psz_tiger_default_font_desc );
1135 p_sys->psz_tiger_default_font_desc = NULL;
1137 if( newval.psz_string )
1139 p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
1141 UpdateTigerFontDesc( p_dec );
1144 TEST_TIGER_VAR( "kate-tiger-default-font-color" )
1146 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
1147 UpdateTigerFontColor( p_dec );
1150 TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
1152 p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
1153 UpdateTigerFontColor( p_dec );
1156 TEST_TIGER_VAR( "kate-tiger-default-background-color" )
1158 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
1159 UpdateTigerBackgroundColor( p_dec );
1162 TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
1164 p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
1165 UpdateTigerBackgroundColor( p_dec );
1168 TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
1170 p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
1171 UpdateTigerFontEffect( p_dec );
1174 TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
1176 p_sys->f_tiger_default_font_effect_strength = newval.f_float;
1177 UpdateTigerFontEffect( p_dec );
1180 #undef TEST_TIGER_VAR
1182 vlc_mutex_unlock( &p_sys->lock );
1184 return VLC_SUCCESS;
1187 static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
1188 vlc_value_t oldval, vlc_value_t newval,
1189 void *p_data )
1191 size_t i_idx;
1193 VLC_UNUSED( p_this );
1194 VLC_UNUSED( oldval );
1195 VLC_UNUSED( newval );
1196 VLC_UNUSED( p_data );
1198 vlc_mutex_lock( &kate_decoder_list_mutex );
1200 /* Update all existing decoders from the global user prefs */
1201 for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
1203 decoder_t *p_dec = kate_decoder_list[ i_idx ];
1204 OnConfigurationChanged( p_dec, psz_var, oldval, newval );
1207 vlc_mutex_unlock( &kate_decoder_list_mutex );
1209 return VLC_SUCCESS;
1212 #endif
1214 /*****************************************************************************
1215 * DecodePacket: decodes a Kate packet.
1216 *****************************************************************************/
1217 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1219 decoder_sys_t *p_sys = p_dec->p_sys;
1220 const kate_event *ev = NULL;
1221 subpicture_t *p_spu = NULL;
1222 int i_ret;
1224 if( !p_sys->b_ready )
1226 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1227 return NULL;
1230 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1231 if( i_ret < 0 )
1233 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1234 return NULL;
1237 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1238 if( i_ret < 0 )
1240 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1241 return NULL;
1243 if( i_ret > 0 )
1245 /* no event to go with this packet, this is normal */
1246 return NULL;
1249 /* we have an event */
1251 /* Get a new spu */
1252 p_spu = decoder_NewSubpicture( p_dec );
1253 if( !p_spu )
1255 /* this will happen for lyrics as there is no vout - so no error */
1256 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1257 return NULL;
1260 p_spu->i_start = p_block->i_pts;
1261 p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
1262 p_spu->b_ephemer = false;
1263 p_spu->b_absolute = false;
1265 #ifdef HAVE_TIGER
1266 if( p_sys->b_use_tiger)
1268 /* setup the structure to get our decoder struct back */
1269 p_spu->p_sys = malloc( sizeof( subpicture_sys_t ));
1270 if( !p_spu->p_sys )
1272 decoder_DeleteSubpicture( p_dec, p_spu );
1273 return NULL;
1275 p_spu->p_sys->p_dec_sys = p_sys;
1276 p_spu->p_sys->i_start = p_block->i_pts;
1277 DecSysHold( p_sys );
1279 p_spu->b_absolute = true;
1281 /* add the event to tiger */
1282 vlc_mutex_lock( &p_sys->lock );
1283 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1284 vlc_mutex_unlock( &p_sys->lock );
1286 /* hookup render/update routines */
1287 p_spu->pf_pre_render = TigerPreRender;
1288 p_spu->pf_update_regions = TigerUpdateRegions;
1289 p_spu->pf_destroy = TigerDestroySubpicture;
1291 else
1292 #endif
1294 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1297 return p_spu;
1300 /*****************************************************************************
1301 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1302 *****************************************************************************/
1303 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1304 const kate_event *ev )
1306 decoder_sys_t *p_sys = p_dec->p_sys;
1307 video_format_t fmt;
1308 subpicture_region_t *p_bitmap_region = NULL;
1309 video_palette_t palette;
1310 kate_tracker kin;
1311 bool b_tracker_valid = false;
1312 int i_ret;
1314 /* these may be 0 for "not specified" */
1315 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1316 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1318 /* Create a new subpicture region */
1319 memset( &fmt, 0, sizeof(video_format_t) );
1321 if (p_sys->b_formatted)
1323 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1324 if( i_ret < 0)
1326 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1328 else
1330 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1331 GetVideoSize(p_dec, &w, &h);
1332 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1333 if( i_ret < 0)
1335 kate_tracker_clear(&kin);
1336 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1338 else
1340 // TODO: parse tracker and set style, init fmt
1341 b_tracker_valid = true;
1346 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1348 /* create a separate region for the bitmap */
1349 memset( &fmt, 0, sizeof(video_format_t) );
1350 fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
1351 fmt.i_aspect = 0;
1352 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1353 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1354 fmt.i_x_offset = fmt.i_y_offset = 0;
1355 fmt.p_palette = &palette;
1356 CreateKatePalette( fmt.p_palette, ev->palette );
1358 p_bitmap_region = subpicture_region_New( &fmt );
1359 if( !p_bitmap_region )
1361 msg_Err( p_dec, "cannot allocate SPU region" );
1362 decoder_DeleteSubpicture( p_dec, p_spu );
1363 return NULL;
1366 /* create the bitmap */
1367 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1369 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors\n", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1372 /* text region */
1373 fmt.i_chroma = VLC_FOURCC('T','E','X','T');
1374 fmt.i_aspect = 0;
1375 fmt.i_width = fmt.i_height = 0;
1376 fmt.i_x_offset = fmt.i_y_offset = 0;
1377 p_spu->p_region = subpicture_region_New( &fmt );
1378 if( !p_spu->p_region )
1380 msg_Err( p_dec, "cannot allocate SPU region" );
1381 decoder_DeleteSubpicture( p_dec, p_spu );
1382 return NULL;
1385 SetupText( p_dec, p_spu, ev );
1387 /* default positioning */
1388 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1389 if (p_bitmap_region)
1391 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1393 p_spu->p_region->i_x = 0;
1394 p_spu->p_region->i_y = 10;
1396 /* override if tracker info present */
1397 if (b_tracker_valid)
1399 if (kin.has.region)
1401 p_spu->p_region->i_x = kin.region_x;
1402 p_spu->p_region->i_y = kin.region_y;
1403 if (p_bitmap_region)
1405 p_bitmap_region->i_x = kin.region_x;
1406 p_bitmap_region->i_y = kin.region_y;
1408 p_spu->b_absolute = true;
1411 kate_tracker_clear(&kin);
1414 /* if we have a bitmap, chain it before the text */
1415 if (p_bitmap_region)
1417 p_bitmap_region->p_next = p_spu->p_region;
1418 p_spu->p_region = p_bitmap_region;
1421 return p_spu;
1424 /*****************************************************************************
1425 * ParseKateComments:
1426 *****************************************************************************/
1427 static void ParseKateComments( decoder_t *p_dec )
1429 char *psz_name, *psz_value, *psz_comment;
1430 int i = 0;
1432 while ( i < p_dec->p_sys->kc.comments )
1434 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1435 if( !psz_comment )
1436 break;
1437 psz_name = psz_comment;
1438 psz_value = strchr( psz_comment, '=' );
1439 if( psz_value )
1441 *psz_value = '\0';
1442 psz_value++;
1444 if( !p_dec->p_description )
1445 p_dec->p_description = vlc_meta_New();
1446 if( p_dec->p_description )
1447 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1449 free( psz_comment );
1450 i++;
1454 /*****************************************************************************
1455 * CloseDecoder: clean up the decoder
1456 *****************************************************************************/
1457 static void CloseDecoder( vlc_object_t *p_this )
1459 decoder_t *p_dec = (decoder_t *)p_this;
1460 size_t i_index;
1462 /* remove the decoder from the global list */
1463 vlc_mutex_lock( &kate_decoder_list_mutex );
1464 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1466 if( kate_decoder_list[ i_index ] == p_dec )
1468 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1469 break;
1472 vlc_mutex_unlock( &kate_decoder_list_mutex );
1474 msg_Dbg( p_dec, "Closing Kate decoder" );
1475 DecSysRelease( p_dec->p_sys );
1478 static void DecSysHold( decoder_sys_t *p_sys )
1480 vlc_mutex_lock( &p_sys->lock );
1481 p_sys->i_refcount++;
1482 vlc_mutex_unlock( &p_sys->lock );
1485 static void DecSysRelease( decoder_sys_t *p_sys )
1487 vlc_mutex_lock( &p_sys->lock );
1488 p_sys->i_refcount--;
1489 if( p_sys->i_refcount > 0)
1491 vlc_mutex_unlock( &p_sys->lock );
1492 return;
1495 vlc_mutex_unlock( &p_sys->lock );
1496 vlc_mutex_destroy( &p_sys->lock );
1498 #ifdef HAVE_TIGER
1499 if( p_sys->p_tr )
1500 tiger_renderer_destroy( p_sys->p_tr );
1501 if( p_sys->psz_tiger_default_font_desc )
1502 free( p_sys->psz_tiger_default_font_desc );
1503 #endif
1505 if (p_sys->b_ready)
1506 kate_clear( &p_sys->k );
1507 kate_info_clear( &p_sys->ki );
1508 kate_comment_clear( &p_sys->kc );
1510 free( p_sys );