decoder.c 62.3 KB
Newer Older
1
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
2
 * decoder.c: Functions for the management of decoders
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 1999-2004 VLC authors and VideoLAN
5
 * $Id$
6 7
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
Laurent Aimar's avatar
Laurent Aimar committed
9
 *          Laurent Aimar <fenrir@via.ecp.fr>
10
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
11 12 13
 * 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
14
 * (at your option) any later version.
15
 *
16 17
 * 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
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
20
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
21 22 23
 * 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.
24 25 26 27 28
 *****************************************************************************/

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

34
#include <vlc_common.h>
Laurent Aimar's avatar
Laurent Aimar committed
35

36
#include <vlc_atomic.h>
Clément Stenac's avatar
Clément Stenac committed
37 38 39 40 41
#include <vlc_block.h>
#include <vlc_vout.h>
#include <vlc_aout.h>
#include <vlc_sout.h>
#include <vlc_codec.h>
42
#include <vlc_spu.h>
Laurent Aimar's avatar
Laurent Aimar committed
43
#include <vlc_meta.h>
44
#include <vlc_dialog.h>
45
#include <vlc_modules.h>
Clément Stenac's avatar
Clément Stenac committed
46 47 48

#include "audio_output/aout_internal.h"
#include "stream_output/stream_output.h"
Laurent Aimar's avatar
Laurent Aimar committed
49
#include "input_internal.h"
50 51
#include "clock.h"
#include "decoder.h"
Christophe Mutricy's avatar
Christophe Mutricy committed
52
#include "event.h"
53
#include "resource.h"
54

55
#include "../video_output/vout_control.h"
Laurent Aimar's avatar
Laurent Aimar committed
56

57 58
struct decoder_owner_sys_t
{
Laurent Aimar's avatar
Laurent Aimar committed
59 60
    int64_t         i_preroll_end;

61
    input_thread_t  *p_input;
62
    input_resource_t*p_resource;
63
    input_clock_t   *p_clock;
64
    int             i_last_rate;
65

66 67
    vout_thread_t   *p_spu_vout;
    int              i_spu_channel;
68
    int64_t          i_spu_order;
69

70 71
    sout_instance_t         *p_sout;
    sout_packetizer_input_t *p_sout_input;
72

73 74
    vlc_thread_t     thread;

75 76
    /* Some decoders require already packetized data (ie. not truncated) */
    decoder_t *p_packetizer;
77
    bool b_packetizer;
78

79
    /* Current format in use by the output */
80
    es_format_t    fmt;
81

82 83
    /* */
    bool           b_fmt_description;
Laurent Aimar's avatar
Laurent Aimar committed
84
    vlc_meta_t     *p_description;
85

86 87
    /* fifo */
    block_fifo_t *p_fifo;
88

89 90
    /* Lock for communication with decoder thread */
    vlc_mutex_t lock;
91 92
    vlc_cond_t  wait_request;
    vlc_cond_t  wait_acknowledge;
93
    vlc_cond_t  wait_fifo; /* TODO: merge with wait_acknowledge */
94

Laurent Aimar's avatar
Laurent Aimar committed
95
    /* -- These variables need locking on write(only) -- */
96
    audio_output_t *p_aout;
Laurent Aimar's avatar
Laurent Aimar committed
97 98 99 100 101

    vout_thread_t   *p_vout;

    /* -- Theses variables need locking on read *and* write -- */
    /* Pause */
102 103 104
    mtime_t pause_date;
    unsigned frames_countdown;
    bool paused;
105

106 107 108 109
    /* Waiting */
    bool b_waiting;
    bool b_first;
    bool b_has_data;
110

Laurent Aimar's avatar
Laurent Aimar committed
111
    /* Flushing */
112
    bool flushing;
113
    bool b_draining;
114
    atomic_bool drained;
115
    bool b_idle;
Laurent Aimar's avatar
Laurent Aimar committed
116

117
    /* CC */
118 119 120 121 122 123
    struct
    {
        bool b_supported;
        bool pb_present[4];
        decoder_t *pp_decoder[4];
    } cc;
124 125 126

    /* Delay */
    mtime_t i_ts_delay;
127 128
};

