vout_subpictures.c 50.4 KB
Newer Older
Sam Hocevar's avatar
 
Sam Hocevar committed
1 2 3
/*****************************************************************************
 * vout_subpictures.c : subpicture management functions
 *****************************************************************************
4
 * Copyright (C) 2000-2007 the VideoLAN team
5
 * $Id$
Sam Hocevar's avatar
 
Sam Hocevar committed
6 7 8
 *
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
 *          Samuel Hocevar <sam@zoy.org>
9
 *          Gildas Bazin <gbazin@videolan.org>
Sam Hocevar's avatar
 
Sam Hocevar committed
10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Sam Hocevar's avatar
 
Sam Hocevar committed
24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#include <vlc_common.h>
Clément Stenac's avatar
Clément Stenac committed
34 35 36 37
#include <vlc_vout.h>
#include <vlc_block.h>
#include <vlc_filter.h>
#include <vlc_osd.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
38
#include "../libvlc.h"
39

40 41
#include <assert.h>

42 43 44 45 46 47
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static void UpdateSPU   ( spu_t *, vlc_object_t * );
static int  CropCallback( vlc_object_t *, char const *,
                          vlc_value_t, vlc_value_t, void * );
48

49 50
static int spu_vaControlDefault( spu_t *, int, va_list );

51 52
static subpicture_t *sub_new_buffer( filter_t * );
static void sub_del_buffer( filter_t *, subpicture_t * );
53 54
static subpicture_t *spu_new_buffer( filter_t * );
static void spu_del_buffer( filter_t *, subpicture_t * );
55 56
static picture_t *spu_new_video_buffer( filter_t * );
static void spu_del_video_buffer( filter_t *, picture_t * );
57

58 59 60 61
static int spu_ParseChain( spu_t * );
static int SubFilterCallback( vlc_object_t *, char const *,
                              vlc_value_t, vlc_value_t, void * );

62 63
static int sub_filter_allocation_init( filter_t *, void * );
static void sub_filter_allocation_clear( filter_t * );
64 65 66 67 68 69
struct filter_owner_sys_t
{
    spu_t *p_spu;
    int i_channel;
};

70 71 72 73 74
enum {
    SCALE_DEFAULT,
    SCALE_TEXT,
    SCALE_SIZE
};
75

76
/**
77
 * Creates the subpicture unit
78
 *
79
 * \param p_this the parent object which creates the subpicture unit
80
 */
81
spu_t *__spu_Create( vlc_object_t *p_this )
82 83
{
    int i_index;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
84 85
    spu_t *p_spu = vlc_custom_create( p_this, sizeof( spu_t ),
                                      VLC_OBJECT_GENERIC, "subpicture" );
86 87 88

    for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
    {
89
        p_spu->p_subpicture[i_index].i_status = FREE_SUBPICTURE;
90 91
    }

92 93 94
    p_spu->p_blend = NULL;
    p_spu->p_text = NULL;
    p_spu->p_scale = NULL;
95
    p_spu->pf_control = spu_vaControlDefault;
96 97

    /* Register the default subpicture channel */
98
    p_spu->i_channel = 2;
99

100
    vlc_mutex_init( &p_spu->subpicture_lock );
101

102 103
    vlc_object_attach( p_spu, p_this );

104 105 106 107
    p_spu->p_chain = filter_chain_New( p_spu, "sub filter", false,
                                       sub_filter_allocation_init,
                                       sub_filter_allocation_clear,
                                       p_spu );
108 109 110 111 112 113 114 115 116 117 118 119
    return p_spu;
}

/**
 * Initialise the subpicture unit
 *
 * \param p_spu the subpicture unit object
 */
int spu_Init( spu_t *p_spu )
{
    vlc_value_t val;

120 121 122
    /* If the user requested a sub margin, we force the position. */
    var_Create( p_spu, "sub-margin", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_spu, "sub-margin", &val );
123 124 125
    p_spu->i_margin = val.i_int;

    var_Create( p_spu, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
126 127 128 129
    var_AddCallback( p_spu, "sub-filter", SubFilterCallback, p_spu );

    spu_ParseChain( p_spu );

130
    return VLC_SUCCESS;
131
}
Antoine Cellerier's avatar
 
Antoine Cellerier committed
132

133 134
int spu_ParseChain( spu_t *p_spu )
{
135 136
    char *psz_parser = var_GetString( p_spu, "sub-filter" );
    if( filter_chain_AppendFromString( p_spu->p_chain, psz_parser ) < 0 )
137
    {
138 139
        free( psz_parser );
        return VLC_EGENERIC;
140
    }
141

142
    free( psz_parser );
143
    return VLC_SUCCESS;
144 145 146
}

/**
147
 * Destroy the subpicture unit
148
 *
149
 * \param p_this the parent object which destroys the subpicture unit
150
 */
151
void spu_Destroy( spu_t *p_spu )
152 153 154 155 156 157
{
    int i_index;

    /* Destroy all remaining subpictures */
    for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
    {
158
        if( p_spu->p_subpicture[i_index].i_status != FREE_SUBPICTURE )
159
        {
160
            spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] );
161 162 163
        }
    }

164
    if( p_spu->p_blend )
165
    {
166 167
        if( p_spu->p_blend->p_module )
            module_Unneed( p_spu->p_blend, p_spu->p_blend->p_module );
168

169
        vlc_object_detach( p_spu->p_blend );
170
        vlc_object_release( p_spu->p_blend );
171 172
    }

173
    if( p_spu->p_text )
174
    {
175 176
        if( p_spu->p_text->p_module )
            module_Unneed( p_spu->p_text, p_spu->p_text->p_module );
177

178
        vlc_object_detach( p_spu->p_text );
179
        vlc_object_release( p_spu->p_text );
180 181
    }

182 183 184 185 186 187
    if( p_spu->p_scale )
    {
        if( p_spu->p_scale->p_module )
            module_Unneed( p_spu->p_scale, p_spu->p_scale->p_module );

        vlc_object_detach( p_spu->p_scale );
188
        vlc_object_release( p_spu->p_scale );
189 190
    }

