kate.c 46.9 KB
Newer Older
1 2 3
/*****************************************************************************
 * kate.c : a decoder for the kate bitstream format
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2000-2008 VLC authors and VideoLAN
5 6 7 8
 * $Id$
 *
 * Authors: Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23 24 25 26 27 28 29 30
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

31
#include <vlc_common.h>
32
#include <vlc_plugin.h>
33 34
#include <vlc_input.h>
#include <vlc_codec.h>
35
#include "../demux/xiph.h"
36 37

#include <kate/kate.h>
38 39 40
#ifdef HAVE_TIGER
# include <tiger/tiger.h>
#endif
41 42

/* #define ENABLE_PACKETIZER */
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
/* #define ENABLE_PROFILE */

#ifdef ENABLE_PROFILE
# define PROFILE_START(name) int64_t profile_start_##name = mdate()
# define PROFILE_STOP(name) fprintf( stderr, #name ": %f ms\n", (mdate() - profile_start_##name)/1000.0f )
#else
# define PROFILE_START(name) ((void)0)
# define PROFILE_STOP(name) ((void)0)
#endif

#define CHECK_TIGER_RET( statement )                                   \
    do                                                                 \
    {                                                                  \
        int i_ret = (statement);                                       \
        if( i_ret < 0 )                                                \
        {                                                              \
            msg_Dbg( p_dec, "Error in " #statement ": %d", i_ret );    \
        }                                                              \
    } while( 0 )
62 63 64 65 66 67 68 69 70 71 72 73 74 75

/*****************************************************************************
 * decoder_sys_t : decoder descriptor
 *****************************************************************************/
struct decoder_sys_t
{
#ifdef ENABLE_PACKETIZER
    /* Module mode */
    bool b_packetizer;
#endif

    /*
     * Input properties
     */
76
    bool b_has_headers;
77 78 79 80 81 82 83 84 85 86 87 88 89

    /*
     * Kate properties
     */
    bool           b_ready;
    kate_info      ki;
    kate_comment   kc;
    kate_state     k;

    /*
     * Common properties
     */
    mtime_t i_pts;
90
    mtime_t i_max_stop;
91

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    /* decoder_sys_t is shared between decoder and spu units */
    vlc_mutex_t lock;
    int         i_refcount;

#ifdef HAVE_TIGER
    /*
     * Tiger properties
     */
    tiger_renderer    *p_tr;
    bool               b_dirty;

    uint32_t           i_tiger_default_font_color;
    uint32_t           i_tiger_default_background_color;
    tiger_font_effect  e_tiger_default_font_effect;
    double             f_tiger_default_font_effect_strength;
    char              *psz_tiger_default_font_desc;
    double             f_tiger_quality;
#endif

111 112 113 114
    /*
     * Options
     */
    bool   b_formatted;
115
    bool   b_use_tiger;
116 117
};

118
struct subpicture_updater_sys_t
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
{
    decoder_sys_t *p_dec_sys;
    mtime_t        i_start;
};


/*
 * This is a global list of existing decoders.
 * The reason for this list is that:
 *  - I want to be able to reconfigure Tiger when user prefs change
 *  - User prefs are variables which are not specific to a decoder (eg, if
 *    there are several decoders, there will still be one set of variables)
 *  - A callback set on those will not be passed a pointer to the decoder
 *    (as the decoder isn't known, and there could be multiple ones)
 *  - Creating variables in the decoder will create different ones, with
 *    values copied from the relevant user pref, so a callback on those
 *    won't be called when the user pref is changed
 * Therefore, each decoder will register/unregister itself with this list,
 * callbacks will be set for the user prefs, and these will in turn walk
 * through this list and tell each decoder to update the relevant variable.
 * HOWEVER.
 * VLC's variable system is still in my way as I can't get the value of
 * the user pref variables at decoder start *unless* I create my own vars
 * which inherit from the user ones, but those are utterly useless after
 * that first use, since they'll be detached from the ones the user can
 * change. So, I create them, read their values, and then destroy them.
 */
static vlc_mutex_t kate_decoder_list_mutex = VLC_STATIC_MUTEX;
static size_t kate_decoder_list_size = 0;
static decoder_t **kate_decoder_list = NULL;

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  OpenDecoder   ( vlc_object_t * );
static void CloseDecoder  ( vlc_object_t * );
#ifdef ENABLE_PACKETIZER
static int OpenPacketizer( vlc_object_t *p_this );
#endif

static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block );
static int ProcessHeaders( decoder_t *p_dec );
static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
                            block_t **pp_block );
static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp,
                            block_t *p_block );
static void ParseKateComments( decoder_t * );
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
                            const kate_event *ev );
static void DecSysRelease( decoder_sys_t *p_sys );
static void DecSysHold( decoder_sys_t *p_sys );
#ifdef HAVE_TIGER
static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix );
static char *GetTigerString( decoder_t *p_dec, const char *psz_name );
static int GetTigerInteger( decoder_t *p_dec, const char *psz_name );
static double GetTigerFloat( decoder_t *p_dec, const char *psz_name );
static void UpdateTigerFontColor( decoder_t *p_dec );
static void UpdateTigerBackgroundColor( decoder_t *p_dec );
static void UpdateTigerFontEffect( decoder_t *p_dec );
static void UpdateTigerQuality( decoder_t *p_dec );
static void UpdateTigerFontDesc( decoder_t *p_dec );
static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
                                       vlc_value_t oldvar, vlc_value_t newval,
                                       void *p_data );