129 130 131 132 133 134 135
/* Pictures which are DECODER_BOGUS_VIDEO_DELAY or more in advance probably have
 * a bogus PTS and won't be displayed */
#define DECODER_BOGUS_VIDEO_DELAY                ((mtime_t)(DEFAULT_PTS_DELAY * 30))

/* */
#define DECODER_SPU_VOUT_WAIT_DURATION ((int)(0.200*CLOCK_FREQ))

136 137 138 139 140 141 142 143 144 145 146 147 148 149
/**
 * Load a decoder module
 */
static int LoadDecoder( decoder_t *p_dec, bool b_packetizer,
                        const es_format_t *restrict p_fmt )
{
    p_dec->b_frame_drop_allowed = true;
    p_dec->i_extra_picture_buffers = 0;

    p_dec->pf_decode_audio = NULL;
    p_dec->pf_decode_video = NULL;
    p_dec->pf_decode_sub = NULL;
    p_dec->pf_get_cc = NULL;
    p_dec->pf_packetize = NULL;
150
    p_dec->pf_flush = NULL;
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

    es_format_Copy( &p_dec->fmt_in, p_fmt );
    es_format_Init( &p_dec->fmt_out, UNKNOWN_ES, 0 );

    /* Find a suitable decoder/packetizer module */
    if( !b_packetizer )
        p_dec->p_module = module_need( p_dec, "decoder", "$codec", false );
    else
        p_dec->p_module = module_need( p_dec, "packetizer", "$packetizer", false );

    if( !p_dec->p_module )
    {
        es_format_Clean( &p_dec->fmt_in );
        return -1;
    }
    else
        return 0;
}

/**
 * Unload a decoder module
 */
static void UnloadDecoder( decoder_t *p_dec )
{
    if( p_dec->p_module )
    {
        module_unneed( p_dec, p_dec->p_module );
        p_dec->p_module = NULL;
    }

    if( p_dec->p_description )
    {
        vlc_meta_Delete( p_dec->p_description );
        p_dec->p_description = NULL;
    }

    es_format_Clean( &p_dec->fmt_in );
    es_format_Clean( &p_dec->fmt_out );
189
    p_dec->b_error = false;
190 191
}

192
static void DecoderUpdateFormatLocked( decoder_t *p_dec )
193
{
194
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
195

196
    vlc_assert_locked( &p_owner->lock );
197

198 199
    es_format_Clean( &p_owner->fmt );
    es_format_Copy( &p_owner->fmt, &p_dec->fmt_out );
200

201
    /* Move p_description */
202 203 204 205 206 207 208 209 210
    if( p_dec->p_description != NULL )
    {
        if( p_owner->p_description != NULL )
            vlc_meta_Delete( p_owner->p_description );
        p_owner->p_description = p_dec->p_description;
        p_dec->p_description = NULL;
    }

    p_owner->b_fmt_description = true;
211 212
}

213
static block_t *DecoderBlockFlushNew()
214
{
215 216 217
    block_t *p_null = block_Alloc( 128 );
    if( !p_null )
        return NULL;
218

219
    p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY |
220
                       BLOCK_FLAG_CORRUPTED;
221
    memset( p_null->p_buffer, 0, p_null->i_buffer );
222

223 224
    return p_null;
}
225

226 227 228 229 230
/*****************************************************************************
 * Buffers allocation callbacks for the decoders
 *****************************************************************************/
static vout_thread_t *aout_request_vout( void *p_private,
                                         vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recyle )
231
{
232
    decoder_t *p_dec = p_private;
233
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
234
    input_thread_t *p_input = p_owner->p_input;
235

236 237 238 239
    p_vout = input_resource_RequestVout( p_owner->p_resource, p_vout, p_fmt, 1,
                                         b_recyle );
    if( p_input != NULL )
        input_SendEventVout( p_input );
240

241
    return p_vout;
242
}
Clément Stenac's avatar
Clément Stenac committed
243

