ts.c 49.2 KB
Newer Older
1
/*****************************************************************************
2
 * ts.c: MPEG-II TS Muxer
3 4
 *****************************************************************************
 * Copyright (C) 2001, 2002 VideoLAN
5
 * $Id: ts.c,v 1.27 2003/08/14 11:47:32 gbazin Exp $
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Eric Petit <titer@videolan.org>
 *
 *
 * 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/sout.h>

#include "codecs.h"
#include "bits.h"
#include "pes.h"

39
#if defined MODULE_NAME_IS_mux_ts_dvbpsi
ipkiss's avatar
ipkiss committed
40
#   ifdef HAVE_DVBPSI_DR_H
41 42 43 44 45
#       include <dvbpsi/dvbpsi.h>
#       include <dvbpsi/descriptor.h>
#       include <dvbpsi/pat.h>
#       include <dvbpsi/pmt.h>
#       include <dvbpsi/dr.h>
46
#       include <dvbpsi/psi.h>
ipkiss's avatar
ipkiss committed
47 48 49 50 51 52
#   else
#       include "dvbpsi.h"
#       include "descriptor.h"
#       include "tables/pat.h"
#       include "tables/pmt.h"
#       include "descriptors/dr.h"
53
#       include "psi.h"
ipkiss's avatar
ipkiss committed
54
#   endif
55 56
#endif

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 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
/*
 * TODO:
 *  - check PCR frequency requirement
 *  - check PAT/PMT  "        "
 *  - check PCR/PCR "soft"
 *
 *  - remove creation of PAT/PMT without dvbpsi
 *  - ?
 * FIXME:
 *  - subtitle support is far from perfect. I expect some subtitles drop
 *    if they arrive a bit late
 *    (We cannot rely on the fact that the fifo should be full)
 */
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int     Open   ( vlc_object_t * );
static void    Close  ( vlc_object_t * );

vlc_module_begin();
#if defined MODULE_NAME_IS_mux_ts
    set_description( _("TS muxer") );
    set_capability( "sout mux", 100 );
    add_shortcut( "ts" );
    add_shortcut( "ts_nodvbpsi" );
#elif defined MODULE_NAME_IS_mux_ts_dvbpsi
    set_description( _("TS muxer (libdvbpsi)") );
    set_capability( "sout mux", 120 );
    add_shortcut( "ts" );
    add_shortcut( "ts_dvbpsi" );
#endif
    set_callbacks( Open, Close );
vlc_module_end();

/*****************************************************************************
 * Exported prototypes
 *****************************************************************************/
static int     Capability(sout_mux_t *, int, void *, void * );
static int     AddStream( sout_mux_t *, sout_input_t * );
static int     DelStream( sout_mux_t *, sout_input_t * );
static int     Mux      ( sout_mux_t * );

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
#define SOUT_BUFFER_FLAGS_PRIVATE_PCR_SOFT  ( 1 << SOUT_BUFFER_FLAGS_PRIVATE_SHIFT )
typedef struct
{
    int           i_depth;
    sout_buffer_t *p_first;
    sout_buffer_t **pp_last;
} sout_buffer_chain_t;

static inline void BufferChainInit  ( sout_buffer_chain_t *c )
{
    c->i_depth = 0;
    c->p_first = NULL;
    c->pp_last = &c->p_first;
}
static inline void BufferChainAppend( sout_buffer_chain_t *c, sout_buffer_t *b )
{
    *c->pp_last = b;
    c->i_depth++;

    while( b->p_next )
    {
        b = b->p_next;
        c->i_depth++;
    }
    c->pp_last = &b->p_next;
}
static inline sout_buffer_t *BufferChainGet( sout_buffer_chain_t *c )
{
    sout_buffer_t *b = c->p_first;

    if( b )
    {
        c->i_depth--;
        c->p_first = b->p_next;

        if( c->p_first == NULL )
        {
            c->pp_last = &c->p_first;
        }

        b->p_next = NULL;
    }
    return b;
}

147 148 149 150 151 152
typedef struct ts_stream_s
{
    int             i_pid;
    int             i_stream_type;
    int             i_stream_id;
    int             i_continuity_counter;
153

154 155 156 157
    /* to be used for carriege of DIV3 */
    vlc_fourcc_t    i_bih_codec;
    int             i_bih_width, i_bih_height;

158 159 160
    /* Specific to mpeg4 in mpeg2ts */
    int             i_es_id;

161
    int             i_decoder_specific_info;
162
    uint8_t         *p_decoder_specific_info;
163 164 165 166

    /* for TS building */
    sout_buffer_chain_t chain_ts;

167 168
} ts_stream_t;