static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
                                   vlc_value_t oldval, vlc_value_t newval);
#endif
186 187 188 189 190 191 192 193 194 195

#define DEFAULT_NAME "Default"
#define MAX_LINE 8192

/*****************************************************************************
 * Module descriptor.
 *****************************************************************************/

#define FORMAT_TEXT N_("Formatted Subtitles")
#define FORMAT_LONGTEXT N_("Kate streams allow for text formatting. " \
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
 "VLC partly implements this, but you can choose to disable all formatting." \
 "Note that this has no effect is rendering via Tiger is enabled.")

#ifdef HAVE_TIGER

static const tiger_font_effect pi_font_effects[] = { tiger_font_plain, tiger_font_shadow, tiger_font_outline };
static const char * const ppsz_font_effect_names[] = { N_("None"), N_("Shadow"), N_("Outline") };

/* nicked off freetype.c */
static const int pi_color_values[] = {
  0x00000000, 0x00808080, 0x00C0C0C0, 0x00FFFFFF, 0x00800000,
  0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00808000, 0x00008000, 0x00008080,
  0x0000FF00, 0x00800080, 0x00000080, 0x000000FF, 0x0000FFFF };
static const char *const ppsz_color_descriptions[] = {
  N_("Black"), N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"),
  N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"), N_("Teal"),
  N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"), N_("Aqua") };

#define TIGER_TEXT N_("Use Tiger for rendering")
#define TIGER_LONGTEXT N_("Kate streams can be rendered using the Tiger library. " \
 "Disabling this will only render static text and bitmap based streams.")

#define TIGER_QUALITY_DEFAULT 1.0
#define TIGER_QUALITY_TEXT N_("Rendering quality")
#define TIGER_QUALITY_LONGTEXT N_("Select rendering quality, at the expense of speed. " \
 "0 is fastest, 1 is highest quality.")

#define TIGER_DEFAULT_FONT_EFFECT_DEFAULT 0
#define TIGER_DEFAULT_FONT_EFFECT_TEXT N_("Default font effect")
#define TIGER_DEFAULT_FONT_EFFECT_LONGTEXT N_("Add a font effect to text to improve readability " \
 "against different backgrounds.")

#define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT 0.5
#define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT N_("Default font effect strength")
#define TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT N_("How pronounced to make the chosen font effect " \
 "(effect dependent).")

#define TIGER_DEFAULT_FONT_DESC_DEFAULT ""
#define TIGER_DEFAULT_FONT_DESC_TEXT N_("Default font description")
#define TIGER_DEFAULT_FONT_DESC_LONGTEXT N_("Which font description to use if the Kate stream " \
 "does not specify particular font parameters (name, size, etc) to use. " \
 "A blank name will let Tiger choose font parameters where appropriate.")

#define TIGER_DEFAULT_FONT_COLOR_DEFAULT 0x00ffffff
#define TIGER_DEFAULT_FONT_COLOR_TEXT N_("Default font color")
#define TIGER_DEFAULT_FONT_COLOR_LONGTEXT N_("Default font color to use if the Kate stream " \
 "does not specify a particular font color to use.")

#define TIGER_DEFAULT_FONT_ALPHA_DEFAULT 0xff
#define TIGER_DEFAULT_FONT_ALPHA_TEXT N_("Default font alpha")
#define TIGER_DEFAULT_FONT_ALPHA_LONGTEXT N_("Transparency of the default font color if the Kate stream " \
 "does not specify a particular font color to use.")

#define TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT 0x00ffffff
#define TIGER_DEFAULT_BACKGROUND_COLOR_TEXT N_("Default background color")
#define TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT N_("Default background color if the Kate stream " \
 "does not specify a background color to use.")

#define TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT 0
#define TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT N_("Default background alpha")
#define TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT N_("Transparency of the default background color if the Kate stream " \
 "does not specify a particular background color to use.")

259 260
#endif

261 262 263 264 265 266 267 268
#define HELP_TEXT N_( \
    "Kate is a codec for text and image based overlays.\n" \
    "The Tiger rendering library is needed to render complex Kate streams, " \
    "but VLC can still render static text and image based subtitles if " \
    "it is not available.\n" \
    "Note that changing settings below will not take effect until a new stream is played. " \
    "This will hopefully be fixed soon." \
    )
269

270 271
vlc_module_begin ()
    set_shortname( N_("Kate"))
272 273
    set_description( N_("Kate overlay decoder") )
    set_help( HELP_TEXT )
274 275 276 277 278
    set_capability( "decoder", 50 )
    set_callbacks( OpenDecoder, CloseDecoder )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_SCODEC )
    add_shortcut( "kate" )
279

280
    add_bool( "kate-formatted", true, FORMAT_TEXT, FORMAT_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
281
              true )
282 283

#ifdef HAVE_TIGER
284
    add_bool( "kate-use-tiger", true, TIGER_TEXT, TIGER_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
285
              true )
286
    add_float_with_range( "kate-tiger-quality",
287
                          TIGER_QUALITY_DEFAULT, 0.0f, 1.0f,
288
                          TIGER_QUALITY_TEXT, TIGER_QUALITY_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
289
                          true )
290 291

    set_section( N_("Tiger rendering defaults"), NULL );