244
static int aout_update_format( decoder_t *p_dec )
245
{
246 247
    decoder_owner_sys_t *p_owner = p_dec->p_owner;

248 249
    if( p_owner->p_aout
     && !AOUT_FMTS_IDENTICAL(&p_dec->fmt_out.audio, &p_owner->fmt.audio) )
250
    {
251
        audio_output_t *p_aout = p_owner->p_aout;
252

253 254 255
        /* Parameters changed, restart the aout */
        vlc_mutex_lock( &p_owner->lock );
        p_owner->p_aout = NULL;
256
        vlc_mutex_unlock( &p_owner->lock );
257
        aout_DecDelete( p_aout );
258

259
        input_resource_PutAout( p_owner->p_resource, p_aout );
260
    }
261

262
    if( p_owner->p_aout == NULL )
263
    {
264
        p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
265

266 267
        audio_sample_format_t format = p_dec->fmt_out.audio;
        aout_FormatPrepare( &format );
268

269 270 271 272
        const int i_force_dolby = var_InheritInteger( p_dec, "force-dolby-surround" );
        if( i_force_dolby &&
            (format.i_original_channels&AOUT_CHAN_PHYSMASK) ==
                (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) )
273
        {
274 275 276 277 278 279 280 281 282 283
            if( i_force_dolby == 1 )
            {
                format.i_original_channels = format.i_original_channels |
                                             AOUT_CHAN_DOLBYSTEREO;
            }
            else /* i_force_dolby == 2 */
            {
                format.i_original_channels = format.i_original_channels &
                                             ~AOUT_CHAN_DOLBYSTEREO;
            }
284
        }
285

286 287 288 289 290
        aout_request_vout_t request_vout = {
            .pf_request_vout = aout_request_vout,
            .p_private = p_dec,
        };
        audio_output_t *p_aout;
Laurent Aimar's avatar
Laurent Aimar committed
291

292 293
        p_aout = input_resource_GetAout( p_owner->p_resource );
        if( p_aout )
Laurent Aimar's avatar
Laurent Aimar committed
294
        {
295 296 297
            if( aout_DecNew( p_aout, &format,
                             &p_dec->fmt_out.audio_replay_gain,
                             &request_vout ) )
Laurent Aimar's avatar
Laurent Aimar committed
298
            {
299 300
                input_resource_PutAout( p_owner->p_resource, p_aout );
                p_aout = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
301 302
            }
        }
303

304 305
        vlc_mutex_lock( &p_owner->lock );
        p_owner->p_aout = p_aout;
306

307
        DecoderUpdateFormatLocked( p_dec );
308
        aout_FormatPrepare( &p_owner->fmt.audio );
309
        vlc_mutex_unlock( &p_owner->lock );
310

311 312
        if( p_owner->p_input != NULL )
            input_SendEventAout( p_owner->p_input );
313

314 315 316 317 318 319
        if( p_aout == NULL )
        {
            msg_Err( p_dec, "failed to create audio output" );
            p_dec->b_error = true;
            return -1;
        }
Laurent Aimar's avatar
Laurent Aimar committed
320

321 322 323 324
        p_dec->fmt_out.audio.i_bytes_per_frame =
            p_owner->fmt.audio.i_bytes_per_frame;
        p_dec->fmt_out.audio.i_frame_length =
            p_owner->fmt.audio.i_frame_length;
325
    }
326
    return 0;
Laurent Aimar's avatar
Laurent Aimar committed
327 328
}

329
static int vout_update_format( decoder_t *p_dec )
Sam Hocevar's avatar
 