169
struct sout_mux_sys_t
170 171
{
    int             i_pcr_pid;
172 173
    sout_input_t    *p_pcr_input;

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    int             i_stream_id_mpga;
    int             i_stream_id_mpgv;
    int             i_stream_id_a52;

    int             i_audio_bound;
    int             i_video_bound;

    int             i_pid_free; // first usable pid

    int             i_pat_version_number;
    ts_stream_t     pat;

    int             i_pmt_version_number;
    ts_stream_t     pmt;        // Up to now only one program

189 190
    int             i_mpeg4_streams;

191
    int             i_null_continuity_counter;  /* Needed ? */
192

193 194 195 196 197
    /* for TS building */
    int64_t             i_bitrate_min;
    int64_t             i_bitrate_max;
    int64_t             i_pcr_delay;
    int64_t             i_pcr_soft_delay;
Laurent Aimar's avatar
Laurent Aimar committed
198

199 200 201 202 203
    mtime_t             i_pcr;  /* last PCR emited (for pcr-soft) */
    mtime_t             i_dts;
    mtime_t             i_length;
    sout_buffer_chain_t chain_ts;
};
204 205


206
/* Reserve a pid and return it */
207
static int  AllocatePID( sout_mux_sys_t *p_sys )
208
{
209
    return( ++p_sys->i_pid_free );
210 211
}

212 213
static void GetPAT( sout_mux_t *p_mux, sout_buffer_chain_t *c );
static void GetPMT( sout_mux_t *p_mux, sout_buffer_chain_t *c );
214

215 216 217 218 219 220
static int  TSFill   ( sout_mux_t *, sout_input_t * );
static void PEStoTS  ( sout_instance_t *, sout_buffer_chain_t *, sout_buffer_t *, ts_stream_t *, vlc_bool_t );
static void TSSetDate( sout_buffer_chain_t *, mtime_t, mtime_t );
static void TSSetConstraints( sout_mux_t*, sout_buffer_chain_t *,
                              mtime_t i_length, int i_bitrate_min, int i_bitrate_max );

221 222 223 224 225
/*****************************************************************************
 * Open:
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
226 227
    sout_mux_t          *p_mux =(sout_mux_t*)p_this;
    sout_mux_sys_t      *p_sys;
228
    char                *val;
229

230
    msg_Dbg( p_mux, "Open" );
231

232
    p_sys = malloc( sizeof( sout_mux_sys_t ) );
233

234 235 236 237 238 239
    p_mux->pf_capacity  = Capability;
    p_mux->pf_addstream = AddStream;
    p_mux->pf_delstream = DelStream;
    p_mux->pf_mux       = Mux;
    p_mux->p_sys        = p_sys;
    p_mux->i_preheader  = 30; // really enough for a pes header
240

241 242
    srand( (uint32_t)mdate() );

243 244 245
    p_sys->i_stream_id_mpga = 0xc0;
    p_sys->i_stream_id_a52  = 0x80;
    p_sys->i_stream_id_mpgv = 0xe0;
246

247 248
    p_sys->i_audio_bound = 0;
    p_sys->i_video_bound = 0;
249

250 251 252
    p_sys->i_pat_version_number = rand() % 32;
    p_sys->pat.i_pid = 0;
    p_sys->pat.i_continuity_counter = 0;
253

254
    p_sys->i_pmt_version_number = rand() % 32;
255
    p_sys->pmt.i_pid = 0x42;
256
    p_sys->pmt.i_continuity_counter = 0;
257

258
    p_sys->i_pid_free = 0x43;
259

260
    p_sys->i_pcr_pid = 0x1fff;
261
    p_sys->p_pcr_input = NULL;
262

263
    p_sys->i_mpeg4_streams = 0;
264

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    p_sys->i_null_continuity_counter = 0;

    /* Allow to create constrained stream */
    p_sys->i_bitrate_min = 0;
    p_sys->i_bitrate_max = 0;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "bmin" ) ) )
    {
        p_sys->i_bitrate_min = atoll( val );
    }
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "bmax" ) ) )
    {
        p_sys->i_bitrate_max = atoll( val );
    }
    if( p_sys->i_bitrate_min > 0 && p_sys->i_bitrate_max > 0 &&
        p_sys->i_bitrate_min > p_sys->i_bitrate_max )
    {
gbazin's avatar
 
gbazin committed
281 282
        msg_Err( p_mux, "incompatible minimum and maximum bitrate, "
                 "disabling bitrate control" );
283 284 285 286 287 288 289 290 291 292
        p_sys->i_bitrate_min = 0;
        p_sys->i_bitrate_max = 0;
    }
    p_sys->i_pcr_delay = 100000;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "pcr" ) ) )
    {
        p_sys->i_pcr_delay = (int64_t)atoi( val ) * 1000;
        if( p_sys->i_pcr_delay <= 0 )
        {
            msg_Err( p_mux,
gbazin's avatar
 
gbazin committed
293
                     "invalid pcr delay ("I64Fd"ms) reseting to 100ms",
294 295 296 297 298 299 300 301 302 303 304 305
                     p_sys->i_pcr_delay / 1000 );
            p_sys->i_pcr_delay = 100000;
        }
    }
    p_sys->i_pcr_soft_delay = 0;
    if( ( val = sout_cfg_find_value( p_mux->p_cfg, "pcr-soft" ) ) )
    {
        p_sys->i_pcr_soft_delay = (int64_t)atoi( val ) * 1000;
        if( p_sys->i_pcr_soft_delay <= 0 ||
            p_sys->i_pcr_soft_delay >= p_sys->i_pcr_delay )
        {
            msg_Err( p_mux,
gbazin's avatar
 
gbazin committed
306
                     "invalid pcr-soft delay ("I64Fd"ms) disabled",
307 308 309 310 311
                     p_sys->i_pcr_soft_delay / 1000 );
            p_sys->i_pcr_soft_delay = 0;
        }
    }