292
    add_string( "kate-tiger-default-font-desc", TIGER_DEFAULT_FONT_DESC_DEFAULT,
293 294 295
                TIGER_DEFAULT_FONT_DESC_TEXT, TIGER_DEFAULT_FONT_DESC_LONGTEXT, true);
    add_integer_with_range( "kate-tiger-default-font-effect",
                            TIGER_DEFAULT_FONT_EFFECT_DEFAULT,
296
                            0, sizeof(pi_font_effects)/sizeof(pi_font_effects[0])-1,
297
                            TIGER_DEFAULT_FONT_EFFECT_TEXT, TIGER_DEFAULT_FONT_EFFECT_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
298
                            true )
299
    change_integer_list( pi_font_effects, ppsz_font_effect_names );
300
    add_float_with_range( "kate-tiger-default-font-effect-strength",
301
              TIGER_DEFAULT_FONT_EFFECT_STRENGTH_DEFAULT, 0.0f, 1.0f,
302
              TIGER_DEFAULT_FONT_EFFECT_STRENGTH_TEXT, TIGER_DEFAULT_FONT_EFFECT_STRENGTH_LONGTEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
303
              true )
304
    add_integer_with_range( "kate-tiger-default-font-color",
305
                            TIGER_DEFAULT_FONT_COLOR_DEFAULT, 0, 0x00ffffff,
306 307
                            TIGER_DEFAULT_FONT_COLOR_TEXT, TIGER_DEFAULT_FONT_COLOR_LONGTEXT,
                            true);
308
    change_integer_list( pi_color_values, ppsz_color_descriptions );
309
    add_integer_with_range( "kate-tiger-default-font-alpha",
310
                            TIGER_DEFAULT_FONT_ALPHA_DEFAULT, 0, 255,
311 312 313
                            TIGER_DEFAULT_FONT_ALPHA_TEXT, TIGER_DEFAULT_FONT_ALPHA_LONGTEXT,
                            true);
    add_integer_with_range( "kate-tiger-default-background-color",
314
                            TIGER_DEFAULT_BACKGROUND_COLOR_DEFAULT, 0, 0x00ffffff,
315 316
                            TIGER_DEFAULT_BACKGROUND_COLOR_TEXT, TIGER_DEFAULT_BACKGROUND_COLOR_LONGTEXT,
                            true);
317
    change_integer_list( pi_color_values, ppsz_color_descriptions );
318
    add_integer_with_range( "kate-tiger-default-background-alpha",
319
                            TIGER_DEFAULT_BACKGROUND_ALPHA_DEFAULT, 0, 255,
320 321 322 323
                            TIGER_DEFAULT_BACKGROUND_ALPHA_TEXT, TIGER_DEFAULT_BACKGROUND_ALPHA_LONGTEXT,
                            true);
#endif

324
#ifdef ENABLE_PACKETIZER
325 326 327 328 329
    add_submodule ()
    set_description( N_("Kate text subtitles packetizer") )
    set_capability( "packetizer", 100 )
    set_callbacks( OpenPacketizer, CloseDecoder )
    add_shortcut( "kate" )
330 331
#endif

332
vlc_module_end ()
333 334 335 336 337 338 339 340 341 342 343 344

/*****************************************************************************
 * OpenDecoder: probe the decoder and return score
 *****************************************************************************
 * Tries to launch a decoder and return score so that the interface is able
 * to chose.
 *****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
    decoder_t     *p_dec = (decoder_t*)p_this;
    decoder_sys_t *p_sys;

345
    if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE )
346 347 348 349
    {
        return VLC_EGENERIC;
    }

350 351
    msg_Dbg( p_dec, "kate: OpenDecoder");

352 353 354 355 356 357 358
    /* Set callbacks */
    p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
        DecodeBlock;
    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
        DecodeBlock;

    /* Allocate the memory needed to store the decoder's structure */
359
    if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
360 361
        return VLC_ENOMEM;

362 363 364 365
    vlc_mutex_init( &p_sys->lock );
    p_sys->i_refcount = 0;
    DecSysHold( p_sys );

366 367 368 369 370
    /* init of p_sys */
#ifdef ENABLE_PACKETIZER
    p_sys->b_packetizer = false;
#endif
    p_sys->b_ready = false;
371
    p_sys->i_pts =
372
    p_sys->i_max_stop = VLC_TS_INVALID;
373 374 375 376

    kate_comment_init( &p_sys->kc );
    kate_info_init( &p_sys->ki );

377
    p_sys->b_has_headers = false;
378 379 380

    /* retrieve options */
    p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399

    vlc_mutex_lock( &kate_decoder_list_mutex );