Sam Hocevar committed
330
{
331
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
332

333 334 335 336 337 338 339 340 341 342 343
    if( p_owner->p_vout == NULL
     || p_dec->fmt_out.video.i_width != p_owner->fmt.video.i_width
     || p_dec->fmt_out.video.i_height != p_owner->fmt.video.i_height
     || p_dec->fmt_out.video.i_visible_width != p_owner->fmt.video.i_visible_width
     || p_dec->fmt_out.video.i_visible_height != p_owner->fmt.video.i_visible_height
     || p_dec->fmt_out.video.i_x_offset != p_owner->fmt.video.i_x_offset
     || p_dec->fmt_out.video.i_y_offset != p_owner->fmt.video.i_y_offset
     || p_dec->fmt_out.i_codec != p_owner->fmt.video.i_chroma
     || (int64_t)p_dec->fmt_out.video.i_sar_num * p_owner->fmt.video.i_sar_den !=
        (int64_t)p_dec->fmt_out.video.i_sar_den * p_owner->fmt.video.i_sar_num ||
        p_dec->fmt_out.video.orientation != p_owner->fmt.video.orientation )
344
    {
345
        vout_thread_t *p_vout;
Laurent Aimar's avatar
Laurent Aimar committed
346

347 348 349 350 351 352
        if( !p_dec->fmt_out.video.i_width ||
            !p_dec->fmt_out.video.i_height )
        {
            /* Can't create a new vout without display size */
            return -1;
        }
353

354 355 356 357 358 359 360
        video_format_t fmt = p_dec->fmt_out.video;
        fmt.i_chroma = p_dec->fmt_out.i_codec;

        if( vlc_fourcc_IsYUV( fmt.i_chroma ) )
        {
            const vlc_chroma_description_t *dsc = vlc_fourcc_GetChromaDescription( fmt.i_chroma );
            for( unsigned int i = 0; dsc && i < dsc->plane_count; i++ )
361
            {
362 363 364 365
                while( fmt.i_width % dsc->p[i].w.den )
                    fmt.i_width++;
                while( fmt.i_height % dsc->p[i].h.den )
                    fmt.i_height++;
366 367 368
            }
        }

369
        if( !fmt.i_visible_width || !fmt.i_visible_height )
370
        {
371 372
            if( p_dec->fmt_in.video.i_visible_width &&
                p_dec->fmt_in.video.i_visible_height )
373
            {
374 375 376 377
                fmt.i_visible_width  = p_dec->fmt_in.video.i_visible_width;
                fmt.i_visible_height = p_dec->fmt_in.video.i_visible_height;
                fmt.i_x_offset       = p_dec->fmt_in.video.i_x_offset;
                fmt.i_y_offset       = p_dec->fmt_in.video.i_y_offset;
378
            }
379
            else
380
            {
381 382 383 384
                fmt.i_visible_width  = fmt.i_width;
                fmt.i_visible_height = fmt.i_height;
                fmt.i_x_offset       = 0;
                fmt.i_y_offset       = 0;
385 386
            }
        }
387

388 389 390 391 392 393 394 395 396 397 398
        if( fmt.i_visible_height == 1088 &&
            var_CreateGetBool( p_dec, "hdtv-fix" ) )
        {
            fmt.i_visible_height = 1080;
            if( !(fmt.i_sar_num % 136))
            {
                fmt.i_sar_num *= 135;
                fmt.i_sar_den *= 136;
            }
            msg_Warn( p_dec, "Fixing broken HDTV stream (display_height=1088)");
        }
399

400 401 402 403 404
        if( !fmt.i_sar_num || !fmt.i_sar_den )
        {
            fmt.i_sar_num = 1;
            fmt.i_sar_den = 1;
        }
405

406 407
        vlc_ureduce( &fmt.i_sar_num, &fmt.i_sar_den,
                     fmt.i_sar_num, fmt.i_sar_den, 50000 );
408

409
        vlc_mutex_lock( &p_owner->lock );
410

411 412 413
        p_vout = p_owner->p_vout;
        p_owner->p_vout = NULL;
        vlc_mutex_unlock( &p_owner->lock );
414

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
        unsigned dpb_size;
        switch( p_dec->fmt_in.i_codec )
        {
        case VLC_CODEC_HEVC:
        case VLC_CODEC_H264:
        case VLC_CODEC_DIRAC: /* FIXME valid ? */
            dpb_size = 18;
            break;
        case VLC_CODEC_VP5:
        case VLC_CODEC_VP6:
        case VLC_CODEC_VP6F:
        case VLC_CODEC_VP8:
            dpb_size = 3;
            break;
        default:
            dpb_size = 2;
            break;
        }
        p_vout = input_resource_RequestVout( p_owner->p_resource,
                                             p_vout, &fmt,
                                             dpb_size +
                                             p_dec->i_extra_picture_buffers + 1,
                                             true );
        vlc_mutex_lock( &p_owner->lock );
        p_owner->p_vout = p_vout;
440

441
        DecoderUpdateFormatLocked( p_dec );
442
        p_owner->fmt.video.i_chroma = p_dec->fmt_out.i_codec;
443 444 445 446 447 448 449 450 451
        vlc_mutex_unlock( &p_owner->lock );

        if( p_owner->p_input != NULL )
            input_SendEventVout( p_owner->p_input );
        if( p_vout == NULL )
        {
            msg_Err( p_dec, "failed to create video output" );
            return -1;
        }
452
    }
453
    return 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
454 455
}