gbazin's avatar
 
gbazin committed
312
    msg_Dbg( p_mux, "pcr_delay="I64Fd" pcr_soft_delay="I64Fd,
313
             p_sys->i_pcr_delay, p_sys->i_pcr_soft_delay );
gbazin's avatar
 
gbazin committed
314

315 316 317 318 319
    /* for TS gnration */
    p_sys->i_pcr    = 0;
    p_sys->i_dts    = 0;
    p_sys->i_length = 0;
    BufferChainInit( &p_sys->chain_ts );
320 321 322 323 324 325 326 327
    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t * p_this )
{
328 329
    sout_mux_t          *p_mux = (sout_mux_t*)p_this;
    sout_mux_sys_t      *p_sys = p_mux->p_sys;
330
    sout_buffer_t       *p_data;
331

332 333 334 335 336 337 338
    msg_Dbg( p_mux, "Close" );

    /* Empty TS buffer */
    while( ( p_data = BufferChainGet( &p_sys->chain_ts ) ) )
    {
        sout_BufferDelete( p_mux->p_sout, p_data );
    }
339

340
    free( p_sys );
341 342
}

343 344 345
/*****************************************************************************
 * Capability:
 *****************************************************************************/
346
static int Capability( sout_mux_t *p_mux, int i_query, void *p_args, void *p_answer )
347 348 349 350 351 352 353 354 355 356
{
   switch( i_query )
   {
        case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
            *(vlc_bool_t*)p_answer = VLC_TRUE;
            return( SOUT_MUX_CAP_ERR_OK );
        default:
            return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
   }
}
357

358 359 360
/*****************************************************************************
 * AddStream: called for each stream addition
 *****************************************************************************/