#ifdef HAVE_TIGER

    p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" );

    p_sys->p_tr = NULL;

    /* get initial value of configuration */
    p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" );
    p_sys->i_tiger_default_background_color = GetTigerColor( p_dec, "kate-tiger-default-background" );
    p_sys->e_tiger_default_font_effect = GetTigerInteger( p_dec, "kate-tiger-default-font-effect" );
    p_sys->f_tiger_default_font_effect_strength = GetTigerFloat( p_dec, "kate-tiger-default-font-effect-strength" );
    p_sys->psz_tiger_default_font_desc = GetTigerString( p_dec, "kate-tiger-default-font-desc" );
    p_sys->f_tiger_quality = GetTigerFloat( p_dec, "kate-tiger-quality" );

    if( p_sys->b_use_tiger )
    {
Pierre's avatar
Pierre committed
400
        int i_ret = tiger_renderer_create( &p_sys->p_tr );
401 402 403 404 405 406
        if( i_ret < 0 )
        {
            msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" );
            p_sys->p_tr = NULL;
            p_sys->b_use_tiger = false;
        }
407 408 409 410 411 412 413 414 415
        else {
            CHECK_TIGER_RET( tiger_renderer_set_surface_clear_color( p_sys->p_tr, 1, 0, 0, 0, 0 ) );

            UpdateTigerFontEffect( p_dec );
            UpdateTigerFontColor( p_dec );
            UpdateTigerBackgroundColor( p_dec );
            UpdateTigerQuality( p_dec );
            UpdateTigerFontDesc( p_dec );
        }
416 417 418 419 420 421
    }

#else

    p_sys->b_use_tiger = false;

422 423
#endif

424 425
    es_format_Init( &p_dec->fmt_out, SPU_ES, 0 );

426
    /* add the decoder to the global list */
427
    decoder_t **list = realloc( kate_decoder_list, (kate_decoder_list_size+1) * sizeof( *list ));
428 429 430 431 432 433 434 435
    if( list )
    {
        list[ kate_decoder_list_size++ ] = p_dec;
        kate_decoder_list = list;
    }

    vlc_mutex_unlock( &kate_decoder_list_mutex );

436 437 438 439 440 441 442 443 444 445 446 447 448
    return VLC_SUCCESS;
}

#ifdef ENABLE_PACKETIZER
static int OpenPacketizer( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t*)p_this;

    int i_ret = OpenDecoder( p_this );

    if( i_ret == VLC_SUCCESS )
    {
        p_dec->p_sys->b_packetizer = true;
449
        p_dec->fmt_out.i_codec = VLC_CODEC_KATE;
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
    }

    return i_ret;
}
#endif

/****************************************************************************
 * DecodeBlock: the whole thing
 ****************************************************************************
 * This function must be fed with kate packets.
 ****************************************************************************/
static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block;
    kate_packet kp;

467 468
    if( !pp_block || !*pp_block )
        return NULL;
469 470

    p_block = *pp_block;
471

472
    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
473 474
    {
#ifdef HAVE_TIGER
475 476 477 478 479 480 481
        if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY)
        {
            /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */
            vlc_mutex_lock( &p_sys->lock );
            tiger_renderer_seek( p_sys->p_tr, 0 );
            vlc_mutex_unlock( &p_sys->lock );
        }
482
#endif
483 484 485
        p_sys->i_max_stop = VLC_TS_INVALID;
        block_Release( p_block );
        return NULL;
486
    }
487 488 489 490

    /* Block to Kate packet */
    kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);

491
    if( !p_sys->b_has_headers )
492
    {
493
        if( ProcessHeaders( p_dec ) )
494 495 496 497
        {
            block_Release( *pp_block );
            return NULL;
        }
498
        p_sys->b_has_headers = true;
499 500 501 502 503 504 505 506 507 508 509 510 511
    }

    return ProcessPacket( p_dec, &kp, pp_block );
}

/*****************************************************************************
 * ProcessHeaders: process Kate headers.
 *****************************************************************************/
static int ProcessHeaders( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    kate_packet kp;

512 513 514 515 516
    unsigned pi_size[XIPH_MAX_HEADER_COUNT];
    void     *pp_data[XIPH_MAX_HEADER_COUNT];
    unsigned i_count;
    if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
                           p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
517
        return VLC_EGENERIC;
518

519
    if( i_count < 1 )
520
        return VLC_EGENERIC;
521

522 523 524
    /* Take care of the initial Kate header */
    kp.nbytes = pi_size[0];
    kp.data   = pp_data[0];
525
    int i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
526
    if( i_ret < 0 )
527
    {
528
        msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret );
529
        return VLC_EGENERIC;
530 531 532 533 534 535 536 537
    }

    msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
             p_sys->ki.language, p_sys->ki.category,
             (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
             p_sys->ki.granule_shift);

    /* parse all remaining header packets */
538
    for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ )
539
    {
540 541
        kp.nbytes = pi_size[i_headeridx];
        kp.data   = pp_data[i_headeridx];
542 543
        i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
        if( i_ret < 0 )
544
        {
545
            msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret );
546
            return VLC_EGENERIC;
547 548 549
        }

        /* header 1 is comments */
550
        if( i_headeridx == 1 )
551 552 553 554 555 556 557 558 559 560 561
        {
            ParseKateComments( p_dec );
        }
    }

#ifdef ENABLE_PACKETIZER
    if( !p_sys->b_packetizer )
#endif
    {
        /* We have all the headers, initialize decoder */
        msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
562 563
        i_ret = kate_decode_init( &p_sys->k, &p_sys->ki );
        if (i_ret < 0)
564
        {
565
            msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret );
566 567 568 569 570 571 572 573
            return VLC_EGENERIC;
        }
        p_sys->b_ready = true;
    }
#ifdef ENABLE_PACKETIZER
    else
    {
        p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
574
        p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra,
575
                                                  p_dec->fmt_out.i_extra );
576 577 578 579 580
        memcpy( p_dec->fmt_out.p_extra,
                p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
    }
#endif

581
    return VLC_SUCCESS;
582 583 584 585 586 587 588 589 590 591 592 593 594
}