456
static picture_t *vout_new_buffer( decoder_t *p_dec )
Gildas Bazin's avatar
 
Gildas Bazin committed
457
{
458 459
    decoder_owner_sys_t *p_owner = p_dec->p_owner;

460
    return vout_GetPicture( p_owner->p_vout );
461
}
462

463 464 465 466 467 468 469
static subpicture_t *spu_new_buffer( decoder_t *p_dec,
                                     const subpicture_updater_t *p_updater )
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
    vout_thread_t *p_vout = NULL;
    subpicture_t *p_subpic;
    int i_attempts = 30;
470

471 472
    while( i_attempts-- )
    {
473
        if( p_dec->b_error )
474
            break;
475

476 477 478
        p_vout = input_resource_HoldVout( p_owner->p_resource );
        if( p_vout )
            break;
479

480 481
        msleep( DECODER_SPU_VOUT_WAIT_DURATION );
    }
482

483 484 485 486
    if( !p_vout )
    {
        msg_Warn( p_dec, "no vout found, dropping subpicture" );
        return NULL;
487
    }
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506

    if( p_owner->p_spu_vout != p_vout )
    {
        p_owner->i_spu_channel = vout_RegisterSubpictureChannel( p_vout );
        p_owner->i_spu_order = 0;
        p_owner->p_spu_vout = p_vout;
    }

    p_subpic = subpicture_New( p_updater );
    if( p_subpic )
    {
        p_subpic->i_channel = p_owner->i_spu_channel;
        p_subpic->i_order = p_owner->i_spu_order++;
        p_subpic->b_subtitle = true;
    }

    vlc_object_release( p_vout );

    return p_subpic;
507
}
Gildas Bazin's avatar
 
Gildas Bazin committed
508

509 510 511
static int DecoderGetInputAttachments( decoder_t *p_dec,
                                       input_attachment_t ***ppp_attachment,
                                       int *pi_attachment )
512
{
513 514 515 516 517 518 519 520 521 522 523 524 525
    input_thread_t *p_input = p_dec->p_owner->p_input;

    if( unlikely(p_input == NULL) )
        return VLC_ENOOBJ;
    return input_Control( p_input, INPUT_GET_ATTACHMENTS,
                          ppp_attachment, pi_attachment );
}

static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts )
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;

    vlc_mutex_lock( &p_owner->lock );
526
    if( p_owner->b_waiting )
527 528
        i_ts = VLC_TS_INVALID;
    vlc_mutex_unlock( &p_owner->lock );
529

530 531
    if( !p_owner->p_clock || i_ts <= VLC_TS_INVALID )
        return i_ts;
532

533 534 535 536 537 538
    if( input_clock_ConvertTS( VLC_OBJECT(p_dec), p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) {
        msg_Err(p_dec, "Could not get display date for timestamp %"PRId64"", i_ts);
        return VLC_TS_INVALID;
    }

    return i_ts;
539 540
}

541
static int DecoderGetDisplayRate( decoder_t *p_dec )
Laurent Aimar's avatar
Laurent Aimar committed
542 543 544
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;

545 546 547 548
    if( !p_owner->p_clock )
        return INPUT_RATE_DEFAULT;
    return input_clock_GetRate( p_owner->p_clock );
}
Laurent Aimar's avatar
Laurent Aimar committed
549

550 551 552 553
/*****************************************************************************
 * Public functions
 *****************************************************************************/
block_t *decoder_NewAudioBuffer( decoder_t *dec, int samples )
554
{
555 556
    if( decoder_UpdateAudioFormat( dec ) )
        return NULL;
557

558 559 560 561
    size_t length = samples * dec->fmt_out.audio.i_bytes_per_frame
                            / dec->fmt_out.audio.i_frame_length;
    block_t *block = block_Alloc( length );
    if( likely(block != NULL) )
562
    {
563 564
        block->i_nb_samples = samples;
        block->i_pts = block->i_length = 0;
565
    }
566
    return block;
567 568
}