361
static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
362
{
363
    sout_mux_sys_t      *p_sys = p_mux->p_sys;
364 365
    ts_stream_t         *p_stream;

366 367
    msg_Dbg( p_mux, "adding input codec=%4.4s", (char*)&p_input->p_fmt->i_fourcc );

368
    p_input->p_sys = (void*)p_stream = malloc( sizeof( ts_stream_t ) );
369

370
    /* Init this new stream */
371
    p_stream->i_pid = AllocatePID( p_sys );
372 373 374
    p_stream->i_continuity_counter    = 0;
    p_stream->i_decoder_specific_info = 0;
    p_stream->p_decoder_specific_info = NULL;
375

376
    /* All others fields depand on codec */
377
    switch( p_input->p_fmt->i_cat )
378 379
    {
        case VIDEO_ES:
380
            switch( p_input->p_fmt->i_fourcc )
381 382
            {
                case VLC_FOURCC( 'm', 'p','g', 'v' ):
383
                    /* TODO: do we need to check MPEG-I/II ? */
384
                    p_stream->i_stream_type = 0x02;
385 386
                    p_stream->i_stream_id = p_sys->i_stream_id_mpgv;
                    p_sys->i_stream_id_mpgv++;
387 388 389 390
                    break;
                case VLC_FOURCC( 'm', 'p','4', 'v' ):
                    p_stream->i_stream_type = 0x10;
                    p_stream->i_stream_id = 0xfa;
391
                    p_sys->i_mpeg4_streams++;
392
                    p_stream->i_es_id = p_stream->i_pid;
393
                    break;
394 395 396 397
                /* XXX dirty dirty but somebody want that : using crapy MS-codec XXX */
                /* I didn't want to do that :P */
                case VLC_FOURCC( 'H', '2', '6', '3' ):
                case VLC_FOURCC( 'I', '2', '6', '3' ):
398
                case VLC_FOURCC( 'W', 'M', 'V', '2' ):
399 400 401 402
                case VLC_FOURCC( 'W', 'M', 'V', '1' ):
                case VLC_FOURCC( 'D', 'I', 'V', '3' ):
                case VLC_FOURCC( 'D', 'I', 'V', '2' ):
                case VLC_FOURCC( 'D', 'I', 'V', '1' ):
403
                case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
404 405
                    p_stream->i_stream_type = 0xa0; // private
                    p_stream->i_stream_id = 0xa0;   // beurk
406 407 408
                    p_stream->i_bih_codec  = p_input->p_fmt->i_fourcc;
                    p_stream->i_bih_width  = p_input->p_fmt->i_width;
                    p_stream->i_bih_height = p_input->p_fmt->i_height;
409
                    break;
410
                default:
411 412
                    free( p_stream );
                    return VLC_EGENERIC;
413
            }
414
            p_sys->i_video_bound++;
415
            break;
416

417
        case AUDIO_ES:
418
            switch( p_input->p_fmt->i_fourcc )
419
            {
420 421 422 423 424
                case VLC_FOURCC( 'm', 'p','g', 'a' ):
                    p_stream->i_stream_type = p_input->p_fmt->i_sample_rate >= 32000 ? 0x03 : 0x04;
                    p_stream->i_stream_id = p_sys->i_stream_id_mpga;
                    p_sys->i_stream_id_mpga++;
                    break;
425 426
                case VLC_FOURCC( 'a', '5','2', ' ' ):
                    p_stream->i_stream_type = 0x81;
427 428
                    p_stream->i_stream_id = p_sys->i_stream_id_a52;
                    p_sys->i_stream_id_a52++;
429 430 431 432
                    break;
                case VLC_FOURCC( 'm', 'p','4', 'a' ):
                    p_stream->i_stream_type = 0x11;
                    p_stream->i_stream_id = 0xfa;
433
                    p_sys->i_mpeg4_streams++;
434
                    p_stream->i_es_id = p_stream->i_pid;
435 436
                    break;
                default:
437 438
                    free( p_stream );
                    return VLC_EGENERIC;
439
            }
440
            p_sys->i_audio_bound++;
441
            break;
442

443 444
        case SPU_ES:
            switch( p_input->p_fmt->i_fourcc )
445
            {
446 447 448 449 450 451 452
                case VLC_FOURCC( 's', 'p','u', ' ' ):
                    p_stream->i_stream_type = 0x82;
                    p_stream->i_stream_id = 0x82;
                    break;
                default:
                    free( p_stream );
                    return VLC_EGENERIC;
453
            }
454
            break;
455

456
        default:
457 458
            free( p_stream );
            return VLC_EGENERIC;
459 460
    }

461 462 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
    /* Copy extra data (VOL for MPEG-4 and extra BitMapInfoHeader for VFW */
    p_stream->i_decoder_specific_info = p_input->p_fmt->i_extra_data;
    if( p_stream->i_decoder_specific_info > 0 )
    {
        p_stream->p_decoder_specific_info =
            malloc( p_stream->i_decoder_specific_info );
        memcpy( p_stream->p_decoder_specific_info,
                p_input->p_fmt->p_extra_data,
                p_input->p_fmt->i_extra_data );
    }
    /* Init chain for TS building */
    BufferChainInit( &p_stream->chain_ts );

    /* We only change PMT version (PAT isn't changed) */
    p_sys->i_pmt_version_number = ( p_sys->i_pmt_version_number + 1 )%32;

    /* Update pcr_pid */
    if( p_input->p_fmt->i_cat != SPU_ES &&
        ( p_sys->i_pcr_pid == 0x1fff || p_input->p_fmt->i_cat == VIDEO_ES ) )
    {
        sout_buffer_t *p_data;

        if( p_sys->p_pcr_input )
        {
            /* There was already a PCR stream, so clean context */
            ts_stream_t   *p_pcr_stream = (ts_stream_t*)p_sys->p_pcr_input->p_sys;

            while( ( p_data = BufferChainGet( &p_pcr_stream->chain_ts ) ) )
            {
                sout_BufferDelete( p_mux->p_sout, p_data );
            }
        }
        p_sys->i_pcr_pid   = p_stream->i_pid;
        p_sys->p_pcr_input = p_input;
495

496
        /* Empty TS buffer (avoid broken data/problems with pcr stream changement ) */
497 498 499 500 501 502 503
        while( ( p_data = BufferChainGet( &p_sys->chain_ts ) ) )
        {
            sout_BufferDelete( p_mux->p_sout, p_data );
        }
    }

    return VLC_SUCCESS;
504 505
}

506 507 508
/*****************************************************************************
 * DelStream: called before a stream deletion
 *****************************************************************************/