/*****************************************************************************
 * ProcessPacket: processes a kate packet.
 *****************************************************************************/
static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
                            block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_block = *pp_block;
    subpicture_t *p_buf = NULL;

    /* Date management */
595
    if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
    {
        p_sys->i_pts = p_block->i_pts;
    }

    *pp_block = NULL; /* To avoid being fed the same packet again */

#ifdef ENABLE_PACKETIZER
    if( p_sys->b_packetizer )
    {
        /* Date management */
        p_block->i_dts = p_block->i_pts = p_sys->i_pts;

        if( p_sys->i_headers >= p_sys->i_num_headers )
            p_block->i_length = p_sys->i_pts - p_block->i_pts;
        else
            p_block->i_length = 0;

        p_buf = p_block;
    }
    else
#endif
    {
618
        p_buf = DecodePacket( p_dec, p_kp, p_block );
619

620 621
        if( p_block )
            block_Release( p_block );
622 623 624 625 626 627 628 629 630 631 632 633 634 635
    }

    return p_buf;
}

/* nicked off blend.c */
static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
                               int r, int g, int b )
{
    *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
    *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
    *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
}

636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
/*
  This retrieves the size of the video.
  The best case is when the original video size is known, as we can then
  scale images to match. In this case, since VLC autoscales, we want to
  return the original size and let VLC scale everything.
  if the original size is not known, then VLC can't resize, so we return
  the size of the incoming video. If sizes in the Kate stream are in
  relative units, it works fine. If they are absolute, you get what you
  ask for. Images aren't rescaled.
*/
static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
{
    /* searching for vout to get its size is frowned upon, so we don't and
       use a default size if the original canvas size is not specified. */
    decoder_sys_t *p_sys = p_dec->p_sys;
    if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
    {
        *w = p_sys->ki.original_canvas_width;
        *h = p_sys->ki.original_canvas_height;
655
        msg_Dbg( p_dec, "original canvas %zu %zu",
656 657 658 659 660
	         p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
    }
    else
    {
        /* nothing, leave defaults */
661
        msg_Dbg( p_dec, "original canvas size unknown");
662 663 664
    }
}

665
static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
666 667 668 669 670 671 672 673 674 675 676
{
    size_t y;

    for( y=0; y<bitmap->height; ++y )
    {
        uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
        const uint8_t *src = bitmap->pixels+y*bitmap->width;
        memcpy( dest, src, bitmap->width );
    }
}

677
static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
{
    size_t n;

    fmt_palette->i_entries = palette->ncolors;
    for( n=0; n<palette->ncolors; ++n )
    {
        rgb_to_yuv(
            &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
            palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
        );
        fmt_palette->palette[n][3] = palette->colors[n].a;
    }
}

static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
{
    decoder_sys_t *p_sys = p_dec->p_sys;

    if( ev->text_encoding != kate_utf8 )
    {
        msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
        return;
    }

    switch( ev->text_markup_type )
    {
        case kate_markup_none:
        case kate_markup_simple:
            if( p_sys->b_formatted )
707 708 709 710 711
//                p_spu->p_region->p_text = ParseSubtitles(&p_spu->p_region->i_align, ev->text );
                ;//FIXME
            else
                p_spu->p_region->p_text = text_segment_New( ev->text ); /* no leak, this actually gets killed by the core */
            break;
712 713 714 715 716 717
        default:
            /* we don't know about this one, so remove markup and display as text */
            {
                char *copy = strdup( ev->text );
                size_t len0 = strlen( copy ) + 1;
                kate_text_remove_markup( ev->text_encoding, copy, &len0 );
718
                p_spu->p_region->p_text = text_segment_New( copy );
719
                free( copy );
720 721 722 723 724
            }
            break;
    }
}

725 726 727 728
#ifdef HAVE_TIGER

static void TigerDestroySubpicture( subpicture_t *p_subpic )
{
729 730
    DecSysRelease( p_subpic->updater.p_sys->p_dec_sys );
    free( p_subpic->updater.p_sys );
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
}
/*
 * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply
 * alpha to avoid double multiply (and thus thinner text than we should)).
 * Best would be to have VLC be able to handle premultiplied alpha, as it
 * would be faster to blend as well.
 *
 * Also, we flip color components around for big endian machines, as Tiger
 * outputs ARGB or ABGR (the one we selected here) in host endianness.
 */
static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width )
{
    PROFILE_START( tiger_renderer_postprocess );
    int y;
    for( y=0; y<p_plane->i_lines; ++y )
    {
        uint8_t *p_line = (uint8_t*)(p_plane->p_pixels + y*p_plane->i_pitch);
        unsigned int x;
        for( x=0; x<i_width; ++x )
        {
            uint8_t *p_pixel = p_line+x*4;
#ifdef WORDS_BIGENDIAN
            uint8_t a = p_pixel[0];
#else
            uint8_t a = p_pixel[3];
#endif
            if( a )
            {
#ifdef WORDS_BIGENDIAN
760
                uint8_t tmp = p_pixel[2];
761
                p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a);
762
                p_pixel[3] = a;
763 764
                p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
                p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a);
765
#else
766 767 768
                p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a);
                p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a);
                p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a);
769 770 771 772 773 774 775 776 777 778 779 780 781 782
#endif
            }
            else
            {
                p_pixel[0] = 0;
                p_pixel[1] = 0;
                p_pixel[2] = 0;
                p_pixel[3] = 0;
            }
        }
    }
    PROFILE_STOP( tiger_renderer_postprocess );
}