569 570
subpicture_t *decoder_NewSubpicture( decoder_t *p_decoder,
                                     const subpicture_updater_t *p_dyn )
Laurent Aimar's avatar
Laurent Aimar committed
571
{
572 573 574 575 576
    subpicture_t *p_subpicture = p_decoder->pf_spu_buffer_new( p_decoder, p_dyn );
    if( !p_subpicture )
        msg_Warn( p_decoder, "can't get output subpicture" );
    return p_subpicture;
}
Laurent Aimar's avatar
Laurent Aimar committed
577

578 579 580 581 582 583 584 585
/* decoder_GetInputAttachments:
 */
int decoder_GetInputAttachments( decoder_t *p_dec,
                                 input_attachment_t ***ppp_attachment,
                                 int *pi_attachment )
{
    if( !p_dec->pf_get_attachments )
        return VLC_EGENERIC;
Laurent Aimar's avatar
Laurent Aimar committed
586

587 588 589 590 591 592 593 594
    return p_dec->pf_get_attachments( p_dec, ppp_attachment, pi_attachment );
}
/* decoder_GetDisplayDate:
 */
mtime_t decoder_GetDisplayDate( decoder_t *p_dec, mtime_t i_ts )
{
    if( !p_dec->pf_get_display_date )
        return VLC_TS_INVALID;
Laurent Aimar's avatar
Laurent Aimar committed
595

596 597 598 599 600 601 602 603
    return p_dec->pf_get_display_date( p_dec, i_ts );
}
/* decoder_GetDisplayRate:
 */
int decoder_GetDisplayRate( decoder_t *p_dec )
{
    if( !p_dec->pf_get_display_rate )
        return INPUT_RATE_DEFAULT;
Laurent Aimar's avatar
Laurent Aimar committed
604

605
    return p_dec->pf_get_display_rate( p_dec );
Laurent Aimar's avatar
Laurent Aimar committed
606 607
}

608
static void DecoderWaitUnblock( decoder_t *p_dec )
609 610 611 612 613
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;

    vlc_assert_locked( &p_owner->lock );

614
    for( ;; )
615
    {
616 617
        if( !p_owner->b_waiting || !p_owner->b_has_data )
            break;
618
        vlc_cond_wait( &p_owner->wait_request, &p_owner->lock );
619 620 621
    }
}

Laurent Aimar's avatar
Laurent Aimar committed
622 623
static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p )
{
624 625
    if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) )
        *pi_preroll = INT64_MAX;
626
    else if( p->i_dts > VLC_TS_INVALID )
Laurent Aimar's avatar
Laurent Aimar committed
627
        *pi_preroll = __MIN( *pi_preroll, p->i_dts );
628
    else if( p->i_pts > VLC_TS_INVALID )
Laurent Aimar's avatar
Laurent Aimar committed
629
        *pi_preroll = __MIN( *pi_preroll, p->i_pts );
Laurent Aimar's avatar
Laurent Aimar committed
630
}
631

Laurent Aimar's avatar
Laurent Aimar committed
632
static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1,
633
                          mtime_t *pi_duration, int *pi_rate, mtime_t i_ts_bound )