509
static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
510
{
511 512
    sout_mux_sys_t  *p_sys = p_mux->p_sys;
    ts_stream_t     *p_stream;
513
    sout_buffer_t   *p_data;
514

515 516
    msg_Dbg( p_mux, "removing input" );
    p_stream = (ts_stream_t*)p_input->p_sys;
517

518 519 520 521 522 523
    if( p_sys->i_pcr_pid == p_stream->i_pid )
    {
        int i;

        /* Find a new pcr stream (Prefer Video Stream) */
        p_sys->i_pcr_pid = 0x1fff;
524
        p_sys->p_pcr_input = NULL;
525 526 527 528 529 530 531 532 533
        for( i = 0; i < p_mux->i_nb_inputs; i++ )
        {
            if( p_mux->pp_inputs[i] == p_input )
            {
                continue;
            }

            if( p_mux->pp_inputs[i]->p_fmt->i_cat == VIDEO_ES )
            {
534 535
                p_sys->i_pcr_pid  =
                    ((ts_stream_t*)p_mux->pp_inputs[i]->p_sys)->i_pid;
536 537 538
                p_sys->p_pcr_input= p_mux->pp_inputs[i];
                break;
            }
539 540
            else if( p_mux->pp_inputs[i]->p_fmt->i_cat != SPU_ES &&
                     p_sys->i_pcr_pid == 0x1fff )
541
            {
542 543
                p_sys->i_pcr_pid  =
                    ((ts_stream_t*)p_mux->pp_inputs[i]->p_sys)->i_pid;
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
                p_sys->p_pcr_input= p_mux->pp_inputs[i];
            }
        }
        if( p_sys->p_pcr_input )
        {
            /* Empty TS buffer */
            while( ( p_data = BufferChainGet( &((ts_stream_t*)p_sys->p_pcr_input->p_sys)->chain_ts ) ) )
            {
                sout_BufferDelete( p_mux->p_sout, p_data );
            }
        }
    }

    /* Empty all data in chain_ts */
    while( ( p_data = BufferChainGet( &p_stream->chain_ts ) ) )
    {
        sout_BufferDelete( p_mux->p_sout, p_data );
    }
562 563 564 565 566 567
    if( p_stream->p_decoder_specific_info )
    {
        free( p_stream->p_decoder_specific_info );
    }
    if( p_stream->i_stream_id == 0xfa || p_stream->i_stream_id == 0xfb )
    {
568
        p_sys->i_mpeg4_streams--;
569
    }
Laurent Aimar's avatar
Laurent Aimar committed
570 571
    free( p_stream );

572
    /* We only change PMT version (PAT isn't changed) */
573
    p_sys->i_pmt_version_number++; p_sys->i_pmt_version_number %= 32;
574

575
    /*Empty TS buffer (avoid broken data/problems with pcr stream changement) */
576 577 578 579 580 581
    while( ( p_data = BufferChainGet( &p_sys->chain_ts ) ) )
    {
        sout_BufferDelete( p_mux->p_sout, p_data );
    }

    return VLC_SUCCESS;
582 583
}

584 585 586 587 588 589 590 591
/*****************************************************************************
 * Mux: Call each time there is new data for at least one stream
 *****************************************************************************
 *
 *****************************************************************************/
static int Mux( sout_mux_t *p_mux )
{
    sout_mux_sys_t  *p_sys = p_mux->p_sys;
592

593 594
    sout_input_t    *p_pcr_input = p_sys->p_pcr_input;
    ts_stream_t     *p_pcr_stream = (ts_stream_t*)p_sys->p_pcr_input->p_sys;
595

596 597 598 599 600 601
    if( p_sys->i_pcr_pid == 0x1fff )
    {
        msg_Dbg( p_mux, "waiting PCR streams" );
        msleep( 1000 );
        return VLC_SUCCESS;
    }
602

603
    for( ;; )
604
    {
605 606
        ts_stream_t   *p_stream = NULL;
        sout_buffer_t *p_data;
607

608 609
        int     i_stream, i;
        mtime_t i_dts;
610

611 612
        /* fill ts packets for pcr XXX before GetPAT/GetPMT */
        if( p_pcr_stream->chain_ts.p_first == NULL && TSFill( p_mux, p_pcr_input ) )
613
        {
614 615 616
            /* We need more data */
            return VLC_SUCCESS;
        }
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
        if( p_sys->chain_ts.p_first == NULL  )
        {
            /* Every pcr packet send PAT/PMT */
            GetPAT( p_mux, &p_sys->chain_ts);
            GetPMT( p_mux, &p_sys->chain_ts );
        }

        /* search stream with lowest dts */
        for( i = 0, i_stream = -1, i_dts = 0; i < p_mux->i_nb_inputs; i++ )
        {
            p_stream = (ts_stream_t*)p_mux->pp_inputs[i]->p_sys;

            if( p_stream->chain_ts.p_first == NULL )
            {
                if( TSFill( p_mux, p_mux->pp_inputs[i] ) )
                {
                    /* We need more data */
                    return VLC_SUCCESS;
                }
                if( p_stream->chain_ts.p_first == NULL )
                {
                    continue; /* SPU_ES */
                }
            }

            if( i_stream == -1 ||
                p_stream->chain_ts.p_first->i_dts < i_dts )
645 646
            {
                i_stream = i;
647
                i_dts = p_stream->chain_ts.p_first->i_dts;
648 649
            }
        }
650 651 652 653 654 655 656

        p_stream = (ts_stream_t*)p_mux->pp_inputs[i_stream]->p_sys;

        p_data = BufferChainGet( &p_stream->chain_ts );
        BufferChainAppend( &p_sys->chain_ts, p_data );

        if( p_stream->i_pid == p_pcr_stream->i_pid && p_stream->chain_ts.p_first == NULL )
657
        {
658
            sout_buffer_t *p_ts = p_sys->chain_ts.p_first;
659

660
            /* We have consume all TS packets from the PCR stream */
661

662 663 664
            if( p_sys->i_length > p_sys->i_pcr_delay )
            {
                /* Send TS data if last PCR was i_pcr_delay ago */
665

666 667 668 669 670 671
                if( p_sys->i_bitrate_min > 0 ||
                    p_sys->i_bitrate_max > 0 )
                {
                    TSSetConstraints( p_mux, &p_sys->chain_ts, p_sys->i_length,
                                      p_sys->i_bitrate_min, p_sys->i_bitrate_max );
                }
672

673 674 675 676 677
                /* Send all data */
                TSSetDate( &p_sys->chain_ts,
                           p_sys->i_dts + 3  * p_sys->i_pcr_delay / 2,    /* latency is equal to i_pcr_delay, 3/2 is for security */
                           p_sys->i_length );
                sout_AccessOutWrite( p_mux->p_access, p_ts );
678

679 680
                /* Reset the ts chain */
                BufferChainInit( &p_sys->chain_ts );
681

682 683 684
                p_sys->i_length = 0;
            }
        }
685 686
    }

687 688
    return VLC_SUCCESS;
}
689 690 691