191
    filter_chain_Delete( p_spu->p_chain );
192 193

    vlc_mutex_destroy( &p_spu->subpicture_lock );
194
    vlc_object_release( p_spu );
195 196
}

197 198 199
/**
 * Attach/Detach the SPU from any input
 *
200
 * \param p_this the object in which to destroy the subpicture unit
201 202
 * \param b_attach to select attach or detach
 */
203
void spu_Attach( spu_t *p_spu, vlc_object_t *p_this, bool b_attach )
204 205 206
{
    vlc_object_t *p_input;

207
    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
208 209 210
    if( !p_input ) return;

    if( b_attach )
211
    {
212 213
        UpdateSPU( p_spu, VLC_OBJECT(p_input) );
        var_AddCallback( p_input, "highlight", CropCallback, p_spu );
214 215 216 217 218
        vlc_object_release( p_input );
    }
    else
    {
        /* Delete callback */
219
        var_DelCallback( p_input, "highlight", CropCallback, p_spu );
220 221 222 223 224 225 226 227 228 229
        vlc_object_release( p_input );
    }
}

/**
 * Create a subpicture region
 *
 * \param p_this vlc_object_t
 * \param p_fmt the format that this subpicture region should have
 */
230 231
static void RegionPictureRelease( picture_t *p_pic )
{
232
    free( p_pic->p_data_orig );
233
}
234 235 236 237
subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this,
                                         video_format_t *p_fmt )
{
    subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
238 239
    if( !p_region ) return NULL;

240
    memset( p_region, 0, sizeof(subpicture_region_t) );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
241
    p_region->i_alpha = 0xff;
242 243
    p_region->p_next = NULL;
    p_region->p_cache = NULL;
244
    p_region->fmt = *p_fmt;
245
    p_region->psz_text = NULL;
246
    p_region->p_style = NULL;
247 248 249 250 251 252

    if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') )
        p_fmt->p_palette = p_region->fmt.p_palette =
            malloc( sizeof(video_palette_t) );
    else p_fmt->p_palette = p_region->fmt.p_palette = NULL;

253
    p_region->picture.p_data_orig = NULL;
254 255

    if( p_fmt->i_chroma == VLC_FOURCC('T','E','X','T') ) return p_region;
256 257 258 259 260 261 262

    vout_AllocatePicture( p_this, &p_region->picture, p_fmt->i_chroma,
                          p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );

    if( !p_region->picture.i_planes )
    {
        free( p_region );
263
        free( p_fmt->p_palette );
264 265 266
        return NULL;
    }

267 268
    p_region->picture.pf_release = RegionPictureRelease;

269 270 271
    return p_region;
}

272 273 274 275 276 277 278 279 280 281 282 283
/**
 * Make a subpicture region from an existing picture_t
 *
 * \param p_this vlc_object_t
 * \param p_fmt the format that this subpicture region should have
 * \param p_pic a pointer to the picture creating the region (not freed)
 */
subpicture_region_t *__spu_MakeRegion( vlc_object_t *p_this,
                                       video_format_t *p_fmt,
                                       picture_t *p_pic )
{
    subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
284
    (void)p_this;
285
    if( !p_region ) return NULL;
286
    memset( p_region, 0, sizeof(subpicture_region_t) );
287
    p_region->i_alpha = 0xff;
288 289 290 291
    p_region->p_next = 0;
    p_region->p_cache = 0;
    p_region->fmt = *p_fmt;
    p_region->psz_text = 0;
292
    p_region->p_style = NULL;
293 294 295 296 297 298 299 300 301 302 303 304

    if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') )
        p_fmt->p_palette = p_region->fmt.p_palette =
            malloc( sizeof(video_palette_t) );
    else p_fmt->p_palette = p_region->fmt.p_palette = NULL;

    memcpy( &p_region->picture, p_pic, sizeof(picture_t) );
    p_region->picture.pf_release = RegionPictureRelease;

    return p_region;
}

305 306 307 308 309 310 311 312 313
/**
 * Destroy a subpicture region
 *
 * \param p_this vlc_object_t
 * \param p_region the subpicture region to destroy
 */
void __spu_DestroyRegion( vlc_object_t *p_this, subpicture_region_t *p_region )
{
    if( !p_region ) return;
314 315
    if( p_region->picture.pf_release )
        p_region->picture.pf_release( &p_region->picture );
316
    free( p_region->fmt.p_palette );
317
    if( p_region->p_cache ) __spu_DestroyRegion( p_this, p_region->p_cache );
318

319 320
    free( p_region->psz_text );
    free( p_region->psz_html );
321
    //free( p_region->p_style ); FIXME --fenrir plugin does not allocate the memory for it. I think it might lead to segfault, video renderer can live longer than the decoder
322 323
    free( p_region );
}
Sam Hocevar's avatar
 
Sam Hocevar committed
324

325
/**
326
 * Display a subpicture
327
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
328 329
 * Remove the reservation flag of a subpicture, which will cause it to be
 * ready for display.
330
 * \param p_spu the subpicture unit object
331 332
 * \param p_subpic the subpicture to display
 */
333
void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
Sam Hocevar's avatar
 