783 784 785 786
static int 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 )
787
{
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
788 789
    VLC_UNUSED(p_fmt_src); VLC_UNUSED(p_fmt_dst);

790
    decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
791

792 793
    if( b_fmt_src || b_fmt_dst )
        return VLC_EGENERIC;
794

795
    PROFILE_START( TigerValidateSubpicture );
796 797

    /* time in seconds from the start of the stream */
798
    kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;
799 800 801

    /* it is likely that the current region (if any) can be kept as is; test for this */
    vlc_mutex_lock( &p_sys->lock );
802 803
    int i_ret;
    if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) )
804
    {
805 806 807 808 809 810 811 812
        i_ret = VLC_EGENERIC;
        goto exit;
    }
    if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 &&
        tiger_renderer_is_dirty( p_sys->p_tr ) )
    {
        i_ret = VLC_EGENERIC;
        goto exit;
813
    }
814 815 816

    i_ret = VLC_SUCCESS;
exit:
817
    vlc_mutex_unlock( &p_sys->lock );
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
    PROFILE_STOP( TigerValidateSubpicture );
    return i_ret;
}

/* Tiger renders can end up looking a bit crap since they get overlaid on top of
   a subsampled YUV image, so there can be a fair amount of chroma bleeding.
   Looks good with white though since it's all luma. Hopefully that will be the
   common case. */
static void TigerUpdateSubpicture( subpicture_t *p_subpic,
                                   const video_format_t *p_fmt_src,
                                   const video_format_t *p_fmt_dst,
                                   mtime_t ts )
{
    decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys;
    plane_t *p_plane;
    kate_float t;
    int i_ret;
835

836 837 838 839 840

    /* time in seconds from the start of the stream */
    t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f;

    PROFILE_START( TigerUpdateSubpicture );
841 842

    /* create a full frame region - this will also tell Tiger the size of the frame */
843 844
    video_format_t fmt = *p_fmt_dst;
    fmt.i_chroma         = VLC_CODEC_RGBA;
845
    fmt.i_bits_per_pixel = 0;
846 847 848 849 850
    fmt.i_width          =
    fmt.i_visible_width  = p_fmt_src->i_width;
    fmt.i_height         =
    fmt.i_visible_height = p_fmt_src->i_height;
    fmt.i_x_offset       = fmt.i_y_offset = 0;
851

852
    subpicture_region_t *p_r = subpicture_region_New( &fmt );
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
    if( !p_r )
        return;

    p_r->i_x = 0;
    p_r->i_y = 0;
    p_r->i_align = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT;

    vlc_mutex_lock( &p_sys->lock );

    p_plane = &p_r->p_picture->p[0];
    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 );
    if( i_ret < 0 )
    {
        goto failure;
    }

    PROFILE_START( tiger_renderer_update );
    i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 );
    if( i_ret < 0 )
    {
        goto failure;
    }
    PROFILE_STOP( tiger_renderer_update );

    PROFILE_START( tiger_renderer_render );
    i_ret = tiger_renderer_render( p_sys->p_tr );
    if( i_ret < 0 )
    {
        goto failure;
    }
    PROFILE_STOP( tiger_renderer_render );

    PostprocessTigerImage( p_plane, fmt.i_width );
    p_subpic->p_region = p_r;
    p_sys->b_dirty = false;

889
    PROFILE_STOP( TigerUpdateSubpicture );
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002

    vlc_mutex_unlock( &p_sys->lock );

    return;

failure:
    vlc_mutex_unlock( &p_sys->lock );
    subpicture_region_ChainDelete( p_r );
}

static uint32_t GetTigerColor( decoder_t *p_dec, const char *psz_prefix )
{
    char *psz_tmp;
    uint32_t i_color = 0;

    if( asprintf( &psz_tmp, "%s-color", psz_prefix ) >= 0 )
    {
        uint32_t i_rgb = var_CreateGetInteger( p_dec, psz_tmp );
        var_Destroy( p_dec, psz_tmp );
        free( psz_tmp );
        i_color |= i_rgb;
    }

    if( asprintf( &psz_tmp, "%s-alpha", psz_prefix ) >= 0 )
    {
        uint32_t i_alpha = var_CreateGetInteger( p_dec, psz_tmp );
        var_Destroy( p_dec, psz_tmp );
        free( psz_tmp );
        i_color |= (i_alpha << 24);
    }

    return i_color;
}

static char *GetTigerString( decoder_t *p_dec, const char *psz_name )
{
    char *psz_value = var_CreateGetString( p_dec, psz_name );
    if( psz_value)
    {
        psz_value = strdup( psz_value );
    }
    var_Destroy( p_dec, psz_name );
    return psz_value;
}

static int GetTigerInteger( decoder_t *p_dec, const char *psz_name )
{
    int i_value = var_CreateGetInteger( p_dec, psz_name );
    var_Destroy( p_dec, psz_name );
    return i_value;
}

static double GetTigerFloat( decoder_t *p_dec, const char *psz_name )
{
    double f_value = var_CreateGetFloat( p_dec, psz_name );
    var_Destroy( p_dec, psz_name );
    return f_value;
}