692 693 694 695 696 697 698
/*****************************************************************************
 *
 *
 *****************************************************************************/
static int TSFill( sout_mux_t *p_mux, sout_input_t *p_input )
{
    sout_mux_sys_t  *p_sys = p_mux->p_sys;
699

700 701 702 703 704 705
    ts_stream_t     *p_pcr_stream = (ts_stream_t*)p_sys->p_pcr_input->p_sys;
    ts_stream_t     *p_stream = (ts_stream_t*)p_input->p_sys;
    mtime_t         i_dts, i_length;
    sout_buffer_t   *p_data;
    vlc_bool_t      b_pcr = VLC_FALSE;
    vlc_bool_t      b_pcr_soft = VLC_FALSE;
706 707


708 709 710
    for( ;; )
    {
        if( p_input->p_fifo->i_depth <= 0 )
711
        {
712 713
            if( p_input->p_fmt->i_cat == AUDIO_ES ||
                p_input->p_fmt->i_cat == VIDEO_ES )
714
            {
715 716
                /* We need more data */
                return VLC_EGENERIC;
717 718 719
            }
            else
            {
720
                return VLC_SUCCESS;
721
            }
722 723 724 725
        }
        p_data = sout_FifoGet( p_input->p_fifo );
        i_dts    = p_data->i_dts;
        i_length = p_data->i_length;
726

727 728 729 730 731
        if(  p_stream->i_pid == p_pcr_stream->i_pid &&
             p_stream->chain_ts.p_first == NULL )
        {
            p_sys->i_length+= i_length;
            if( p_sys->chain_ts.p_first == NULL )
732
            {
733 734 735
                p_sys->i_dts    = i_dts;
                p_sys->i_pcr    = i_dts;
                b_pcr = VLC_TRUE;
736
            }
737 738 739 740 741 742 743 744
            else if( p_sys->i_pcr_soft_delay > 0 &&
                     p_sys->i_pcr + p_sys->i_pcr_soft_delay < i_dts )
            {
                p_sys->i_pcr    = i_dts;
                b_pcr = VLC_TRUE;
                b_pcr_soft = VLC_TRUE;
            }
            break;
745
        }
746

gbazin's avatar
 
gbazin committed
747
        if( ( p_sys->i_dts + p_sys->i_length ) - i_dts > 2000000 ||
748
            ( p_sys->i_dts + p_sys->i_length ) - i_dts < -2000000 )
749
        {
gbazin's avatar
 
gbazin committed
750 751
            msg_Err( p_mux, "| buffer_dts - pcr_pts | > 2s ("I64Fd") empting "
                     "pcr TS buffers", p_sys->i_dts + p_sys->i_length - i_dts);
752

753 754 755
            sout_BufferDelete( p_mux->p_sout, p_data );

            while( ( p_data = BufferChainGet( &p_pcr_stream->chain_ts ) ) )
756
            {
757
                sout_BufferDelete( p_mux->p_sout, p_data );
758
            }
759
            while( ( p_data = BufferChainGet( &p_sys->chain_ts ) ) )
760
            {
761
                sout_BufferDelete( p_mux->p_sout, p_data );
762
            }
763 764 765 766 767 768
            return VLC_EGENERIC;
        }

        if( i_dts >= p_sys->i_dts )
        {
            break;
769
        }
770

gbazin's avatar
 
gbazin committed
771
        msg_Dbg( p_mux, "dropping buffer size=%d dts="I64Fd" pcr_dts="I64Fd
gbazin's avatar
 
gbazin committed
772 773
                 " diff="I64Fd, p_data->i_size, i_dts, p_sys->i_dts,
                 p_sys->i_dts + p_sys->i_length - i_dts );
774 775 776 777 778 779 780 781 782 783 784 785
        sout_BufferDelete( p_mux->p_sout, p_data );
    }

    E_( EStoPES )( p_mux->p_sout, &p_data, p_data, p_stream->i_stream_id, 1);

    BufferChainInit( &p_stream->chain_ts );
    PEStoTS( p_mux->p_sout, &p_stream->chain_ts, p_data, p_stream, b_pcr );

    TSSetDate( &p_stream->chain_ts, i_dts, i_length );

    if( b_pcr_soft && p_stream->chain_ts.p_first )
    {
786
        p_stream->chain_ts.p_first->i_flags=SOUT_BUFFER_FLAGS_PRIVATE_PCR_SOFT;
787 788
    }

789
    return VLC_SUCCESS;
790 791
}