Sam Hocevar committed
334 335 336 337
{
    /* Check if status is valid */
    if( p_subpic->i_status != RESERVED_SUBPICTURE )
    {
338 339
        msg_Err( p_spu, "subpicture %p has invalid status #%d",
                 p_subpic, p_subpic->i_status );
Sam Hocevar's avatar
 
Sam Hocevar committed
340 341
    }

342 343
    /* Remove reservation flag */
    p_subpic->i_status = READY_SUBPICTURE;
Sam Hocevar's avatar
 
Sam Hocevar committed
344

345
    if( p_subpic->i_channel == DEFAULT_CHAN )
Sam Hocevar's avatar
 
Sam Hocevar committed
346
    {
347 348 349
        p_subpic->i_channel = 0xFFFF;
        spu_Control( p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN );
        p_subpic->i_channel = DEFAULT_CHAN;
Sam Hocevar's avatar
 
Sam Hocevar committed
350
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
351 352
}

353
/**
354
 * Allocate a subpicture in the spu heap.
355
 *
356
 * This function create a reserved subpicture in the spu heap.
Sam Hocevar's avatar
 
Sam Hocevar committed
357 358 359
 * A null pointer is returned if the function fails. This method provides an
 * already allocated zone of memory in the spu data fields. It needs locking
 * since several pictures can be created by several producers threads.
360
 * \param p_spu the subpicture unit in which to create the subpicture
361 362
 * \return NULL on error, a reserved subpicture otherwise
 */
363
subpicture_t *spu_CreateSubpicture( spu_t *p_spu )
Sam Hocevar's avatar
 
Sam Hocevar committed
364 365
{
    int                 i_subpic;                        /* subpicture index */
366
    subpicture_t *      p_subpic = NULL;            /* first free subpicture */
Sam Hocevar's avatar
 
Sam Hocevar committed
367

368
    /* Get lock */
369
    vlc_mutex_lock( &p_spu->subpicture_lock );
370

Sam Hocevar's avatar
 
Sam Hocevar committed
371 372 373
    /*
     * Look for an empty place
     */
374
    p_subpic = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
375 376
    for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
    {
377
        if( p_spu->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE )
Sam Hocevar's avatar
 
Sam Hocevar committed
378 379
        {
            /* Subpicture is empty and ready for allocation */
380 381
            p_subpic = &p_spu->p_subpicture[i_subpic];
            p_spu->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
382
            break;
Sam Hocevar's avatar
 
Sam Hocevar committed
383 384 385
        }
    }

386 387
    /* If no free subpicture could be found */
    if( p_subpic == NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
388
    {
389 390
        msg_Err( p_spu, "subpicture heap is full" );
        vlc_mutex_unlock( &p_spu->subpicture_lock );
391
        return NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
392
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
393

394
    /* Copy subpicture information, set some default values */
395 396
    memset( p_subpic, 0, sizeof(subpicture_t) );
    p_subpic->i_status   = RESERVED_SUBPICTURE;
397 398 399
    p_subpic->b_absolute = true;
    p_subpic->b_pausable = false;
    p_subpic->b_fade     = false;
400
    p_subpic->i_alpha    = 0xFF;
401 402 403 404
    p_subpic->p_region   = NULL;
    p_subpic->pf_render  = NULL;
    p_subpic->pf_destroy = NULL;
    p_subpic->p_sys      = NULL;
405
    vlc_mutex_unlock( &p_spu->subpicture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
406

407
    p_subpic->pf_create_region = __spu_CreateRegion;
408
    p_subpic->pf_make_region = __spu_MakeRegion;
409
    p_subpic->pf_destroy_region = __spu_DestroyRegion;
410

411
    return p_subpic;
Sam Hocevar's avatar
 
Sam Hocevar committed
412 413
}

414 415 416
/**
 * Remove a subpicture from the heap
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
417 418 419
 * This function frees a previously reserved subpicture.
 * It is meant to be used when the construction of a picture aborted.
 * This function does not need locking since reserved subpictures are ignored
420
 * by the spu.
421
 */
422
void spu_DestroySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
Sam Hocevar's avatar
 
Sam Hocevar committed
423
{
Gildas Bazin's avatar
 
Gildas Bazin committed
424
    /* Get lock */
425
    vlc_mutex_lock( &p_spu->subpicture_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
426 427 428 429

    /* There can be race conditions so we need to check the status */
    if( p_subpic->i_status == FREE_SUBPICTURE )
    {
430
        vlc_mutex_unlock( &p_spu->subpicture_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
431 432 433
        return;
    }

434 435 436 437
    /* Check if status is valid */
    if( ( p_subpic->i_status != RESERVED_SUBPICTURE )
           && ( p_subpic->i_status != READY_SUBPICTURE ) )
    {
438
        msg_Err( p_spu, "subpicture %p has invalid status %d",
439 440 441
                         p_subpic, p_subpic->i_status );
    }

442 443 444 445
    while( p_subpic->p_region )
    {
        subpicture_region_t *p_region = p_subpic->p_region;
        p_subpic->p_region = p_region->p_next;
446
        spu_DestroyRegion( p_spu, p_region );
447 448
    }

449 450 451 452 453 454
    if( p_subpic->pf_destroy )
    {
        p_subpic->pf_destroy( p_subpic );
    }

    p_subpic->i_status = FREE_SUBPICTURE;
Gildas Bazin's avatar
 
Gildas Bazin committed
455

456
    vlc_mutex_unlock( &p_spu->subpicture_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
457 458 459
}

/*****************************************************************************
460
 * spu_RenderSubpictures: render a subpicture list
Sam Hocevar's avatar
 
Sam Hocevar committed
461
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
462
 * This function renders all sub picture units in the list.
Sam Hocevar's avatar
 
Sam Hocevar committed
463
 *****************************************************************************/
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
static void SpuRenderCreateBlend( spu_t *p_spu, vlc_fourcc_t i_chroma, int i_aspect )
{
    filter_t *p_blend;

    assert( !p_spu->p_blend );

    p_spu->p_blend =
    p_blend        = vlc_custom_create( p_spu, sizeof(filter_t),
                                        VLC_OBJECT_GENERIC, "blend" );
    if( !p_blend )
        return;

    es_format_Init( &p_blend->fmt_in, VIDEO_ES, 0 );

    es_format_Init( &p_blend->fmt_out, VIDEO_ES, 0 );
    p_blend->fmt_out.video.i_x_offset = 0;
    p_blend->fmt_out.video.i_y_offset = 0;
    p_blend->fmt_out.video.i_chroma = i_chroma;
    p_blend->fmt_out.video.i_aspect = i_aspect;

    /* The blend module will be loaded when needed with the real
    * input format */
    p_blend->p_module = NULL;

    /* */
    vlc_object_attach( p_blend, p_spu );
}
static void SpuRenderUpdateBlend( spu_t *p_spu, const video_format_t *p_vfmt )
{
    filter_t *p_blend = p_spu->p_blend;

    assert( p_blend );

    /* */
    if( p_blend->p_module && p_blend->fmt_in.video.i_chroma != p_vfmt->i_chroma )
    {
        /* The chroma is not the same, we need to reload the blend module
         * XXX to match the old behaviour just test !p_blend->fmt_in.video.i_chroma */
        module_Unneed( p_blend, p_blend->p_module );
        p_blend->p_module = NULL;
    }

    /* */
    p_blend->fmt_in.video = *p_vfmt;

    /* */
    if( !p_blend->p_module )
        p_blend->p_module = module_Need( p_blend, "video blending", 0, 0 );
}
static void SpuRenderCreateAndLoadText( spu_t *p_spu, int i_width, int i_height )
{
    filter_t *p_text;

    assert( !p_spu->p_text );

    p_spu->p_text =
    p_text        = vlc_custom_create( p_spu, sizeof(filter_t),
                                       VLC_OBJECT_GENERIC, "spu text" );
    if( !p_text )
        return;

    es_format_Init( &p_text->fmt_in, VIDEO_ES, 0 );

    es_format_Init( &p_text->fmt_out, VIDEO_ES, 0 );
    p_text->fmt_out.video.i_width =
    p_text->fmt_out.video.i_visible_width = i_width;
    p_text->fmt_out.video.i_height =
    p_text->fmt_out.video.i_visible_height = i_height;

    p_text->pf_sub_buffer_new = spu_new_buffer;
    p_text->pf_sub_buffer_del = spu_del_buffer;

    vlc_object_attach( p_text, p_spu );

    /* FIXME TOCHECK shouldn't module_Need( , , psz_modulename, false ) do the
     * same than these 2 calls ? */
    char *psz_modulename = var_CreateGetString( p_spu, "text-renderer" );
    if( psz_modulename && *psz_modulename )
    {
        p_text->p_module = module_Need( p_text, "text renderer",
                                        psz_modulename, true );
    }
    free( psz_modulename );

    if( !p_text->p_module )
        p_text->p_module = module_Need( p_text, "text renderer", NULL, false );
}

static void SpuRenderCreateAndLoadScale( spu_t *p_spu )
{
    /* FIXME: We'll also be using it for YUVA and RGBA blending ... */
    const vlc_fourcc_t i_dummy_chroma = VLC_FOURCC('Y','U','V','P');

    filter_t *p_scale;

    assert( !p_spu->p_scale );

    p_spu->p_scale =
    p_scale        = vlc_custom_create( p_spu, sizeof(filter_t),
                                        VLC_OBJECT_GENERIC, "scale" );
    if( !p_scale )
        return;

    es_format_Init( &p_scale->fmt_in, VIDEO_ES, 0 );
    p_scale->fmt_in.video.i_chroma = i_dummy_chroma;
    p_scale->fmt_in.video.i_width =
    p_scale->fmt_in.video.i_height = 32;

    es_format_Init( &p_scale->fmt_out, VIDEO_ES, 0 );
    p_scale->fmt_out.video.i_chroma = i_dummy_chroma;
    p_scale->fmt_out.video.i_width =
    p_scale->fmt_out.video.i_height = 16;

    p_scale->pf_vout_buffer_new = spu_new_video_buffer;
    p_scale->pf_vout_buffer_del = spu_del_video_buffer;

    vlc_object_attach( p_scale, p_spu );
    p_scale->p_module = module_Need( p_spu->p_scale, "video filter2", 0, 0 );
}

Laurent Aimar's avatar
Laurent Aimar committed
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
//__MIN(i_scale_width_orig, i_scale_height_orig) );
static void SpuRenderText( spu_t *p_spu, bool *pb_rerender_text,
                           subpicture_t *p_subpic, subpicture_region_t *p_region, int i_min_scale_ratio )
{
    assert( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') );

    if( !p_spu->p_text || !p_spu->p_text->p_module )
        goto exit;

    /* Setup 3 variables which can be used to render
     * time-dependent text (and effects). The first indicates
     * the total amount of time the text will be on screen,
     * the second the amount of time it has already been on
     * screen (can be a negative value as text is layed out
     * before it is rendered) and the third is a feedback
     * variable from the renderer - if the renderer sets it
     * then this particular text is time-dependent, eg. the
     * visual progress bar inside the text in karaoke and the
     * text needs to be rendered multiple times in order for
     * the effect to work - we therefore need to return the
     * region to its original state at the end of the loop,
     * instead of leaving it in YUVA or YUVP.
     * Any renderer which is unaware of how to render
     * time-dependent text can happily ignore the variables
     * and render the text the same as usual - it should at
     * least show up on screen, but the effect won't change
     * the text over time.
     */

    /* FIXME why these variables are recreated every time and not
     * when text renderer module was created ? */
    var_Create( p_spu->p_text, "spu-duration", VLC_VAR_TIME );
    var_Create( p_spu->p_text, "spu-elapsed", VLC_VAR_TIME );
    var_Create( p_spu->p_text, "text-rerender", VLC_VAR_BOOL );
    var_Create( p_spu->p_text, "scale", VLC_VAR_INTEGER );

    var_SetTime( p_spu->p_text, "spu-duration", p_subpic->i_stop - p_subpic->i_start );
    var_SetTime( p_spu->p_text, "spu-elapsed", mdate() - p_subpic->i_start );
    var_SetBool( p_spu->p_text, "text-rerender", false );
    var_SetInteger( p_spu->p_text, "scale", i_min_scale_ratio );

    if( p_spu->p_text->pf_render_html && p_region->psz_html )
    {
        p_spu->p_text->pf_render_html( p_spu->p_text,
                                       p_region, p_region );
    }
    else if( p_spu->p_text->pf_render_text )
    {
        p_spu->p_text->pf_render_text( p_spu->p_text,
                                       p_region, p_region );
    }
    *pb_rerender_text = var_GetBool( p_spu->p_text, "text-rerender" );

    var_Destroy( p_spu->p_text, "spu-duration" );
    var_Destroy( p_spu->p_text, "spu-elapsed" );
    var_Destroy( p_spu->p_text, "text-rerender" );
    var_Destroy( p_spu->p_text, "scale" );

exit:
    p_region->i_align |= SUBPICTURE_RENDERED;
}

Laurent Aimar's avatar
Laurent Aimar committed
646 647 648 649 650 651 652 653 654
static void SpuRenderRegion( spu_t *p_spu,
                             picture_t *p_pic_dst, picture_t *p_pic_src,
                             subpicture_t *p_subpic, subpicture_region_t *p_region,
                             const int i_scale_width_orig, const int i_scale_height_orig,
                             const int pi_subpic_x[SCALE_SIZE],
                             const int pi_scale_width[SCALE_SIZE],
                             const int pi_scale_height[SCALE_SIZE],
                             const video_format_t *p_fmt )
{
Laurent Aimar's avatar
Laurent Aimar committed
655 656 657
    video_format_t orig_fmt;
    bool b_rerender_text;
    int i_fade_alpha;
Laurent Aimar's avatar
Laurent Aimar committed
658 659
    int i_x_offset;
    int i_y_offset;
Laurent Aimar's avatar
Laurent Aimar committed
660 661 662
    int i_scale_idx;
    int i_inv_scale_x;
    int i_inv_scale_y;
Laurent Aimar's avatar
Laurent Aimar committed
663

Laurent Aimar's avatar
Laurent Aimar committed
664 665
    orig_fmt = p_region->fmt;
    b_rerender_text = false;
Laurent Aimar's avatar
Laurent Aimar committed
666
    if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
Laurent Aimar's avatar
Laurent Aimar committed
667
        SpuRenderText( p_spu, &b_rerender_text, p_subpic, p_region, __MIN(i_scale_width_orig, i_scale_height_orig) );
Laurent Aimar's avatar
Laurent Aimar committed
668

Laurent Aimar's avatar
Laurent Aimar committed
669 670 671 672
    /* From now on, we can only process non text data */
    if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
        goto exit;

Laurent Aimar's avatar
Laurent Aimar committed
673 674
    if( p_region->i_align & SUBPICTURE_RENDERED )
    {
Laurent Aimar's avatar
Laurent Aimar committed
675
        /* We are using a region which come from rendered text */
Laurent Aimar's avatar
Laurent Aimar committed
676 677 678 679
        i_scale_idx   = SCALE_TEXT;
        i_inv_scale_x = i_scale_width_orig;
        i_inv_scale_y = i_scale_height_orig;
    }
Laurent Aimar's avatar
Laurent Aimar committed
680 681 682 683 684 685
    else
    {
        i_scale_idx   = SCALE_DEFAULT;
        i_inv_scale_x = 1000;
        i_inv_scale_y = 1000;
    }
Laurent Aimar's avatar
Laurent Aimar committed
686 687 688 689 690 691

    i_x_offset = (p_region->i_x + pi_subpic_x[ i_scale_idx ]) * i_inv_scale_x / 1000;
    i_y_offset = (p_region->i_y + p_subpic->i_y) * i_inv_scale_y / 1000;

    /* Force palette if requested */
    if( p_spu->b_force_palette &&
Laurent Aimar's avatar
Laurent Aimar committed
692
        p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','P') )
Laurent Aimar's avatar
Laurent Aimar committed
693
    {
Laurent Aimar's avatar
Laurent Aimar committed
694
        /* It looks so wrong I won't comment
Laurent Aimar's avatar
Laurent Aimar committed
695 696 697 698
         * p_palette->palette is [256][4] with a int i_entries
         * p_spu->palette is [4][4]
         * */
        memcpy( p_region->fmt.p_palette->palette, p_spu->palette, 16 );
Laurent Aimar's avatar
Laurent Aimar committed
699 700 701
    }

    /* Scale SPU if necessary */
Laurent Aimar's avatar
Laurent Aimar committed
702
    if( p_region->p_cache )
Laurent Aimar's avatar
Laurent Aimar committed
703 704 705 706 707 708 709 710
    {
        if( pi_scale_width[ i_scale_idx ] * p_region->fmt.i_width / 1000 !=
            p_region->p_cache->fmt.i_width ||
            pi_scale_height[ i_scale_idx ] * p_region->fmt.i_height / 1000 !=
            p_region->p_cache->fmt.i_height )
        {
            p_subpic->pf_destroy_region( VLC_OBJECT(p_spu),
                                         p_region->p_cache );
Laurent Aimar's avatar
Laurent Aimar committed
711
            p_region->p_cache = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
712 713 714
        }
    }

Laurent Aimar's avatar
Laurent Aimar committed
715 716 717
    if( p_spu->p_scale &&
        ( ( pi_scale_width[i_scale_idx]  > 0 && pi_scale_width[i_scale_idx]  != 1000 ) ||
          ( pi_scale_height[i_scale_idx] > 0 && pi_scale_height[i_scale_idx] != 1000 ) ) )
Laurent Aimar's avatar
Laurent Aimar committed
718
    {
Laurent Aimar's avatar
Laurent Aimar committed
719
        if( !p_region->p_cache )
Laurent Aimar's avatar
Laurent Aimar committed
720
        {
Laurent Aimar's avatar
Laurent Aimar committed
721 722 723 724 725 726 727 728 729 730 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
            picture_t *p_pic;

            p_spu->p_scale->fmt_in.video = p_region->fmt;
            p_spu->p_scale->fmt_out.video = p_region->fmt;

            p_region->p_cache =
                p_subpic->pf_create_region( VLC_OBJECT(p_spu),
                    &p_spu->p_scale->fmt_out.video );
            if( p_spu->p_scale->fmt_out.video.p_palette )
                *p_spu->p_scale->fmt_out.video.p_palette =
                    *p_region->fmt.p_palette;
            p_region->p_cache->p_next = p_region->p_next;

            vout_CopyPicture( p_spu, &p_region->p_cache->picture,
                              &p_region->picture );

            p_spu->p_scale->fmt_out.video.i_width =
                p_region->fmt.i_width * pi_scale_width[ i_scale_idx ] / 1000;
            p_spu->p_scale->fmt_out.video.i_visible_width =
                p_region->fmt.i_visible_width * pi_scale_width[ i_scale_idx ] / 1000;
            p_spu->p_scale->fmt_out.video.i_height =
                p_region->fmt.i_height * pi_scale_height[ i_scale_idx ] / 1000;
            p_spu->p_scale->fmt_out.video.i_visible_height =
                p_region->fmt.i_visible_height * pi_scale_height[ i_scale_idx ] / 1000;
            p_region->p_cache->fmt = p_spu->p_scale->fmt_out.video;
            p_region->p_cache->i_x = p_region->i_x * pi_scale_width[ i_scale_idx ] / 1000;
            p_region->p_cache->i_y = p_region->i_y * pi_scale_height[ i_scale_idx ] / 1000;
            p_region->p_cache->i_align = p_region->i_align;
            p_region->p_cache->i_alpha = p_region->i_alpha;

            p_pic = p_spu->p_scale->pf_video_filter(
                             p_spu->p_scale, &p_region->p_cache->picture );
            if( p_pic )
            {
                picture_t p_pic_tmp = p_region->p_cache->picture;
                p_region->p_cache->picture = *p_pic;
                *p_pic = p_pic_tmp;
                free( p_pic );
            }
Laurent Aimar's avatar
Laurent Aimar committed
760 761
        }

Laurent Aimar's avatar
Laurent Aimar committed
762 763
        if( p_region->p_cache )
            p_region = p_region->p_cache;
Laurent Aimar's avatar
Laurent Aimar committed
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
    }

    if( p_region->i_align & SUBPICTURE_ALIGN_BOTTOM )
    {
        i_y_offset = p_fmt->i_height - p_region->fmt.i_height -
            (p_subpic->i_y + p_region->i_y) * i_inv_scale_y / 1000;
    }
    else if ( !(p_region->i_align & SUBPICTURE_ALIGN_TOP) )
    {
        i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2;
    }

    if( p_region->i_align & SUBPICTURE_ALIGN_RIGHT )
    {
        i_x_offset = p_fmt->i_width - p_region->fmt.i_width -
            (pi_subpic_x[ i_scale_idx ] + p_region->i_x)
            * i_inv_scale_x / 1000;
    }
    else if ( !(p_region->i_align & SUBPICTURE_ALIGN_LEFT) )
    {
        i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2;
    }

    if( p_subpic->b_absolute )
    {
        i_x_offset = (p_region->i_x +
            pi_subpic_x[ i_scale_idx ] *
                             pi_scale_width[ i_scale_idx ] / 1000)
            * i_inv_scale_x / 1000;
        i_y_offset = (p_region->i_y +
            p_subpic->i_y * pi_scale_height[ i_scale_idx ] / 1000)
            * i_inv_scale_y / 1000;

    }

    i_x_offset = __MAX( i_x_offset, 0 );
    i_y_offset = __MAX( i_y_offset, 0 );

Laurent Aimar's avatar
Laurent Aimar committed
802
    if( p_spu->i_margin != 0 && !p_spu->b_force_crop )
Laurent Aimar's avatar
Laurent Aimar committed
803 804 805 806 807 808 809 810 811 812 813 814 815
    {
        int i_diff = 0;
        int i_low = (i_y_offset - p_spu->i_margin) * i_inv_scale_y / 1000;
        int i_high = i_low + p_region->fmt.i_height;

        /* crop extra margin to keep within bounds */
        if( i_low < 0 )
            i_diff = i_low;
        if( i_high > (int)p_fmt->i_height )
            i_diff = i_high - p_fmt->i_height;
        i_y_offset -= ( p_spu->i_margin * i_inv_scale_y / 1000 + i_diff );
    }

Laurent Aimar's avatar
Laurent Aimar committed
816
    i_fade_alpha = 255;
Laurent Aimar's avatar
Laurent Aimar committed
817 818 819 820 821 822 823 824 825 826 827 828
    if( p_subpic->b_fade )
    {
        mtime_t i_fade_start = ( p_subpic->i_stop +
                                 p_subpic->i_start ) / 2;
        mtime_t i_now = mdate();
        if( i_now >= i_fade_start && p_subpic->i_stop > i_fade_start )
        {
            i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
                           ( p_subpic->i_stop - i_fade_start );
        }
    }

Laurent Aimar's avatar
Laurent Aimar committed
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
    /* */
    SpuRenderUpdateBlend( p_spu, &p_region->fmt );

    /* Force cropping if requested */
    if( p_spu->b_force_crop )
    {
        video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video;
        int i_crop_x = p_spu->i_crop_x * pi_scale_width[ i_scale_idx ] / 1000
                            * i_inv_scale_x / 1000;
        int i_crop_y = p_spu->i_crop_y * pi_scale_height[ i_scale_idx ] / 1000
                            * i_inv_scale_y / 1000;
        int i_crop_width = p_spu->i_crop_width * pi_scale_width[ i_scale_idx ] / 1000
                            * i_inv_scale_x / 1000;
        int i_crop_height = p_spu->i_crop_height * pi_scale_height[ i_scale_idx ] / 1000
                            * i_inv_scale_y / 1000;

        /* Find the intersection */
        if( i_crop_x + i_crop_width <= i_x_offset ||
            i_x_offset + (int)p_fmt->i_visible_width < i_crop_x ||
            i_crop_y + i_crop_height <= i_y_offset ||
            i_y_offset + (int)p_fmt->i_visible_height < i_crop_y )
Laurent Aimar's avatar
Laurent Aimar committed
850
        {
Laurent Aimar's avatar
Laurent Aimar committed
851 852
            /* No intersection */
            p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
Laurent Aimar's avatar
Laurent Aimar committed
853 854 855
        }
        else
        {
Laurent Aimar's avatar
Laurent Aimar committed
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
            int i_x, i_y, i_x_end, i_y_end;
            i_x = __MAX( i_crop_x, i_x_offset );
            i_y = __MAX( i_crop_y, i_y_offset );
            i_x_end = __MIN( i_crop_x + i_crop_width,
                           i_x_offset + (int)p_fmt->i_visible_width );
            i_y_end = __MIN( i_crop_y + i_crop_height,
                           i_y_offset + (int)p_fmt->i_visible_height );

            p_fmt->i_x_offset = i_x - i_x_offset;
            p_fmt->i_y_offset = i_y - i_y_offset;
            p_fmt->i_visible_width = i_x_end - i_x;
            p_fmt->i_visible_height = i_y_end - i_y;

            i_x_offset = i_x;
            i_y_offset = i_y;
Laurent Aimar's avatar
Laurent Aimar committed
871 872 873
        }
    }

Laurent Aimar's avatar
Laurent Aimar committed
874 875 876 877 878
    i_x_offset = __MAX( i_x_offset, 0 );
    i_y_offset = __MAX( i_y_offset, 0 );

    /* Update the output picture size */
    p_spu->p_blend->fmt_out.video.i_width =
Laurent Aimar's avatar
Laurent Aimar committed
879
    p_spu->p_blend->fmt_out.video.i_visible_width = p_fmt->i_width;
Laurent Aimar's avatar
Laurent Aimar committed
880
    p_spu->p_blend->fmt_out.video.i_height =
Laurent Aimar's avatar
Laurent Aimar committed
881
    p_spu->p_blend->fmt_out.video.i_visible_height = p_fmt->i_height;
Laurent Aimar's avatar
Laurent Aimar committed
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896

    if( p_spu->p_blend->p_module )
    {
        p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
            p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
            i_fade_alpha * p_subpic->i_alpha * p_region->i_alpha / 65025 );
    }
    else
    {
        msg_Err( p_spu, "blending %4.4s to %4.4s failed",
                 (char *)&p_spu->p_blend->fmt_out.video.i_chroma,
                 (char *)&p_spu->p_blend->fmt_out.video.i_chroma );
    }

exit:
Laurent Aimar's avatar
Laurent Aimar committed
897 898 899 900 901 902 903 904 905 906 907 908 909
    if( b_rerender_text )
    {
        /* Some forms of subtitles need to be re-rendered more than
         * once, eg. karaoke. We therefore restore the region to its
         * pre-rendered state, so the next time through everything is
         * calculated again.
         */
        p_region->picture.pf_release( &p_region->picture );
        memset( &p_region->picture, 0, sizeof( picture_t ) );
        p_region->fmt = orig_fmt;
        p_region->i_align &= ~SUBPICTURE_RENDERED;
    }
}
910

911 912 913
void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
                            picture_t *p_pic_dst, picture_t *p_pic_src,
                            subpicture_t *p_subpic,
914
                            int i_scale_width_orig, int i_scale_height_orig )
Sam Hocevar's avatar
 
Sam Hocevar committed
915
{
916 917
    int i_source_video_width;
    int i_source_video_height;
Laurent Aimar's avatar
Laurent Aimar committed
918
    subpicture_t *p_subpic_v;
919

Gildas Bazin's avatar
 
Gildas Bazin committed
920
    /* Get lock */
921
    vlc_mutex_lock( &p_spu->subpicture_lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
922

923 924 925 926 927 928 929 930 931 932
    for( p_subpic_v = p_subpic;
            p_subpic_v != NULL && p_subpic_v->i_status != FREE_SUBPICTURE;
            p_subpic_v = p_subpic_v->p_next )
    {
        if( p_subpic_v->pf_pre_render )
        {
            p_subpic_v->pf_pre_render( p_fmt, p_spu, p_subpic_v, mdate() );
        }
    }

933
    if( i_scale_width_orig <= 0 )
Laurent Aimar's avatar
Laurent Aimar committed
934
        i_scale_width_orig = 1000;
935
    if( i_scale_height_orig <= 0 )
Laurent Aimar's avatar
Laurent Aimar committed
936
        i_scale_height_orig = 1000;
937 938 939 940

    i_source_video_width  = p_fmt->i_width  * 1000 / i_scale_width_orig;
    i_source_video_height = p_fmt->i_height * 1000 / i_scale_height_orig;

Gildas Bazin's avatar
 
Gildas Bazin committed
941
    /* Check i_status again to make sure spudec hasn't destroyed the subpic */
Laurent Aimar's avatar
Laurent Aimar committed
942
    for( ; ( p_subpic != NULL ) && ( p_subpic->i_status != FREE_SUBPICTURE ); p_subpic = p_subpic->p_next )
Sam Hocevar's avatar
 
Sam Hocevar committed
943
    {
944
        subpicture_region_t *p_region;
945 946 947 948 949
        int pi_scale_width[ SCALE_SIZE ];
        int pi_scale_height[ SCALE_SIZE ];
        int pi_subpic_x[ SCALE_SIZE ];
        int k;

950 951 952 953 954 955 956 957 958 959 960
        /* If the source video and subtitles stream agree on the size of
         * the video then disregard all further references to the subtitle
         * stream.
         */
        if( ( i_source_video_height == p_subpic->i_original_picture_height ) &&
            ( i_source_video_width  == p_subpic->i_original_picture_width ) )
        {
            p_subpic->i_original_picture_height = 0;
            p_subpic->i_original_picture_width = 0;
        }

961
        for( k = 0; k < SCALE_SIZE ; k++ )
962
            pi_subpic_x[ k ] = p_subpic->i_x;
963

964 965
        if( p_subpic->pf_update_regions )
        {
966 967 968
            /* FIXME that part look like crap too if there is more than 1 region */

            if( p_subpic->p_region )
969
                spu_DestroyRegion( p_spu, p_subpic->p_region );
970 971 972 973 974 975 976 977 978 979

            /* TODO do not reverse the scaling that was done before calling
             * spu_RenderSubpictures, just pass it along (or do it inside
             * spu_RenderSubpictures) */
            video_format_t fmt_org = *p_fmt;
            fmt_org.i_width =
            fmt_org.i_visible_width = i_source_video_width;
            fmt_org.i_height =
            fmt_org.i_visible_height = i_source_video_height;

980
            p_subpic->p_region = p_subpic->pf_update_regions( &fmt_org, p_spu, p_subpic, mdate() );
981 982
        }

983 984 985 986 987
        /* */
        p_region = p_subpic->p_region;
        if( !p_region )
            continue;

988
        /* Create the blending module */
989
        if( !p_spu->p_blend )
990
            SpuRenderCreateBlend( p_spu, p_fmt->i_chroma, p_fmt->i_aspect );
991

992 993 994 995
        /* Load the text rendering module; it is possible there is a
         * text region somewhere in the subpicture other than the first
         * element in the region list, so just load it anyway as we'll
         * probably want it sooner or later. */
996
        if( !p_spu->p_text )
997
            SpuRenderCreateAndLoadText( p_spu, p_fmt->i_width, p_fmt->i_height );
998

999
        if( p_spu->p_text )
1000
        {
1001 1002
            subpicture_region_t *p_text_region = p_subpic->p_region;

1003 1004 1005 1006 1007 1008 1009
            /* Only overwrite the size fields if the region is still in
             * pre-rendered TEXT format. We have to traverse the subregion
             * list because if more than one subregion is present, the text
             * region isn't guarentteed to be the first in the list, and
             * only text regions use this flag. All of this effort assists
             * with the rescaling of text that has been rendered at native
             * resolution, rather than video resolution.
1010 1011
             */
            while( p_text_region &&
1012
                   p_text_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') )
1013
            {
1014
                p_text_region = p_text_region->p_next;
1015
            }
1016

1017
            if( p_text_region &&
1018
                ( ( p_text_region->i_align & SUBPICTURE_RENDERED ) == 0 ) )
1019
            {
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
                if( (p_subpic->i_original_picture_height > 0) &&
                    (p_subpic->i_original_picture_width  > 0) )
                {
                    p_spu->p_text->fmt_out.video.i_width =
                        p_spu->p_text->fmt_out.video.i_visible_width =
                        p_subpic->i_original_picture_width;
                    p_spu->p_text->fmt_out.video.i_height =
                        p_spu->p_text->fmt_out.video.i_visible_height =
                        p_subpic->i_original_picture_height;
                }
                else
                {
                    p_spu->p_text->fmt_out.video.i_width =
                        p_spu->p_text->fmt_out.video.i_visible_width =
                        p_fmt->i_width;
                    p_spu->p_text->fmt_out.video.i_height =
                        p_spu->p_text->fmt_out.video.i_visible_height =
                        p_fmt->i_height;
                }
1039
            }
Laurent Aimar's avatar
Laurent Aimar committed
1040 1041 1042 1043 1044 1045

            /* */
            pi_scale_width[SCALE_TEXT] = p_fmt->i_width * 1000 /
                                          p_spu->p_text->fmt_out.video.i_width;
            pi_scale_height[SCALE_TEXT]= p_fmt->i_height * 1000 /
                                          p_spu->p_text->fmt_out.video.i_height;
1046
        }
1047

1048 1049
        pi_scale_width[ SCALE_DEFAULT ]  = i_scale_width_orig;
        pi_scale_height[ SCALE_DEFAULT ] = i_scale_height_orig;
1050

1051 1052 1053 1054 1055 1056
        /* If we have an explicit size plane to render to, then turn off
         * the fontsize rescaling.
         */
        if( (p_subpic->i_original_picture_height > 0) &&
            (p_subpic->i_original_picture_width  > 0) )
        {
1057
#if 1
Laurent Aimar's avatar
Laurent Aimar committed
1058
            /* FIXME That seems so wrong */
1059 1060
            i_scale_width_orig  = 1000;
            i_scale_height_orig = 1000;
1061 1062
#else
            /* It is probably that :*/
Laurent Aimar's avatar
Laurent Aimar committed
1063 1064
            pi_scale_width[ SCALE_DEFAULT ]  = i_scale_width_orig * i_source_video_width / p_subpic->i_original_picture_width;
            pi_scale_height[ SCALE_DEFAULT ] = i_scale_height_orig * i_source_video_height / p_subpic->i_original_picture_height;
1065
#endif
1066
        }
1067 1068

        for( k = 0; k < SCALE_SIZE ; k++ )
1069
        {
1070 1071 1072
            /* Case of both width and height being specified has been dealt
             * with above by instead rendering to an output pane of the
             * explicit dimensions specified - we don't need to scale it.
1073
             */
1074
            if( (p_subpic->i_original_picture_height > 0) &&
Jean-Paul Saman's avatar
Jean-Paul Saman committed
1075
                (p_subpic->i_original_picture_width <= 0) )
1076 1077 1078 1079 1080 1081
            {
                pi_scale_height[ k ] = pi_scale_height[ k ] * i_source_video_height /
                                 p_subpic->i_original_picture_height;
                pi_scale_width[ k ]  = pi_scale_width[ k ]  * i_source_video_height /
                                 p_subpic->i_original_picture_height;
            }
1082
        }
1083

1084
        /* Set default subpicture aspect ratio */
1085
        if( p_region->fmt.i_aspect && ( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den ) )
1086
        {
1087 1088 1089
            p_region->fmt.i_sar_den = p_region->fmt.i_aspect;
            p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR;
        }
1090
        if( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den )
1091