static void UpdateTigerQuality( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
    CHECK_TIGER_RET( tiger_renderer_set_quality( p_sys->p_tr, p_sys->f_tiger_quality ) );
    p_sys->b_dirty = true;
}

static void UpdateTigerFontDesc( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
    CHECK_TIGER_RET( tiger_renderer_set_default_font_description( p_sys->p_tr, p_sys->psz_tiger_default_font_desc ) );
    p_sys->b_dirty = true;
}

static void UpdateTigerFontColor( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
    double f_a = ((p_sys->i_tiger_default_font_color >> 24) & 0xff) / 255.0;
    double f_r = ((p_sys->i_tiger_default_font_color >> 16) & 0xff) / 255.0;
    double f_g = ((p_sys->i_tiger_default_font_color >> 8) & 0xff) / 255.0;
    double f_b = (p_sys->i_tiger_default_font_color & 0xff) / 255.0;
    CHECK_TIGER_RET( tiger_renderer_set_default_font_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
    p_sys->b_dirty = true;
}

static void UpdateTigerBackgroundColor( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
    double f_a = ((p_sys->i_tiger_default_background_color >> 24) & 0xff) / 255.0;
    double f_r = ((p_sys->i_tiger_default_background_color >> 16) & 0xff) / 255.0;
    double f_g = ((p_sys->i_tiger_default_background_color >> 8) & 0xff) / 255.0;
    double f_b = (p_sys->i_tiger_default_background_color & 0xff) / 255.0;
    CHECK_TIGER_RET( tiger_renderer_set_default_background_fill_color( p_sys->p_tr, f_r, f_g, f_b, f_a ) );
    p_sys->b_dirty = true;
}

static void UpdateTigerFontEffect( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;
    CHECK_TIGER_RET( tiger_renderer_set_default_font_effect( p_sys->p_tr,
                                                             p_sys->e_tiger_default_font_effect,
                                                             p_sys->f_tiger_default_font_effect_strength ) );
    p_sys->b_dirty = true;
}

static int OnConfigurationChanged( decoder_t *p_dec, const char *psz_var,
                                   vlc_value_t oldval, vlc_value_t newval )
{
    decoder_sys_t *p_sys = (decoder_sys_t*)p_dec->p_sys;

    VLC_UNUSED( oldval );

    vlc_mutex_lock( &p_sys->lock );

1003
    msg_Dbg( p_dec, "OnConfigurationChanged: %s", psz_var );
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103

    if( !p_sys->b_use_tiger || !p_sys->p_tr )
    {
        vlc_mutex_unlock( &p_sys->lock );
        return VLC_SUCCESS;
    }

#define TEST_TIGER_VAR( name ) \
    if( !strcmp( name, psz_var ) )

    TEST_TIGER_VAR( "kate-tiger-quality" )
    {
        p_sys->f_tiger_quality = newval.f_float;
        UpdateTigerQuality( p_dec );
    }

    TEST_TIGER_VAR( "kate-tiger-default-font-desc" )
    {
        if( p_sys->psz_tiger_default_font_desc )
        {
            free( p_sys->psz_tiger_default_font_desc );
            p_sys->psz_tiger_default_font_desc = NULL;
        }
        if( newval.psz_string )
        {
            p_sys->psz_tiger_default_font_desc = strdup( newval.psz_string );
        }
        UpdateTigerFontDesc( p_dec );
    }

    TEST_TIGER_VAR( "kate-tiger-default-font-color" )
    {
        p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0xff00000000) | newval.i_int;
        UpdateTigerFontColor( p_dec );
    }

    TEST_TIGER_VAR( "kate-tiger-default-font-alpha" )
    {
        p_sys->i_tiger_default_font_color = (p_sys->i_tiger_default_font_color & 0x00ffffff) | (newval.i_int<<24);
        UpdateTigerFontColor( p_dec );
    }

    TEST_TIGER_VAR( "kate-tiger-default-background-color" )
    {
        p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0xff00000000) | newval.i_int;
        UpdateTigerBackgroundColor( p_dec );
    }

    TEST_TIGER_VAR( "kate-tiger-default-background-alpha" )
    {
        p_sys->i_tiger_default_background_color = (p_sys->i_tiger_default_background_color & 0x00ffffff) | (newval.i_int<<24);
        UpdateTigerBackgroundColor( p_dec );
    }

    TEST_TIGER_VAR( "kate-tiger-default-font-effect" )
    {
        p_sys->e_tiger_default_font_effect = (tiger_font_effect)newval.i_int;
        UpdateTigerFontEffect( p_dec );
    }

    TEST_TIGER_VAR( "kate-tiger-default-font-effect-strength" )
    {
        p_sys->f_tiger_default_font_effect_strength = newval.f_float;
        UpdateTigerFontEffect( p_dec );
    }

#undef TEST_TIGER_VAR

    vlc_mutex_unlock( &p_sys->lock );

    return VLC_SUCCESS;
}

static int TigerConfigurationCallback( vlc_object_t *p_this, const char *psz_var,
                                       vlc_value_t oldval, vlc_value_t newval,
                                       void *p_data )
{
    size_t i_idx;

    VLC_UNUSED( p_this );
    VLC_UNUSED( oldval );
    VLC_UNUSED( newval );
    VLC_UNUSED( p_data );

    vlc_mutex_lock( &kate_decoder_list_mutex );

    /* Update all existing decoders from the global user prefs */
    for( i_idx = 0; i_idx < kate_decoder_list_size; i_idx++ )
    {
        decoder_t *p_dec = kate_decoder_list[ i_idx ];
        OnConfigurationChanged( p_dec, psz_var, oldval, newval );
    }

    vlc_mutex_unlock( &kate_decoder_list_mutex );

    return VLC_SUCCESS;
}