792
static void TSSetConstraints( sout_mux_t *p_mux, sout_buffer_chain_t *c, mtime_t i_length, int i_bitrate_min, int i_bitrate_max )
793
{
794 795 796 797 798 799
    sout_mux_sys_t  *p_sys = p_mux->p_sys;
    sout_buffer_chain_t s = *c;

    int i_packets = 0;
    int i_packets_min = 0;
    int i_packets_max = 0;
800

801
    if( i_length <= 0 )
802
    {
803
        return;
804 805
    }

806 807 808 809 810
    i_packets     = c->i_depth;
    i_packets_min = ( (int64_t)i_bitrate_min * i_length / 8 / 1000000  + 187 ) / 188;
    i_packets_max = ( (int64_t)i_bitrate_max * i_length / 8 / 1000000  + 187 ) / 188;

    if( i_packets < i_packets_min && i_packets_min > 0 )
811
    {
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
        sout_buffer_t *p_pk;
        int i_div = ( i_packets_min - i_packets ) / i_packets;
        int i_mod = ( i_packets_min - i_packets ) % i_packets;
        int i_rest = 0;

        /* We need to pad with null packets (pid=0x1fff)
         * We try to melt null packets with true packets */
        msg_Dbg( p_mux,
                 "packets=%d but min=%d -> adding %d packets of padding",
                 i_packets, i_packets_min, i_packets_min - i_packets );

        BufferChainInit( c );
        while( ( p_pk = BufferChainGet( &s ) ) )
        {
            int i, i_null;

            BufferChainAppend( c, p_pk );

            i_null = i_div + ( i_rest + i_mod ) / i_packets;

            for( i = 0; i < i_null; i++ )
            {
                sout_buffer_t *p_null;

                p_null = sout_BufferNew( p_mux->p_sout, 188 );
                p_null->p_buffer[0] = 0x47;
                p_null->p_buffer[1] = 0x1f;
                p_null->p_buffer[2] = 0xff;
                p_null->p_buffer[3] = 0x10 | p_sys->i_null_continuity_counter;
                memset( &p_null->p_buffer[4], 0, 184 );
                p_sys->i_null_continuity_counter =
                    ( p_sys->i_null_continuity_counter + 1 ) % 16;

                BufferChainAppend( c, p_null );
            }
847

848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
            i_rest = ( i_rest + i_mod ) % i_packets;
        }
    }
    else if( i_packets > i_packets_max && i_packets_max > 0 )
    {
        sout_buffer_t *p_pk;
        int           i;

        /* Arg, we need to drop packets, I don't do something clever (like
         * dropping complete pid, b frames, ... ), I just get the right amount
         * of packets and discard the others */
        msg_Warn( p_mux,
                  "packets=%d but max=%d -> removing %d packets -> stream broken",
                  i_packets, i_packets_max, i_packets - i_packets_max );

        BufferChainInit( c );
        for( i = 0; i < i_packets_max; i++ )
        {
            BufferChainAppend( c, BufferChainGet( &s ) );
        }

        while( ( p_pk = BufferChainGet( &s ) ) )
        {
            sout_BufferDelete( p_mux->p_sout, p_pk );
        }
873 874 875
    }
}

876
static void TSSetDate( sout_buffer_chain_t *c, mtime_t i_dts, mtime_t i_length )
877
{
878 879 880
    sout_buffer_t *p_ts;
    mtime_t       i_delta = i_length / c->i_depth;
    int           i_packet = 0;
881

882
    for( p_ts = c->p_first; p_ts != NULL; p_ts = p_ts->p_next )
883
    {
884 885
        p_ts->i_dts    = i_dts + i_packet * i_length / c->i_depth;  /* avoid rounding error */
        p_ts->i_length = i_delta;
886

887
        if( p_ts->i_flags&SOUT_BUFFER_FLAGS_PRIVATE_PCR_SOFT )
888
        {
889 890 891 892 893 894 895
            mtime_t i_pcr = 9 * p_ts->i_dts / 100;

            p_ts->p_buffer[6] = ( i_pcr >> 25 )&0xff;
            p_ts->p_buffer[7] = ( i_pcr >> 17 )&0xff;
            p_ts->p_buffer[8] = ( i_pcr >> 9  )&0xff;
            p_ts->p_buffer[9] = ( i_pcr >> 1  )&0xff;
            p_ts->p_buffer[10]= ( i_pcr << 7  )&0x80;
896 897
        }

898 899 900
        i_packet++;
    }
}
901