634
{
Laurent Aimar's avatar
Laurent Aimar committed
635 636
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
    input_clock_t   *p_clock = p_owner->p_clock;
637

Laurent Aimar's avatar
Laurent Aimar committed
638
    vlc_assert_locked( &p_owner->lock );
639

Laurent Aimar's avatar
Laurent Aimar committed
640
    const mtime_t i_es_delay = p_owner->i_ts_delay;
641

642 643
    if( !p_clock )
        return;
644

645 646
    const bool b_ephemere = pi_ts1 && *pi_ts0 == *pi_ts1;
    int i_rate;
647

648 649 650 651 652
    if( *pi_ts0 > VLC_TS_INVALID )
    {
        *pi_ts0 += i_es_delay;
        if( pi_ts1 && *pi_ts1 > VLC_TS_INVALID )
            *pi_ts1 += i_es_delay;
653 654
        if( i_ts_bound != INT64_MAX )
            i_ts_bound += i_es_delay;
655
        if( input_clock_ConvertTS( VLC_OBJECT(p_dec), p_clock, &i_rate, pi_ts0, pi_ts1, i_ts_bound ) ) {
656 657 658 659 660
            if( pi_ts1 != NULL )
                msg_Err(p_dec, "Could not convert timestamps %"PRId64
                        ", %"PRId64"", *pi_ts0, *pi_ts1);
            else
                msg_Err(p_dec, "Could not convert timestamp %"PRId64, *pi_ts0);
661
            *pi_ts0 = VLC_TS_INVALID;
662
        }
663 664 665 666 667
    }
    else
    {
        i_rate = input_clock_GetRate( p_clock );
    }
668

669 670 671
    /* Do not create ephemere data because of rounding errors */
    if( !b_ephemere && pi_ts1 && *pi_ts0 == *pi_ts1 )
        *pi_ts1 += 1;
672

673 674 675 676 677 678
    if( pi_duration )
        *pi_duration = ( *pi_duration * i_rate + INPUT_RATE_DEFAULT-1 )
            / INPUT_RATE_DEFAULT;

    if( pi_rate )
        *pi_rate = i_rate;
679
}
680

681 682
#ifdef ENABLE_SOUT
static int DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block )
683 684
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
685

686 687
    assert( p_owner->p_clock );
    assert( !p_sout_block->p_next );
688

689
    vlc_mutex_lock( &p_owner->lock );
690

691
    if( p_owner->b_waiting )
692
    {
693
        p_owner->b_has_data = true;
694
        vlc_cond_signal( &p_owner->wait_acknowledge );
695
    }
696

697
    DecoderWaitUnblock( p_dec );
698 699
    DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts,
                  &p_sout_block->i_length, NULL, INT64_MAX );
700

701
    vlc_mutex_unlock( &p_owner->lock );
702

703 704
    /* FIXME --VLC_TS_INVALID inspect stream_output*/
    return sout_InputSendBuffer( p_owner->p_sout_input, p_sout_block );
705 706
}

707 708 709
/* This function process a block for sout
 */
static void DecoderProcessSout( decoder_t *p_dec, block_t *p_block )
Laurent Aimar's avatar
Laurent Aimar committed
710
{
711
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
712
    block_t *p_sout_block;
Laurent Aimar's avatar
Laurent Aimar committed
713

714 715
    while( ( p_sout_block =
                 p_dec->pf_packetize( p_dec, p_block ? &p_block : NULL ) ) )
Laurent Aimar's avatar
Laurent Aimar committed
716
    {
717
        if( p_owner->p_sout_input == NULL )
718
        {
719 720 721
            vlc_mutex_lock( &p_owner->lock );
            DecoderUpdateFormatLocked( p_dec );
            vlc_mutex_unlock( &p_owner->lock );
Laurent Aimar's avatar
Laurent Aimar committed
722

723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
            p_owner->fmt.i_group = p_dec->fmt_in.i_group;
            p_owner->fmt.i_id = p_dec->fmt_in.i_id;
            if( p_dec->fmt_in.psz_language )
            {
                free( p_owner->fmt.psz_language );
                p_owner->fmt.psz_language =
                    strdup( p_dec->fmt_in.psz_language );
            }

            p_owner->p_sout_input =
                sout_InputNew( p_owner->p_sout, &p_owner->fmt );

            if( p_owner->p_sout_input == NULL )
            {
                msg_Err( p_dec, "cannot create packetizer output (%4.4s)",
                         (char *)&p_owner->fmt.i_codec );
                p_dec->b_error = true;

                block_ChainRelease(p_sout_block);
                break;
            }
Laurent Aimar's avatar
Laurent Aimar committed
744
        }
745

746
        while( p_sout_block )
Laurent Aimar's avatar
Laurent Aimar committed
747
        {
748
            block_t *p_next = p_sout_block->p_next;
749

750 751 752 753 754 755 756
            p_sout_block->p_next = NULL;

            if( DecoderPlaySout( p_dec, p_sout_block ) == VLC_EGENERIC )
            {
                msg_Err( p_dec, "cannot continue streaming due to errors" );

                p_dec->b_error = true;
757

758 759 760 761
                /* Cleanup */
                block_ChainRelease( p_next );
                return;
            }
762

763 764
            p_sout_block = p_next;
        }
Laurent Aimar's avatar
Laurent Aimar committed
765 766
    }
}
767 768
#endif