#endif

1104 1105 1106 1107 1108 1109
/*****************************************************************************
 * DecodePacket: decodes a Kate packet.
 *****************************************************************************/
static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
1110
    const kate_event *ev = NULL;
1111
    subpicture_t *p_spu = NULL;
1112
    int i_ret;
1113

1114
    if( !p_sys->b_ready )
1115
    {
1116
        msg_Err( p_dec, "Cannot decode Kate packet, decoder not initialized" );
1117 1118 1119
        return NULL;
    }

1120 1121
    i_ret = kate_decode_packetin( &p_sys->k, p_kp );
    if( i_ret < 0 )
1122
    {
1123
        msg_Err( p_dec, "Kate failed to decode packet: %d", i_ret );
1124 1125
        return NULL;
    }
1126 1127 1128 1129 1130 1131 1132 1133

    i_ret = kate_decode_eventout( &p_sys->k, &ev );
    if( i_ret < 0 )
    {
        msg_Err( p_dec, "Kate failed to retrieve event: %d", i_ret );
        return NULL;
    }
    if( i_ret > 0 )
1134 1135 1136 1137 1138 1139 1140 1141
    {
        /* no event to go with this packet, this is normal */
        return NULL;
    }

    /* we have an event */

    /* Get a new spu */
1142 1143 1144 1145 1146 1147 1148 1149
    subpicture_updater_sys_t *p_spu_sys = NULL;
    if( p_sys->b_use_tiger)
    {
        p_spu_sys = malloc( sizeof(*p_spu_sys) );
        if( !p_spu_sys )
            return NULL;
    }
    subpicture_updater_t updater = {
1150
#ifdef HAVE_TIGER
1151 1152 1153
        .pf_validate = TigerValidateSubpicture,
        .pf_update   = TigerUpdateSubpicture,
        .pf_destroy  = TigerDestroySubpicture,
1154
#endif
1155 1156 1157
        .p_sys       = p_spu_sys,
    };
    p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL );
1158 1159
    if( !p_spu )
    {
1160
        free( p_spu_sys );
1161 1162
        /* this will happen for lyrics as there is no vout - so no error */
        /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */
1163 1164 1165
        return NULL;
    }

1166
    p_spu->i_start = p_block->i_pts;
Tristan Matthews's avatar
Tristan Matthews committed
1167 1168
    p_spu->i_stop = p_block->i_pts + CLOCK_FREQ *
        ev->duration * p_sys->ki.gps_denominator / p_sys->ki.gps_numerator;
1169 1170 1171 1172 1173 1174
    p_spu->b_ephemer = false;
    p_spu->b_absolute = false;

#ifdef HAVE_TIGER
    if( p_sys->b_use_tiger)
    {
1175 1176
        p_spu_sys->p_dec_sys = p_sys;
        p_spu_sys->i_start   = p_block->i_pts;
1177 1178
        DecSysHold( p_sys );

1179 1180
        p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop );
        p_spu->b_ephemer = true;
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
        p_spu->b_absolute = true;

        /* add the event to tiger */
        vlc_mutex_lock( &p_sys->lock );
        CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) );
        vlc_mutex_unlock( &p_sys->lock );
    }
    else
#endif
    {
        p_spu = SetupSimpleKateSPU( p_dec, p_spu, ev );
    }

    return p_spu;
}

/*****************************************************************************
 * SetupSimpleKateSPU: creates text/bitmap regions where appropriate
 *****************************************************************************/
static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu,
                                         const kate_event *ev )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    video_format_t fmt;
    subpicture_region_t *p_bitmap_region = NULL;
    video_palette_t palette;
    kate_tracker kin;
    bool b_tracker_valid = false;
    int i_ret;

1211 1212 1213
    /* these may be 0 for "not specified" */
    p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
    p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
1214 1215 1216 1217 1218 1219

    /* Create a new subpicture region */
    memset( &fmt, 0, sizeof(video_format_t) );

    if (p_sys->b_formatted)
    {
1220 1221
        i_ret = kate_tracker_init( &kin, &p_sys->ki, ev );
        if( i_ret < 0)
1222
        {
1223
            msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", i_ret );
1224 1225 1226
        }
        else
        {
1227 1228
            int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
            GetVideoSize(p_dec, &w, &h);
1229 1230
            i_ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
            if( i_ret < 0)
1231 1232
            {
                kate_tracker_clear(&kin);
1233
                msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", i_ret );
1234 1235 1236 1237
            }
            else
            {
                // TODO: parse tracker and set style, init fmt
1238
                b_tracker_valid = true;
1239 1240 1241 1242
            }
        }
    }

1243
    if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
1244

1245 1246
        /* create a separate region for the bitmap */
        memset( &fmt, 0, sizeof(video_format_t) );
1247
        fmt.i_chroma = VLC_CODEC_YUVP;
1248 1249 1250
        fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
        fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
        fmt.i_x_offset = fmt.i_y_offset = 0;
1251 1252
        fmt.p_palette = &palette;
        CreateKatePalette( fmt.p_palette, ev->palette );
1253

Laurent Aimar's avatar