1 /*****************************************************************************
2 * kate.c : a decoder for the kate bitstream format
3 *****************************************************************************
4 * Copyright (C) 2000-2008 VLC authors and VideoLAN
5 * $Id: cbcb0090c44de7bf44125f22b1bf75a763ee2134 $
6 *
7 * Authors: Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
8 *
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.
13 *
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.
18 *
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 *****************************************************************************/
23
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
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"
36
37 #include <kate/kate.h>
38 #ifdef HAVE_TIGER
39 # include <tiger/tiger.h>
40 #endif
41
42 /* #define ENABLE_PACKETIZER */
43 /* #define ENABLE_PROFILE */
44
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
52
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 )
62
63 /*****************************************************************************
64 * decoder_sys_t : decoder descriptor
65 *****************************************************************************/
66 struct decoder_sys_t
67 {
68 #ifdef ENABLE_PACKETIZER
69 /* Module mode */
70 bool b_packetizer;
71 #endif
72
73 /*
74 * Input properties
75 */
76 bool b_has_headers;
77
78 /*
79 * Kate properties
80 */
81 bool b_ready;
82 kate_info ki;
83 kate_comment kc;
84 kate_state k;
85
86 /*
87 * Common properties
88 */
89 mtime_t i_pts;
90 mtime_t i_max_stop;
91
92 /* decoder_sys_t is shared between decoder and spu units */
93 vlc_mutex_t lock;
94 int i_refcount;
95
96 #ifdef HAVE_TIGER
97 /*
98 * Tiger properties
99 */
100 tiger_renderer *p_tr;
101 bool b_dirty;
102
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
110
111 /*
112 * Options
113 */
114 bool b_formatted;
115 bool b_use_tiger;
116 };
117
118 struct subpicture_updater_sys_t
119 {
120 decoder_sys_t *p_dec_sys;
121 mtime_t i_start;
122 };
123
124
125 /*
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.
145 */
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;
149
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
158
159 static int DecodeSub( decoder_t *p_dec, block_t *p_block );
160 static block_t * Packetize( decoder_t *p_dec, block_t **pp_block );
161 static void Flush( decoder_t * );
162 static int ProcessHeaders( decoder_t *p_dec );
163 static void *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
164 block_t *p_block );
165 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp,
166 block_t *p_block );
167 static void ParseKateComments( decoder_t * );
168 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
169 const kate_event *ev );
170 static void DecSysRelease( decoder_sys_t *p_sys );
171 static void DecSysHold( decoder_sys_t *p_sys );
172 #ifdef HAVE_TIGER
173 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix );
174 static char *GetTigerString( decoder_t *p_dec, const char *psz_name );
175 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name );
176 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name );
177 static void UpdateTigerFontColor( decoder_t *p_dec );
178 static void UpdateTigerBackgroundColor( decoder_t *p_dec );
179 static void UpdateTigerFontEffect( decoder_t *p_dec );
180 static void UpdateTigerQuality( decoder_t *p_dec );
181 static void UpdateTigerFontDesc( decoder_t *p_dec );
182 #endif
183
184 #define DEFAULT_NAME "Default"
185 #define MAX_LINE 8192
186
187 /*****************************************************************************
188 * Module descriptor.
189 *****************************************************************************/
190
191 #define FORMAT_TEXT N_("Formatted Subtitles")
192 #define FORMAT_LONGTEXT N_("Kate streams allow for text formatting. " \
193 "VLC partly implements this, but you can choose to disable all formatting. " \
194 "Note that this has no effect is rendering via Tiger is enabled.")
195
196 #ifdef HAVE_TIGER
197
198 static const tiger_font_effect pi_font_effects[] = { tiger_font_plain, tiger_font_shadow, tiger_font_outline };
199 static const char * const ppsz_font_effect_names[] = { N_("None"), N_("Shadow"), N_("Outline") };
200
201 /* nicked off freetype.c */
202 static const int pi_color_values[] = {
203 0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000,
204 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080,
205 0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF };
206 static const char *const ppsz_color_descriptions[] = {
207 N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"),
208 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"),
209 N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") };
210
211 #define TIGER_TEXT N_("Use Tiger for rendering")
212 #define TIGER_LONGTEXT N_("Kate streams can be rendered using the Tiger library. " \
213 "Disabling this will only render static text and bitmap based streams.")
214
215 #define TIGER_QUALITY_DEFAULT 1.0
216 #define TIGER_QUALITY_TEXT N_("Rendering quality")
217 #define TIGER_QUALITY_LONGTEXT N_("Select rendering quality, at the expense of speed. " \
218 "0 is fastest, 1 is highest quality.")
219
220 #define TIGER_DEFAULT_FONT_EFFECT_DEFAULT 0
221 #define TIGER_DEFAULT_FONT_EFFECT_TEXT N_("Default font effect")
222 #define TIGER_DEFAULT_FONT_EFFECT_LONGTEXT N_("Add a font effect to text to improve readability " \
223 "against different backgrounds.")
224
225 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT 0.5
226 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT N_("Default font effect strength")
227 #define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT N_("How pronounced to make the chosen font effect " \
228 "(effect dependent).")
229
230 #define TIGER_DEFAULT_FONT_DESC_DEFAULT ""
231 #define TIGER_DEFAULT_FONT_DESC_TEXT N_("Default font description")
232 #define TIGER_DEFAULT_FONT_DESC_LONGTEXT N_("Which font description to use if the Kate stream " \
233 "does not specify particular font parameters (name, size, etc) to use. " \
234 "A blank name will let Tiger choose font parameters where appropriate.")
235
236 #define TIGER_DEFAULT_FONT_COLOR_DEFAULT 0x00ffffff
237 #define TIGER_DEFAULT_FONT_COLOR_TEXT N_("Default font color")
238 #define TIGER_DEFAULT_FONT_COLOR_LONGTEXT N_("Default font color to use if the Kate stream " \
239 "does not specify a particular font color to use.")
240
241 #define TIGER_DEFAULT_FONT_ALPHA_DEFAULT 0xff
242 #define TIGER_DEFAULT_FONT_ALPHA_TEXT N_("Default font alpha")
243 #define TIGER_DEFAULT_FONT_ALPHA_LONGTEXT N_("Transparency of the default font color if the Kate stream " \
244 "does not specify a particular font color to use.")
245
246 #define TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT 0x00ffffff
247 #define TIGER_DEFAULT_BACKGROUND_COLOR_TEXT N_("Default background color")
248 #define TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT N_("Default background color if the Kate stream " \
249 "does not specify a background color to use.")
250
251 #define TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT 0
252 #define TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT N_("Default background alpha")
253 #define TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT N_("Transparency of the default background color if the Kate stream " \
254 "does not specify a particular background color to use.")
255
256 #endif
257
258 #define HELP_TEXT N_( \
259 "Kate is a codec for text and image based overlays.\n" \
260 "The Tiger rendering library is needed to render complex Kate streams, " \
261 "but VLC can still render static text and image based subtitles if " \
262 "it is not available.\n" \
263 "Note that changing settings below will not take effect until a new stream is played. " \
264 "This will hopefully be fixed soon." \
265 )
266
267 vlc_module_begin ()
268 set_shortname( N_("Kate"))
269 set_description( N_("Kate overlay decoder") )
270 set_help( HELP_TEXT )
271 set_capability( "spu decoder", 50 )
272 set_callbacks( OpenDecoder, CloseDecoder )
273 set_category( CAT_INPUT )
274 set_subcategory( SUBCAT_INPUT_SCODEC )
275 add_shortcut( "kate" )
276
277 add_bool( "kate-formatted", true, FORMAT_TEXT, FORMAT_LONGTEXT,
278 true )
279
280 #ifdef HAVE_TIGER
281 add_bool( "kate-use-tiger", true, TIGER_TEXT, TIGER_LONGTEXT,
282 true )
283 add_float_with_range( "kate-tiger-quality",
284 TIGER_QUALITY_DEFAULT, 0.0f, 1.0f,
285 TIGER_QUALITY_TEXT, TIGER_QUALITY_LONGTEXT,
286 true )
287
288 set_section( N_("Tiger rendering defaults"), NULL );
289 add_string( "kate-tiger-default-font-desc", TIGER_DEFAULT_FONT_DESC_DEFAULT,
290 TIGER_DEFAULT_FONT_DESC_TEXT, TIGER_DEFAULT_FONT_DESC_LONGTEXT, true);
291 add_integer_with_range( "kate-tiger-default-font-effect",
292 TIGER_DEFAULT_FONT_EFFECT_DEFAULT,
293 0, sizeof(pi_font_effects)/sizeof(pi_font_effects[0])-1,
294 TIGER_DEFAULT_FONT_EFFECT_TEXT, TIGER_DEFAULT_FONT_EFFECT_LONGTEXT,
295 true )
296 change_integer_list( pi_font_effects, ppsz_font_effect_names );
297 add_float_with_range( "kate-tiger-default-font-effect-strength",
298 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT, 0.0f, 1.0f,
299 TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT, TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT,
300 true )
301 add_integer_with_range( "kate-tiger-default-font-color",
302 TIGER_DEFAULT_FONT_COLOR_DEFAULT, 0, 0x00ffffff,
303 TIGER_DEFAULT_FONT_COLOR_TEXT, TIGER_DEFAULT_FONT_COLOR_LONGTEXT,
304 true);
305 change_integer_list( pi_color_values, ppsz_color_descriptions );
306 add_integer_with_range( "kate-tiger-default-font-alpha",
307 TIGER_DEFAULT_FONT_ALPHA_DEFAULT, 0, 255,
308 TIGER_DEFAULT_FONT_ALPHA_TEXT, TIGER_DEFAULT_FONT_ALPHA_LONGTEXT,
309 true);
310 add_integer_with_range( "kate-tiger-default-background-color",
311 TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT, 0, 0x00ffffff,
312 TIGER_DEFAULT_BACKGROUND_COLOR_TEXT, TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT,
313 true);
314 change_integer_list( pi_color_values, ppsz_color_descriptions );
315 add_integer_with_range( "kate-tiger-default-background-alpha",
316 TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT, 0, 255,
317 TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT, TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT,
318 true);
319 #endif
320
321 #ifdef ENABLE_PACKETIZER
322 add_submodule ()
323 set_description( N_("Kate text subtitles packetizer") )
324 set_capability( "packetizer", 100 )
set_callbacks(OpenPacketizer,CloseDecoder)325 set_callbacks( OpenPacketizer, CloseDecoder )
326 add_shortcut( "kate" )
327 #endif
328
329 vlc_module_end ()
330
331 /*****************************************************************************
332 * OpenDecoder: probe the decoder and return score
333 *****************************************************************************
334 * Tries to launch a decoder and return score so that the interface is able
335 * to chose.
336 *****************************************************************************/
337 static int OpenDecoder( vlc_object_t *p_this )
338 {
339 decoder_t *p_dec = (decoder_t*)p_this;
340 decoder_sys_t *p_sys;
341
342 if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
343 {
344 return VLC_EGENERIC;
345 }
346
347 msg_Dbg( p_dec, "kate: OpenDecoder");
348
349 /* Set callbacks */
350 p_dec->pf_decode = DecodeSub;
351 p_dec->pf_packetize = Packetize;
352 p_dec->pf_flush = Flush;
353
354 /* Allocate the memory needed to store the decoder's structure */
355 if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
356 return VLC_ENOMEM;
357
358 vlc_mutex_init( &p_sys->lock );
359 p_sys->i_refcount = 0;
360 DecSysHold( p_sys );
361
362 /* init of p_sys */
363 #ifdef ENABLE_PACKETIZER
364 p_sys->b_packetizer = false;
365 #endif
366 p_sys->b_ready = false;
367 p_sys->i_pts =
368 p_sys->i_max_stop = VLC_TS_INVALID;
369
370 kate_comment_init( &p_sys->kc );
371 kate_info_init( &p_sys->ki );
372
373 p_sys->b_has_headers = false;
374
375 /* retrieve options */
376 p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
377
378 vlc_mutex_lock( &kate_decoder_list_mutex );
379
380 #ifdef HAVE_TIGER
381
382 p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );
383
384 p_sys->p_tr = NULL;
385
386 /* get initial value of configuration */
387 p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
388 p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
389 p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
390 p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
391 p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
392 p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );
393
394 if( p_sys->b_use_tiger )
395 {
396 int i_ret = tiger_renderer_create( &p_sys->p_tr );
397 if( i_ret < 0 )
398 {
399 msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
400 p_sys->p_tr = NULL;
401 p_sys->b_use_tiger = false;
402 }
403 else {
404 CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );
405
406 UpdateTigerFontEffect( p_dec );
407 UpdateTigerFontColor( p_dec );
408 UpdateTigerBackgroundColor( p_dec );
409 UpdateTigerQuality( p_dec );
410 UpdateTigerFontDesc( p_dec );
411 }
412 }
413
414 #else
415
416 p_sys->b_use_tiger = false;
417
418 #endif
419
420 p_dec->fmt_out.i_codec = 0; // may vary during the stream
421
422 /* add the decoder to the global list */
423 decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
424 if( list )
425 {
426 list[ kate_decoder_list_size++ ] = p_dec;
427 kate_decoder_list = list;
428 }
429
430 vlc_mutex_unlock( &kate_decoder_list_mutex );
431
432 return VLC_SUCCESS;
433 }
434
435 #ifdef ENABLE_PACKETIZER
OpenPacketizer(vlc_object_t * p_this)436 static int OpenPacketizer( vlc_object_t *p_this )
437 {
438 decoder_t *p_dec = (decoder_t*)p_this;
439
440 int i_ret = OpenDecoder( p_this );
441
442 if( i_ret == VLC_SUCCESS )
443 {
444 p_dec->p_sys->b_packetizer = true;
445 p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
446 }
447
448 return i_ret;
449 }
450 #endif
451
452 /*****************************************************************************
453 * Flush:
454 *****************************************************************************/
Flush(decoder_t * p_dec)455 static void Flush( decoder_t *p_dec )
456 {
457 decoder_sys_t *p_sys = p_dec->p_sys;
458
459 #ifdef HAVE_TIGER
460 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
461 vlc_mutex_lock( &p_sys->lock );
462 tiger_renderer_seek( p_sys->p_tr, 0 );
463 vlc_mutex_unlock( &p_sys->lock );
464 #endif
465 p_sys->i_max_stop = VLC_TS_INVALID;
466 }
467
468 /****************************************************************************
469 * DecodeBlock: the whole thing
470 ****************************************************************************
471 * This function must be fed with kate packets.
472 ****************************************************************************/
DecodeBlock(decoder_t * p_dec,block_t * p_block)473 static void *DecodeBlock( decoder_t *p_dec, block_t *p_block )
474 {
475 decoder_sys_t *p_sys = p_dec->p_sys;
476 kate_packet kp;
477
478 if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
479 {
480 #ifdef HAVE_TIGER
481 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
482 {
483 /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
484 vlc_mutex_lock( &p_sys->lock );
485 tiger_renderer_seek( p_sys->p_tr, 0 );
486 vlc_mutex_unlock( &p_sys->lock );
487 }
488 #endif
489 if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
490 {
491 p_sys->i_max_stop = VLC_TS_INVALID;
492 block_Release( p_block );
493 return NULL;
494 }
495 }
496
497 /* Block to Kate packet */
498 kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
499
500 if( !p_sys->b_has_headers )
501 {
502 if( ProcessHeaders( p_dec ) )
503 {
504 block_Release( p_block );
505 return NULL;
506 }
507 p_sys->b_has_headers = true;
508 }
509
510 return ProcessPacket( p_dec, &kp, p_block );
511 }
512
DecodeSub(decoder_t * p_dec,block_t * p_block)513 static int DecodeSub( decoder_t *p_dec, block_t *p_block )
514 {
515 if( p_block == NULL ) /* No Drain */
516 return VLCDEC_SUCCESS;
517
518 subpicture_t *p_spu = DecodeBlock( p_dec, p_block );
519 if( p_spu != NULL )
520 decoder_QueueSub( p_dec, p_spu );
521 return VLCDEC_SUCCESS;
522 }
523
Packetize(decoder_t * p_dec,block_t ** pp_block)524 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
525 {
526 if( pp_block == NULL ) /* No Drain */
527 return NULL;
528 block_t *p_block = *pp_block; *pp_block = NULL;
529 if( p_block == NULL )
530 return NULL;
531 return DecodeBlock( p_dec, p_block );
532 }
533
534 /*****************************************************************************
535 * ProcessHeaders: process Kate headers.
536 *****************************************************************************/
ProcessHeaders(decoder_t * p_dec)537 static int ProcessHeaders( decoder_t *p_dec )
538 {
539 decoder_sys_t *p_sys = p_dec->p_sys;
540 kate_packet kp;
541
542 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
543 const void *pp_data[XIPH_MAX_HEADER_COUNT];
544 unsigned i_count;
545 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
546 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
547 return VLC_EGENERIC;
548
549 if( i_count < 1 )
550 return VLC_EGENERIC;
551
552 /* Take care of the initial Kate header */
553 kp.nbytes = pi_size[0];
554 kp.data = (void *)pp_data[0];
555 int i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
556 if( i_ret < 0 )
557 {
558 msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
559 return VLC_EGENERIC;
560 }
561
562 msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
563 p_sys->ki.language, p_sys->ki.category,
564 (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
565 p_sys->ki.granule_shift);
566
567 /* parse all remaining header packets */
568 for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
569 {
570 kp.nbytes = pi_size[i_headeridx];
571 kp.data = (void *)pp_data[i_headeridx];
572 i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
573 if( i_ret < 0 )
574 {
575 msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
576 return VLC_EGENERIC;
577 }
578
579 /* header 1 is comments */
580 if( i_headeridx == 1 )
581 {
582 ParseKateComments( p_dec );
583 }
584 }
585
586 #ifdef ENABLE_PACKETIZER
587 if( !p_sys->b_packetizer )
588 #endif
589 {
590 /* We have all the headers, initialize decoder */
591 msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
592 i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
593 if (i_ret < 0)
594 {
595 msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
596 return VLC_EGENERIC;
597 }
598 p_sys->b_ready = true;
599 }
600 #ifdef ENABLE_PACKETIZER
601 else
602 {
603 void* p_extra = realloc( p_dec->fmt_out.p_extra,
604 p_dec->fmt_in.i_extra );
605 if( unlikely( p_extra == NULL ) )
606 {
607 return VLC_ENOMEM;
608 }
609 p_dec->fmt_out.p_extra = p_extra;
610 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
611 memcpy( p_dec->fmt_out.p_extra,
612 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
613 }
614 #endif
615
616 return VLC_SUCCESS;
617 }
618
619 /*****************************************************************************
620 * ProcessPacket: processes a kate packet.
621 *****************************************************************************/
ProcessPacket(decoder_t * p_dec,kate_packet * p_kp,block_t * p_block)622 static void *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
623 block_t *p_block )
624 {
625 decoder_sys_t *p_sys = p_dec->p_sys;
626
627 /* Date management */
628 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
629 {
630 p_sys->i_pts = p_block->i_pts;
631 }
632
633 #ifdef ENABLE_PACKETIZER
634 if( p_sys->b_packetizer )
635 {
636 /* Date management */
637 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
638
639 if( p_sys->i_headers >= p_sys->i_num_headers )
640 p_block->i_length = p_sys->i_pts - p_block->i_pts;
641 else
642 p_block->i_length = 0;
643 return p_block;
644 }
645 else
646 #endif
647 {
648 subpicture_t *p_buf = DecodePacket( p_dec, p_kp, p_block );
649
650 block_Release( p_block );
651 return p_buf;
652 }
653 }
654
655 /* nicked off blend.c */
rgb_to_yuv(uint8_t * y,uint8_t * u,uint8_t * v,int r,int g,int b)656 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
657 int r, int g, int b )
658 {
659 *y = ( ( ( 66 * r + 129 * g + 25 * b + 128 ) >> 8 ) + 16 );
660 *u = ( ( -38 * r - 74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
661 *v = ( ( 112 * r - 94 * g - 18 * b + 128 ) >> 8 ) + 128 ;
662 }
663
664 /*
665 This retrieves the size of the video.
666 The best case is when the original video size is known, as we can then
667 scale images to match. In this case, since VLC autoscales, we want to
668 return the original size and let VLC scale everything.
669 if the original size is not known, then VLC can't resize, so we return
670 the size of the incoming video. If sizes in the Kate stream are in
671 relative units, it works fine. If they are absolute, you get what you
672 ask for. Images aren't rescaled.
673 */
GetVideoSize(decoder_t * p_dec,int * w,int * h)674 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
675 {
676 /* searching for vout to get its size is frowned upon, so we don't and
677 use a default size if the original canvas size is not specified. */
678 decoder_sys_t *p_sys = p_dec->p_sys;
679 if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
680 {
681 *w = p_sys->ki.original_canvas_width;
682 *h = p_sys->ki.original_canvas_height;
683 msg_Dbg( p_dec, "original canvas %zu %zu",
684 p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
685 }
686 else
687 {
688 /* nothing, leave defaults */
689 msg_Dbg( p_dec, "original canvas size unknown");
690 }
691 }
692
CreateKateBitmap(picture_t * pic,const kate_bitmap * bitmap)693 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
694 {
695 size_t y;
696
697 for( y=0; y<bitmap->height; ++y )
698 {
699 uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
700 const uint8_t *src = bitmap->pixels+y*bitmap->width;
701 memcpy( dest, src, bitmap->width );
702 }
703 }
704
CreateKatePalette(video_palette_t * fmt_palette,const kate_palette * palette)705 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
706 {
707 size_t n;
708
709 fmt_palette->i_entries = palette->ncolors;
710 for( n=0; n<palette->ncolors; ++n )
711 {
712 rgb_to_yuv(
713 &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
714 palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
715 );
716 fmt_palette->palette[n][3] = palette->colors[n].a;
717 }
718 }
719
SetupText(decoder_t * p_dec,subpicture_t * p_spu,const kate_event * ev)720 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
721 {
722 decoder_sys_t *p_sys = p_dec->p_sys;
723
724 if( ev->text_encoding != kate_utf8 )
725 {
726 msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
727 return;
728 }
729
730 switch( ev->text_markup_type )
731 {
732 case kate_markup_none:
733 case kate_markup_simple:
734 if( p_sys->b_formatted )
735 // p_spu->p_region->p_text = ParseSubtitles(&p_spu->p_region->i_align, ev->text );
736 ;//FIXME
737 else
738 p_spu->p_region->p_text = text_segment_New( ev->text ); /* no leak, this actually gets killed by the core */
739 break;
740 default:
741 /* we don't know about this one, so remove markup and display as text */
742 {
743 char *copy = strdup( ev->text );
744 size_t len0 = strlen( copy ) + 1;
745 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
746 p_spu->p_region->p_text = text_segment_New( copy );
747 free( copy );
748 }
749 break;
750 }
751 }
752
753 #ifdef HAVE_TIGER
754
TigerDestroySubpicture(subpicture_t * p_subpic)755 static void TigerDestroySubpicture( subpicture_t *p_subpic )
756 {
757 DecSysRelease( p_subpic->updater.p_sys->p_dec_sys );
758 free( p_subpic->updater.p_sys );
759 }
760 /*
761 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
762 * alpha to avoid double multiply (and thus thinner text than we should)).
763 * Best would be to have VLC be able to handle premultiplied alpha, as it
764 * would be faster to blend as well.
765 *
766 * Also, we flip color components around for big endian machines, as Tiger
767 * outputs ARGB or ABGR (the one we selected here) in host endianness.
768 */
PostprocessTigerImage(plane_t * p_plane,unsigned int i_width)769 static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
770 {
771 PROFILE_START( tiger_renderer_postprocess );
772 int y;
773 for( y=0; y<p_plane->i_lines; ++y )
774 {
775 uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
776 unsigned int x;
777 for( x=0; x<i_width; ++x )
778 {
779 uint8_t *p_pixel = p_line+x*4;
780 #ifdef WORDS_BIGENDIAN
781 uint8_t a = p_pixel[0];
782 #else
783 uint8_t a = p_pixel[3];
784 #endif
785 if( a )
786 {
787 #ifdef WORDS_BIGENDIAN
788 uint8_t tmp = p_pixel[2];
789 p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
790 p_pixel[3] = a;
791 p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
792 p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
793 #else
794 p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
795 p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
796 p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
797 #endif
798 }
799 else
800 {
801 p_pixel[0] = 0;
802 p_pixel[1] = 0;
803 p_pixel[2] = 0;
804 p_pixel[3] = 0;
805 }
806 }
807 }
808 PROFILE_STOP( tiger_renderer_postprocess );
809 }
810
TigerValidateSubpicture(subpicture_t * p_subpic,bool b_fmt_src,const video_format_t * p_fmt_src,bool b_fmt_dst,const video_format_t * p_fmt_dst,mtime_t ts)811 static int TigerValidateSubpicture( subpicture_t *p_subpic,
812 bool b_fmt_src, const video_format_t *p_fmt_src,
813 bool b_fmt_dst, const video_format_t *p_fmt_dst,
814 mtime_t ts )
815 {
816 VLC_UNUSED(p_fmt_src); VLC_UNUSED(p_fmt_dst);
817
818 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
819
820 if( b_fmt_src || b_fmt_dst )
821 return VLC_EGENERIC;
822
823 PROFILE_START( TigerValidateSubpicture );
824
825 /* time in seconds from the start of the stream */
826 kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
827
828 /* it is likely that the current region (if any) can be kept as is; test for this */
829 vlc_mutex_lock( &p_sys->lock );
830 int i_ret;
831 if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
832 {
833 i_ret = VLC_EGENERIC;
834 goto exit;
835 }
836 if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
837 tiger_renderer_is_dirty( p_sys->p_tr ) )
838 {
839 i_ret = VLC_EGENERIC;
840 goto exit;
841 }
842
843 i_ret = VLC_SUCCESS;
844 exit:
845 vlc_mutex_unlock( &p_sys->lock );
846 PROFILE_STOP( TigerValidateSubpicture );
847 return i_ret;
848 }
849
850 /* Tiger renders can end up looking a bit crap since they get overlaid on top of
851 a subsampled YUV image, so there can be a fair amount of chroma bleeding.
852 Looks good with white though since it's all luma. Hopefully that will be the
853 common case. */
TigerUpdateSubpicture(subpicture_t * p_subpic,const video_format_t * p_fmt_src,const video_format_t * p_fmt_dst,mtime_t ts)854 static void TigerUpdateSubpicture( subpicture_t *p_subpic,
855 const video_format_t *p_fmt_src,
856 const video_format_t *p_fmt_dst,
857 mtime_t ts )
858 {
859 decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
860 plane_t *p_plane;
861 kate_float t;
862 int i_ret;
863
864
865 /* time in seconds from the start of the stream */
866 t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
867
868 PROFILE_START( TigerUpdateSubpicture );
869
870 /* create a full frame region - this will also tell Tiger the size of the frame */
871 video_format_t fmt = *p_fmt_dst;
872 fmt.i_chroma = VLC_CODEC_RGBA;
873 fmt.i_bits_per_pixel = 0;
874 fmt.i_width =
875 fmt.i_visible_width = p_fmt_src->i_width;
876 fmt.i_height =
877 fmt.i_visible_height = p_fmt_src->i_height;
878 fmt.i_x_offset = fmt.i_y_offset = 0;
879
880 subpicture_region_t *p_r = subpicture_region_New( &fmt );
881 if( !p_r )
882 return;
883
884 p_r->i_x = 0;
885 p_r->i_y = 0;
886 p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;
887
888 vlc_mutex_lock( &p_sys->lock );
889
890 p_plane = &p_r->p_picture->p[0];
891 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 );
892 if( i_ret < 0 )
893 {
894 goto failure;
895 }
896
897 PROFILE_START( tiger_renderer_update );
898 i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
899 if( i_ret < 0 )
900 {
901 goto failure;
902 }
903 PROFILE_STOP( tiger_renderer_update );
904
905 PROFILE_START( tiger_renderer_render );
906 i_ret = tiger_renderer_render( p_sys->p_tr );
907 if( i_ret < 0 )
908 {
909 goto failure;
910 }
911 PROFILE_STOP( tiger_renderer_render );
912
913 PostprocessTigerImage( p_plane, fmt.i_width );
914 p_subpic->p_region = p_r;
915 p_sys->b_dirty = false;
916
917 PROFILE_STOP( TigerUpdateSubpicture );
918
919 vlc_mutex_unlock( &p_sys->lock );
920
921 return;
922
923 failure:
924 vlc_mutex_unlock( &p_sys->lock );
925 subpicture_region_ChainDelete( p_r );
926 }
927
GetTigerColor(decoder_t * p_dec,const char * psz_prefix)928 static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
929 {
930 char *psz_tmp;
931 uint32_t i_color = 0;
932
933 if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
934 {
935 uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
936 var_Destroy( p_dec, psz_tmp );
937 free( psz_tmp );
938 i_color |= i_rgb;
939 }
940
941 if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
942 {
943 uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
944 var_Destroy( p_dec, psz_tmp );
945 free( psz_tmp );
946 i_color |= (i_alpha << 24);
947 }
948
949 return i_color;
950 }
951
GetTigerString(decoder_t * p_dec,const char * psz_name)952 static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
953 {
954 char *psz_value = var_CreateGetString( p_dec, psz_name );
955 if( psz_value)
956 {
957 psz_value = strdup( psz_value );
958 }
959 var_Destroy( p_dec, psz_name );
960 return psz_value;
961 }
962
GetTigerInteger(decoder_t * p_dec,const char * psz_name)963 static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
964 {
965 int i_value = var_CreateGetInteger( p_dec, psz_name );
966 var_Destroy( p_dec, psz_name );
967 return i_value;
968 }
969
GetTigerFloat(decoder_t * p_dec,const char * psz_name)970 static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
971 {
972 double f_value = var_CreateGetFloat( p_dec, psz_name );
973 var_Destroy( p_dec, psz_name );
974 return f_value;
975 }
976
UpdateTigerQuality(decoder_t * p_dec)977 static void UpdateTigerQuality( decoder_t *p_dec )
978 {
979 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
980 CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
981 p_sys->b_dirty = true;
982 }
983
UpdateTigerFontDesc(decoder_t * p_dec)984 static void UpdateTigerFontDesc( decoder_t *p_dec )
985 {
986 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
987 CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
988 p_sys->b_dirty = true;
989 }
990
UpdateTigerFontColor(decoder_t * p_dec)991 static void UpdateTigerFontColor( decoder_t *p_dec )
992 {
993 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
994 double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
995 double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
996 double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
997 double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
998 CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
999 p_sys->b_dirty = true;
1000 }
1001
UpdateTigerBackgroundColor(decoder_t * p_dec)1002 static void UpdateTigerBackgroundColor( decoder_t *p_dec )
1003 {
1004 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1005 double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
1006 double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
1007 double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
1008 double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
1009 CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
1010 p_sys->b_dirty = true;
1011 }
1012
UpdateTigerFontEffect(decoder_t * p_dec)1013 static void UpdateTigerFontEffect( decoder_t *p_dec )
1014 {
1015 decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
1016 CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
1017 p_sys->e_tiger_default_font_effect,
1018 p_sys->f_tiger_default_font_effect_strength ) );
1019 p_sys->b_dirty = true;
1020 }
1021
1022 #endif
1023
1024 /*****************************************************************************
1025 * DecodePacket: decodes a Kate packet.
1026 *****************************************************************************/
DecodePacket(decoder_t * p_dec,kate_packet * p_kp,block_t * p_block)1027 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
1028 {
1029 decoder_sys_t *p_sys = p_dec->p_sys;
1030 const kate_event *ev = NULL;
1031 subpicture_t *p_spu = NULL;
1032 int i_ret;
1033
1034 if( !p_sys->b_ready )
1035 {
1036 msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1037 return NULL;
1038 }
1039
1040 i_ret = kate_decode_packetin( &p_sys->k, p_kp );
1041 if( i_ret < 0 )
1042 {
1043 msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1044 return NULL;
1045 }
1046
1047 i_ret = kate_decode_eventout( &p_sys->k, &ev );
1048 if( i_ret < 0 )
1049 {
1050 msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
1051 return NULL;
1052 }
1053 if( i_ret > 0 )
1054 {
1055 /* no event to go with this packet, this is normal */
1056 return NULL;
1057 }
1058
1059 /* we have an event */
1060
1061 /* Get a new spu */
1062 subpicture_updater_sys_t *p_spu_sys = NULL;
1063 if( p_sys->b_use_tiger)
1064 {
1065 p_spu_sys = malloc( sizeof(*p_spu_sys) );
1066 if( !p_spu_sys )
1067 return NULL;
1068 }
1069 subpicture_updater_t updater = {
1070 #ifdef HAVE_TIGER
1071 .pf_validate = TigerValidateSubpicture,
1072 .pf_update = TigerUpdateSubpicture,
1073 .pf_destroy = TigerDestroySubpicture,
1074 #endif
1075 .p_sys = p_spu_sys,
1076 };
1077 p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1078 if( !p_spu )
1079 {
1080 free( p_spu_sys );
1081 /* this will happen for lyrics as there is no vout - so no error */
1082 /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1083 return NULL;
1084 }
1085
1086 p_spu->i_start = p_block->i_pts;
1087 p_spu->i_stop = p_block->i_pts + CLOCK_FREQ *
1088 ev->duration * p_sys->ki.gps_denominator / p_sys->ki.gps_numerator;
1089 p_spu->b_ephemer = false;
1090 p_spu->b_absolute = false;
1091
1092 #ifdef HAVE_TIGER
1093 if( p_sys->b_use_tiger)
1094 {
1095 p_spu_sys->p_dec_sys = p_sys;
1096 p_spu_sys->i_start = p_block->i_pts;
1097 DecSysHold( p_sys );
1098
1099 p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
1100 p_spu->b_ephemer = true;
1101 p_spu->b_absolute = true;
1102
1103 /* add the event to tiger */
1104 vlc_mutex_lock( &p_sys->lock );
1105 CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
1106 vlc_mutex_unlock( &p_sys->lock );
1107 }
1108 else
1109 #endif
1110 {
1111 p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
1112 }
1113
1114 return p_spu;
1115 }
1116
1117 /*****************************************************************************
1118 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
1119 *****************************************************************************/
SetupSimpleKateSPU(decoder_t * p_dec,subpicture_t * p_spu,const kate_event * ev)1120 static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
1121 const kate_event *ev )
1122 {
1123 decoder_sys_t *p_sys = p_dec->p_sys;
1124 video_format_t fmt;
1125 subpicture_region_t *p_bitmap_region = NULL;
1126 video_palette_t palette;
1127 kate_tracker kin;
1128 bool b_tracker_valid = false;
1129 int i_ret;
1130
1131 /* these may be 0 for "not specified" */
1132 p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
1133 p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1134
1135 /* Create a new subpicture region */
1136 if (p_sys->b_formatted)
1137 {
1138 i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
1139 if( i_ret < 0)
1140 {
1141 msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1142 }
1143 else
1144 {
1145 int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
1146 GetVideoSize(p_dec, &w, &h);
1147 i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
1148 if( i_ret < 0)
1149 {
1150 kate_tracker_clear(&kin);
1151 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1152 }
1153 else
1154 {
1155 // TODO: parse tracker and set style, init fmt
1156 b_tracker_valid = true;
1157 }
1158 }
1159 }
1160
1161 if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1162
1163 /* create a separate region for the bitmap */
1164 video_format_Init( &fmt, VLC_CODEC_YUVP );
1165 fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
1166 fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
1167 fmt.i_x_offset = fmt.i_y_offset = 0;
1168 fmt.p_palette = &palette;
1169 CreateKatePalette( fmt.p_palette, ev->palette );
1170
1171 p_bitmap_region = subpicture_region_New( &fmt );
1172 if( !p_bitmap_region )
1173 {
1174 msg_Err( p_dec, "cannot allocate SPU region" );
1175 subpicture_Delete( p_spu );
1176 return NULL;
1177 }
1178
1179 /* create the bitmap */
1180 CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
1181
1182 msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
1183 }
1184
1185 /* text region */
1186 video_format_Init( &fmt, VLC_CODEC_TEXT );
1187 fmt.i_sar_num = 0;
1188 fmt.i_sar_den = 1;
1189 fmt.i_width = fmt.i_height = 0;
1190 fmt.i_x_offset = fmt.i_y_offset = 0;
1191 p_spu->p_region = subpicture_region_New( &fmt );
1192 video_format_Clean( &fmt );
1193 if( !p_spu->p_region )
1194 {
1195 msg_Err( p_dec, "cannot allocate SPU region" );
1196 if( p_bitmap_region )
1197 subpicture_region_Delete( p_bitmap_region );
1198 subpicture_Delete( p_spu );
1199 return NULL;
1200 }
1201
1202 SetupText( p_dec, p_spu, ev );
1203
1204 /* default positioning */
1205 p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1206 if (p_bitmap_region)
1207 {
1208 p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
1209 }
1210 p_spu->p_region->i_x = 0;
1211 p_spu->p_region->i_y = 10;
1212
1213 /* override if tracker info present */
1214 if (b_tracker_valid)
1215 {
1216 if (kin.has.region)
1217 {
1218 p_spu->p_region->i_x = kin.region_x;
1219 p_spu->p_region->i_y = kin.region_y;
1220 if (p_bitmap_region)
1221 {
1222 p_bitmap_region->i_x = kin.region_x;
1223 p_bitmap_region->i_y = kin.region_y;
1224 }
1225 p_spu->b_absolute = true;
1226 }
1227
1228 kate_tracker_clear(&kin);
1229 }
1230
1231 /* if we have a bitmap, chain it before the text */
1232 if (p_bitmap_region)
1233 {
1234 p_bitmap_region->p_next = p_spu->p_region;
1235 p_spu->p_region = p_bitmap_region;
1236 }
1237
1238 return p_spu;
1239 }
1240
1241 /*****************************************************************************
1242 * ParseKateComments:
1243 *****************************************************************************/
ParseKateComments(decoder_t * p_dec)1244 static void ParseKateComments( decoder_t *p_dec )
1245 {
1246 char *psz_name, *psz_value, *psz_comment;
1247 int i = 0;
1248
1249 while ( i < p_dec->p_sys->kc.comments )
1250 {
1251 psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
1252 if( !psz_comment )
1253 break;
1254 psz_name = psz_comment;
1255 psz_value = strchr( psz_comment, '=' );
1256 if( psz_value )
1257 {
1258 *psz_value = '\0';
1259 psz_value++;
1260
1261 if( !p_dec->p_description )
1262 p_dec->p_description = vlc_meta_New();
1263 if( p_dec->p_description )
1264 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
1265 }
1266 free( psz_comment );
1267 i++;
1268 }
1269 }
1270
1271 /*****************************************************************************
1272 * CloseDecoder: clean up the decoder
1273 *****************************************************************************/
CloseDecoder(vlc_object_t * p_this)1274 static void CloseDecoder( vlc_object_t *p_this )
1275 {
1276 decoder_t *p_dec = (decoder_t *)p_this;
1277 size_t i_index;
1278
1279 /* remove the decoder from the global list */
1280 vlc_mutex_lock( &kate_decoder_list_mutex );
1281 for( i_index = 0; i_index < kate_decoder_list_size; i_index++ )
1282 {
1283 if( kate_decoder_list[ i_index ] == p_dec )
1284 {
1285 kate_decoder_list[ i_index ] = kate_decoder_list[ --kate_decoder_list_size ];
1286 break;
1287 }
1288 }
1289 vlc_mutex_unlock( &kate_decoder_list_mutex );
1290
1291 msg_Dbg( p_dec, "Closing Kate decoder" );
1292 DecSysRelease( p_dec->p_sys );
1293 }
1294
DecSysHold(decoder_sys_t * p_sys)1295 static void DecSysHold( decoder_sys_t *p_sys )
1296 {
1297 vlc_mutex_lock( &p_sys->lock );
1298 p_sys->i_refcount++;
1299 vlc_mutex_unlock( &p_sys->lock );
1300 }
1301
DecSysRelease(decoder_sys_t * p_sys)1302 static void DecSysRelease( decoder_sys_t *p_sys )
1303 {
1304 vlc_mutex_lock( &p_sys->lock );
1305 p_sys->i_refcount--;
1306 if( p_sys->i_refcount > 0)
1307 {
1308 vlc_mutex_unlock( &p_sys->lock );
1309 return;
1310 }
1311
1312 vlc_mutex_unlock( &p_sys->lock );
1313 vlc_mutex_destroy( &p_sys->lock );
1314
1315 #ifdef HAVE_TIGER
1316 if( p_sys->p_tr )
1317 tiger_renderer_destroy( p_sys->p_tr );
1318 free( p_sys->psz_tiger_default_font_desc );
1319 #endif
1320
1321 if (p_sys->b_ready)
1322 kate_clear( &p_sys->k );
1323 kate_info_clear( &p_sys->ki );
1324 kate_comment_clear( &p_sys->kc );
1325
1326 free( p_sys );
1327 }
1328
1329