769 770
static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
{
771
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
772
    block_t *p_cc;
773
    bool pb_present[4];
774
    bool b_processed = false;
775 776 777 778 779 780
    int i;
    int i_cc_decoder;

    assert( p_dec_cc->pf_get_cc != NULL );

    /* Do not try retreiving CC if not wanted (sout) or cannot be retreived */
781
    if( !p_owner->cc.b_supported )
782 783 784 785 786 787
        return;

    p_cc = p_dec_cc->pf_get_cc( p_dec_cc, pb_present );
    if( !p_cc )
        return;

788
    vlc_mutex_lock( &p_owner->lock );
789 790
    for( i = 0, i_cc_decoder = 0; i < 4; i++ )
    {
791 792
        p_owner->cc.pb_present[i] |= pb_present[i];
        if( p_owner->cc.pp_decoder[i] )
793 794 795 796 797
            i_cc_decoder++;
    }

    for( i = 0; i < 4; i++ )
    {
798
        if( !p_owner->cc.pp_decoder[i] )
799 800
            continue;

801 802 803
        block_FifoPut( p_owner->cc.pp_decoder[i]->p_owner->p_fifo,
            (i_cc_decoder > 1) ? block_Duplicate(p_cc) : p_cc);

804
        i_cc_decoder--;
805
        b_processed = true;
806
    }
807
    vlc_mutex_unlock( &p_owner->lock );
808 809 810

    if( !b_processed )
        block_Release( p_cc );
811
}
812

813 814 815 816 817 818
static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
                              int *pi_played_sum, int *pi_lost_sum )
{
    decoder_owner_sys_t *p_owner = p_dec->p_owner;
    vout_thread_t  *p_vout = p_owner->p_vout;

819
    if( p_picture->date <= VLC_TS_INVALID )
820
    {
821
        msg_Warn( p_dec, "non-dated video buffer received" );
822
        *pi_lost_sum += 1;
823
        picture_Release( p_picture );
824 825 826 827
        return;
    }

    /* */
828 829
    vlc_mutex_lock( &p_owner->lock );

830
    if( p_owner->b_waiting && !p_owner->b_first )
831
    {
832
        p_owner->b_has_data = true;
833
        vlc_cond_signal( &p_owner->wait_acknowledge );
834
    }
835
    bool b_first_after_wait = p_owner->b_waiting && p_owner->b_has_data;
Laurent Aimar's avatar
Laurent Aimar committed
836

837
    DecoderWaitUnblock( p_dec );
838

839
    if( p_owner->b_waiting )
840
    {
841
        assert( p_owner->b_first );
842
        msg_Dbg( p_dec, "Received first picture" );
843
        p_owner->b_first = false;
844 845
        p_picture->b_force = true;
    }
Laurent Aimar's avatar
Laurent Aimar committed
846

847 848 849 850
    const bool b_dated = p_picture->date > VLC_TS_INVALID;
    int i_rate = INPUT_RATE_DEFAULT;
    DecoderFixTs( p_dec, &p_picture->date, NULL, NULL,
                  &i_rate, DECODER_BOGUS_VIDEO_DELAY );
851

852
    vlc_mutex_unlock( &p_owner->lock );
853

854
    /* FIXME: The *input* FIFO should not be locked here. This will not work
855
     * properly if/when pictures are queued asynchronously. */
856
    vlc_fifo_Lock( p_owner->p_fifo );
857 858
    if( unlikely(p_owner->paused) && likely(p_owner->frames_countdown > 0) )
        p_owner->frames_countdown--;
859 860
    vlc_fifo_Unlock( p_owner->p_fifo );

861
    /* */
862 863
    if( p_picture->b_force || p_picture->date > VLC_TS_INVALID )
        /* FIXME: VLC_TS_INVALID -- verify video_output */
864 865
    {
        if( i_rate != p_owner->i_last_rate || b_first_after_wait )
866
        {
867 868 869
            /* Be sure to not display old picture after our own */
            vout_Flush( p_vout, p_picture->date );
            p_owner->i_last_rate = i_rate;
870
        }
Felix Abecassis's avatar