902 903 904 905 906 907 908 909
static void PEStoTS( sout_instance_t *p_sout,
                     sout_buffer_chain_t *c, sout_buffer_t *p_pes,
                     ts_stream_t *p_stream,
                     vlc_bool_t b_pcr )
{
    uint8_t *p_data;
    int     i_size;
    int     b_new_pes;
910

911 912 913
    /* get PES total size */
    i_size = p_pes->i_size;
    p_data = p_pes->p_buffer;
914

915 916 917 918 919
    /* Set pcr only with valid DTS */
    if( p_pes->i_dts <= 0 )
    {
        b_pcr = VLC_FALSE;
    }
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
    b_new_pes = VLC_TRUE;

    for( ;; )
    {
        int           b_adaptation_field;
        int           i_payload;
        int           i_copy;
        sout_buffer_t *p_ts;

        p_ts = sout_BufferNew( p_sout, 188 );
        /* write header
         * 8b   0x47    sync byte
         * 1b           transport_error_indicator
         * 1b           payload_unit_start
         * 1b           transport_priority
         * 13b          pid
         * 2b           transport_scrambling_control
         * 2b           if adaptation_field 0x03 else 0x01
         * 4b           continuity_counter
         */

        i_payload = 184 - ( b_pcr ? 8 : 0 );
        i_copy    = __MIN( i_size, i_payload );
        b_adaptation_field = (b_pcr||i_size<i_payload) ? VLC_TRUE : VLC_FALSE;

        p_ts->p_buffer[0] = 0x47;
        p_ts->p_buffer[1] = ( b_new_pes ? 0x40 : 0x00 )|
                            ( ( p_stream->i_pid >> 8 )&0x1f );
        p_ts->p_buffer[2] = p_stream->i_pid & 0xff;
        p_ts->p_buffer[3] = ( b_adaptation_field ? 0x30 : 0x10 )|
                            p_stream->i_continuity_counter;

        b_new_pes = VLC_FALSE;
        p_stream->i_continuity_counter = (p_stream->i_continuity_counter+1)%16;

        if( b_adaptation_field )
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
            int i;

            if( b_pcr )
            {
                mtime_t i_pcr = p_pes->i_dts * 9 / 100;
                int     i_stuffing = i_payload - i_copy;

                p_ts->p_buffer[4] = 7 + i_stuffing;
                p_ts->p_buffer[5] = 0x10;   /* flags */
                p_ts->p_buffer[6] = ( i_pcr >> 25 )&0xff;
                p_ts->p_buffer[7] = ( i_pcr >> 17 )&0xff;
                p_ts->p_buffer[8] = ( i_pcr >> 9  )&0xff;
                p_ts->p_buffer[9] = ( i_pcr >> 1  )&0xff;
                p_ts->p_buffer[10]= ( i_pcr << 7  )&0x80;
                p_ts->p_buffer[11]= 0;

                b_pcr = VLC_FALSE;
                for( i = 12; i < 12 + i_stuffing; i++ )
                {
                    p_ts->p_buffer[i] = 0xff;
                }
            }
            else
            {
                int i_stuffing = i_payload - i_copy;

                p_ts->p_buffer[4] = i_stuffing - 1;
                if( i_stuffing > 1 )
                {
                    p_ts->p_buffer[5] = 0x00;
                    for( i = 6; i < 6 + i_stuffing - 2; i++ )
                    {
                        p_ts->p_buffer[i] = 0xff;
                    }
                }
            }
994
        }
995 996 997 998
        /* copy payload */
        memcpy( &p_ts->p_buffer[188 - i_copy], p_data, i_copy );
        p_data += i_copy;
        i_size -= i_copy;
999

1000
        BufferChainAppend( c, p_ts );
1001

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
        if( i_size <= 0 )
        {
            sout_buffer_t *p_next = p_pes->p_next;

            p_pes->p_next = NULL;
            sout_BufferDelete( p_sout, p_pes );
            if( p_next == NULL )
            {
                break;
            }
            b_new_pes = VLC_TRUE;
            p_pes = p_next;
            i_size = p_pes->i_size;
            p_data = p_pes->p_buffer;
        }
1017 1018
    }

1019
    return;
1020 1021
}

gbazin's avatar
 
gbazin committed
1022
#if defined MODULE_NAME_IS_mux_ts
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