ts.c
资源名称:vlc-1.0.5.zip [点击查看]
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:96k
源码类别:
midi
开发平台:
Unix_Linux
- /*****************************************************************************
- * ts.c: MPEG-II TS Muxer
- *****************************************************************************
- * Copyright (C) 2001-2005 the VideoLAN team
- * $Id: dccd56043fd4333c3c36da94df7bd59066101586 $
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- * Eric Petit <titer@videolan.org>
- * Jean-Paul Saman <jpsaman #_at_# m2x.nl>
- * Wallace Wadge <wwadge #_at_# gmail.com>
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
- /*****************************************************************************
- * Preamble
- *****************************************************************************/
- #ifdef HAVE_CONFIG_H
- # include "config.h"
- #endif
- #include <limits.h>
- #include <vlc_common.h>
- #include <vlc_plugin.h>
- #include <vlc_sout.h>
- #include <vlc_codecs.h>
- #include <vlc_block.h>
- #include <vlc_iso_lang.h>
- #include "bits.h"
- #include "pes.h"
- #include "csa.h"
- #ifdef HAVE_DVBPSI_DR_H
- # include <dvbpsi/dvbpsi.h>
- # include <dvbpsi/demux.h>
- # include <dvbpsi/descriptor.h>
- # include <dvbpsi/pat.h>
- # include <dvbpsi/pmt.h>
- # include <dvbpsi/sdt.h>
- # include <dvbpsi/dr.h>
- # include <dvbpsi/psi.h>
- #else
- # include "dvbpsi.h"
- # include "demux.h"
- # include "descriptor.h"
- # include "tables/pat.h"
- # include "tables/pmt.h"
- # include "tables/sdt.h"
- # include "descriptors/dr.h"
- # include "psi.h"
- #endif
- /*
- * TODO:
- * - check PCR frequency requirement
- * - check PAT/PMT " "
- * - check PCR/PCR "soft"
- * - check if "registration" descriptor : "AC-3" should be a program
- * descriptor or an es one. (xine want an es one)
- *
- * - 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)
- */
- /*****************************************************************************
- * Callback prototypes
- *****************************************************************************/
- static int ChangeKeyCallback ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
- static int ActiveKeyCallback ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
- /*****************************************************************************
- * Module descriptor
- *****************************************************************************/
- static int Open ( vlc_object_t * );
- static void Close ( vlc_object_t * );
- #define VPID_TEXT N_("Video PID")
- #define VPID_LONGTEXT N_("Assign a fixed PID to the video stream. The PCR "
- "PID will automatically be the video.")
- #define APID_TEXT N_("Audio PID")
- #define APID_LONGTEXT N_("Assign a fixed PID to the audio stream.")
- #define SPUPID_TEXT N_("SPU PID")
- #define SPUPID_LONGTEXT N_("Assign a fixed PID to the SPU.")
- #define PMTPID_TEXT N_("PMT PID")
- #define PMTPID_LONGTEXT N_("Assign a fixed PID to the PMT")
- #define TSID_TEXT N_("TS ID")
- #define TSID_LONGTEXT N_("Assign a fixed Transport Stream ID.")
- #define NETID_TEXT N_("NET ID")
- #define NETID_LONGTEXT N_("Assign a fixed Network ID (for SDT table)")
- #define PMTPROG_TEXT N_("PMT Program numbers")
- #define PMTPROG_LONGTEXT N_("Assign a program number to each PMT. This "
- "requires "Set PID to ID of ES" to be enabled." )
- #define MUXPMT_TEXT N_("Mux PMT (requires --sout-ts-es-id-pid)")
- #define MUXPMT_LONGTEXT N_("Define the pids to add to each pmt. This "
- "requires "Set PID to ID of ES" to be enabled." )
- #define SDTDESC_TEXT N_("SDT Descriptors (requires --sout-ts-es-id-pid)")
- #define SDTDESC_LONGTEXT N_("Defines the descriptors of each SDT. This"
- "requires "Set PID to ID of ES" to be enabled." )
- #define PID_TEXT N_("Set PID to ID of ES")
- #define PID_LONGTEXT N_("Sets PID to the ID if the incoming ES. This is for "
- "use with --ts-es-id-pid, and allows to have the same PIDs in the input "
- "and output streams.")
- #define ALIGNMENT_TEXT N_("Data alignment")
- #define ALIGNMENT_LONGTEXT N_("Enforces alignment of all access units on "
- "PES boundaries. Disabling this might save some bandwidth but introduce incompatibilities.")
- #define SHAPING_TEXT N_("Shaping delay (ms)")
- #define SHAPING_LONGTEXT N_("Cut the "
- "stream in slices of the given duration, and ensure a constant bitrate "
- "between the two boundaries. This avoids having huge bitrate peaks, "
- "especially for reference frames." )
- #define KEYF_TEXT N_("Use keyframes")
- #define KEYF_LONGTEXT N_("If enabled, and shaping is specified, "
- "the TS muxer will place the boundaries at the end of I pictures. In "
- "that case, the shaping duration given by the user is a worse case "
- "used when no reference frame is available. This enhances the efficiency "
- "of the shaping algorithm, since I frames are usually the biggest "
- "frames in the stream.")
- #define PCR_TEXT N_("PCR delay (ms)")
- #define PCR_LONGTEXT N_("Set at which interval "
- "PCRs (Program Clock Reference) will be sent (in milliseconds). "
- "This value should be below 100ms. (default is 70ms).")
- #define BMIN_TEXT N_( "Minimum B (deprecated)")
- #define BMIN_LONGTEXT N_( "This setting is deprecated and not used anymore" )
- #define BMAX_TEXT N_( "Maximum B (deprecated)")
- #define BMAX_LONGTEXT N_( "This setting is deprecated and not used anymore")
- #define DTS_TEXT N_("DTS delay (ms)")
- #define DTS_LONGTEXT N_("Delay the DTS (decoding time "
- "stamps) and PTS (presentation timestamps) of the data in the "
- "stream, compared to the PCRs. This allows for some buffering inside "
- "the client decoder.")
- #define ACRYPT_TEXT N_("Crypt audio")
- #define ACRYPT_LONGTEXT N_("Crypt audio using CSA")
- #define VCRYPT_TEXT N_("Crypt video")
- #define VCRYPT_LONGTEXT N_("Crypt video using CSA")
- #define CK_TEXT N_("CSA Key")
- #define CK_LONGTEXT N_("CSA encryption key. This must be a "
- "16 char string (8 hexadecimal bytes).")
- #define CK2_TEXT N_("Second CSA Key")
- #define CK2_LONGTEXT N_("The even CSA encryption key. This must be a "
- "16 char string (8 hexadecimal bytes).")
- #define CU_TEXT N_("CSA Key in use")
- #define CU_LONGTEXT N_("CSA encryption key used. It can be the odd/first/1 "
- "(default) or the even/second/2 one.")
- #define CPKT_TEXT N_("Packet size in bytes to encrypt")
- #define CPKT_LONGTEXT N_("Size of the TS packet to encrypt. "
- "The encryption routines subtract the TS-header from the value before "
- "encrypting." )
- #define SOUT_CFG_PREFIX "sout-ts-"
- #define MAX_PMT 64 /* Maximum number of programs. FIXME: I just chose an arbitary number. Where is the maximum in the spec? */
- #define MAX_PMT_PID 64 /* Maximum pids in each pmt. FIXME: I just chose an arbitary number. Where is the maximum in the spec? */
- vlc_module_begin ()
- set_description( N_("TS muxer (libdvbpsi)") )
- set_shortname( "MPEG-TS")
- set_category( CAT_SOUT )
- set_subcategory( SUBCAT_SOUT_MUX )
- set_capability( "sout mux", 120 )
- add_shortcut( "ts" )
- add_integer( SOUT_CFG_PREFIX "pid-video", 0, NULL,VPID_TEXT, VPID_LONGTEXT,
- true )
- add_integer( SOUT_CFG_PREFIX "pid-audio", 0, NULL, APID_TEXT,
- APID_LONGTEXT, true )
- add_integer( SOUT_CFG_PREFIX "pid-spu", 0, NULL, SPUPID_TEXT,
- SPUPID_LONGTEXT, true )
- add_integer( SOUT_CFG_PREFIX "pid-pmt", 0, NULL, PMTPID_TEXT,
- PMTPID_LONGTEXT, true )
- add_integer( SOUT_CFG_PREFIX "tsid", 0, NULL, TSID_TEXT,
- TSID_LONGTEXT, true )
- #ifdef HAVE_DVBPSI_SDT
- add_integer( SOUT_CFG_PREFIX "netid", 0, NULL, NETID_TEXT,
- NETID_LONGTEXT, true )
- #endif
- add_string( SOUT_CFG_PREFIX "program-pmt", NULL, NULL, PMTPROG_TEXT,
- PMTPROG_LONGTEXT, true )
- add_bool( SOUT_CFG_PREFIX "es-id-pid", 0, NULL, PID_TEXT, PID_LONGTEXT,
- true )
- add_string( SOUT_CFG_PREFIX "muxpmt", NULL, NULL, MUXPMT_TEXT, MUXPMT_LONGTEXT, true )
- #ifdef HAVE_DVBPSI_SDT
- add_string( SOUT_CFG_PREFIX "sdtdesc", NULL, NULL, SDTDESC_TEXT, SDTDESC_LONGTEXT, true )
- #endif
- add_bool( SOUT_CFG_PREFIX "alignment", true, NULL, ALIGNMENT_TEXT,
- ALIGNMENT_LONGTEXT, true )
- add_integer( SOUT_CFG_PREFIX "shaping", 200, NULL, SHAPING_TEXT,
- SHAPING_LONGTEXT, true )
- add_bool( SOUT_CFG_PREFIX "use-key-frames", false, NULL, KEYF_TEXT,
- KEYF_LONGTEXT, true )
- add_integer( SOUT_CFG_PREFIX "pcr", 70, NULL, PCR_TEXT, PCR_LONGTEXT,
- true )
- add_integer( SOUT_CFG_PREFIX "bmin", 0, NULL, BMIN_TEXT, BMIN_LONGTEXT,
- true )
- add_integer( SOUT_CFG_PREFIX "bmax", 0, NULL, BMAX_TEXT, BMAX_LONGTEXT,
- true )
- add_integer( SOUT_CFG_PREFIX "dts-delay", 400, NULL, DTS_TEXT,
- DTS_LONGTEXT, true )
- add_bool( SOUT_CFG_PREFIX "crypt-audio", true, NULL, ACRYPT_TEXT,
- ACRYPT_LONGTEXT, true )
- add_bool( SOUT_CFG_PREFIX "crypt-video", true, NULL, VCRYPT_TEXT,
- VCRYPT_LONGTEXT, true )
- add_string( SOUT_CFG_PREFIX "csa-ck", NULL, NULL, CK_TEXT, CK_LONGTEXT,
- true )
- add_string( SOUT_CFG_PREFIX "csa2-ck", NULL, NULL, CK2_TEXT, CK2_LONGTEXT,
- true )
- add_string( SOUT_CFG_PREFIX "csa-use", "1", NULL, CU_TEXT, CU_LONGTEXT,
- true )
- add_integer( SOUT_CFG_PREFIX "csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true )
- set_callbacks( Open, Close )
- vlc_module_end ()
- /*****************************************************************************
- * Local data structures
- *****************************************************************************/
- static const char *const ppsz_sout_options[] = {
- "pid-video", "pid-audio", "pid-spu", "pid-pmt", "tsid", "netid",
- "es-id-pid", "shaping", "pcr", "bmin", "bmax", "use-key-frames",
- "dts-delay", "csa-ck", "csa2-ck", "csa-use", "csa-pkt", "crypt-audio", "crypt-video",
- "muxpmt", "sdtdesc", "program-pmt", "alignment",
- NULL
- };
- typedef struct pmt_map_t /* Holds the mapping between the pmt-pid/pmt table */
- {
- int i_pid;
- unsigned long i_prog;
- } pmt_map_t;
- typedef struct sdt_desc_t
- {
- char *psz_provider;
- char *psz_service_name; /* name of program */
- } sdt_desc_t;
- typedef struct
- {
- int i_depth;
- block_t *p_first;
- block_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, block_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 block_t *BufferChainGet( sout_buffer_chain_t *c )
- {
- block_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;
- }
- static inline block_t *BufferChainPeek( sout_buffer_chain_t *c )
- {
- block_t *b = c->p_first;
- return b;
- }
- static inline void BufferChainClean( sout_buffer_chain_t *c )
- {
- block_t *b;
- while( ( b = BufferChainGet( c ) ) )
- {
- block_Release( b );
- }
- BufferChainInit( c );
- }
- typedef struct ts_stream_t
- {
- int i_pid;
- vlc_fourcc_t i_codec;
- int i_stream_type;
- int i_stream_id;
- int i_continuity_counter;
- bool b_discontinuity;
- /* to be used for carriege of DIV3 */
- vlc_fourcc_t i_bih_codec;
- int i_bih_width, i_bih_height;
- /* Specific to mpeg4 in mpeg2ts */
- int i_es_id;
- int i_decoder_specific_info;
- uint8_t *p_decoder_specific_info;
- /* language is iso639-2T */
- int i_langs;
- uint8_t *lang;
- sout_buffer_chain_t chain_pes;
- mtime_t i_pes_dts;
- mtime_t i_pes_length;
- int i_pes_used;
- bool b_key_frame;
- } ts_stream_t;
- struct sout_mux_sys_t
- {
- int i_pcr_pid;
- sout_input_t *p_pcr_input;
- vlc_mutex_t csa_lock;
- int i_audio_bound;
- int i_video_bound;
- bool b_es_id_pid;
- bool b_sdt;
- int i_pid_video;
- int i_pid_audio;
- int i_pid_spu;
- int i_pid_free; /* first usable pid */
- int i_tsid;
- int i_netid;
- int i_num_pmt;
- int i_pmtslots;
- int i_pat_version_number;
- ts_stream_t pat;
- int i_pmt_version_number;
- ts_stream_t pmt[MAX_PMT];
- pmt_map_t pmtmap[MAX_PMT_PID];
- int i_pmt_program_number[MAX_PMT];
- sdt_desc_t sdt_descriptors[MAX_PMT];
- bool b_data_alignment;
- int i_mpeg4_streams;
- int i_null_continuity_counter; /* Needed ? */
- ts_stream_t sdt;
- dvbpsi_pmt_t *dvbpmt;
- /* for TS building */
- int64_t i_bitrate_min;
- int64_t i_bitrate_max;
- int64_t i_shaping_delay;
- int64_t i_pcr_delay;
- int64_t i_dts_delay;
- bool b_use_key_frames;
- mtime_t i_pcr; /* last PCR emited */
- csa_t *csa;
- int i_csa_pkt_size;
- bool b_crypt_audio;
- bool b_crypt_video;
- };
- /* Reserve a pid and return it */
- static int AllocatePID( sout_mux_sys_t *p_sys, int i_cat )
- {
- int i_pid;
- if ( i_cat == VIDEO_ES && p_sys->i_pid_video )
- {
- i_pid = p_sys->i_pid_video;
- p_sys->i_pid_video = 0;
- }
- else if ( i_cat == AUDIO_ES && p_sys->i_pid_audio )
- {
- i_pid = p_sys->i_pid_audio;
- p_sys->i_pid_audio = 0;
- }
- else if ( i_cat == SPU_ES && p_sys->i_pid_spu )
- {
- i_pid = p_sys->i_pid_spu;
- p_sys->i_pid_spu = 0;
- }
- else
- {
- i_pid = ++p_sys->i_pid_free;
- }
- return i_pid;
- }
- static int pmtcompare( const void *pa, const void *pb )
- {
- if ( ((pmt_map_t *)pa)->i_pid < ((pmt_map_t *)pb)->i_pid )
- return -1;
- else if ( ((pmt_map_t *)pa)->i_pid > ((pmt_map_t *)pb)->i_pid )
- return 1;
- else
- return 0;
- }
- static int intcompare( const void *pa, const void *pb )
- {
- if ( *(int *)pa < *(int *)pb )
- return -1;
- else if ( *(int *)pa > *(int *)pb )
- return 1;
- else
- return 0;
- }
- /*****************************************************************************
- * Local prototypes
- *****************************************************************************/
- static int Control ( sout_mux_t *, int, va_list );
- static int AddStream( sout_mux_t *, sout_input_t * );
- static int DelStream( sout_mux_t *, sout_input_t * );
- static int Mux ( sout_mux_t * );
- static block_t *FixPES( sout_mux_t *p_mux, block_fifo_t *p_fifo );
- static block_t *Add_ADTS( block_t *, es_format_t * );
- static void TSSchedule ( sout_mux_t *p_mux, sout_buffer_chain_t *p_chain_ts,
- mtime_t i_pcr_length, mtime_t i_pcr_dts );
- static void TSDate ( sout_mux_t *p_mux, sout_buffer_chain_t *p_chain_ts,
- mtime_t i_pcr_length, mtime_t i_pcr_dts );
- 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 );
- static block_t *TSNew( sout_mux_t *p_mux, ts_stream_t *p_stream, bool b_pcr );
- static void TSSetPCR( block_t *p_ts, mtime_t i_dts );
- static void PEStoTS ( sout_instance_t *, sout_buffer_chain_t *, block_t *, ts_stream_t * );
- /*****************************************************************************
- * Open:
- *****************************************************************************/
- static int Open( vlc_object_t *p_this )
- {
- sout_mux_t *p_mux =(sout_mux_t*)p_this;
- sout_mux_sys_t *p_sys = NULL;
- vlc_value_t val;
- int i;
- config_ChainParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
- p_sys = malloc( sizeof( sout_mux_sys_t ) );
- if( !p_sys )
- return VLC_ENOMEM;
- p_sys->i_pmtslots = p_sys->b_sdt = 0;
- p_sys->i_num_pmt = 1;
- p_sys->dvbpmt = NULL;
- memset( &p_sys->pmtmap, 0, sizeof(p_sys->pmtmap) );
- vlc_mutex_init( &p_sys->csa_lock );
- p_mux->pf_control = Control;
- p_mux->pf_addstream = AddStream;
- p_mux->pf_delstream = DelStream;
- p_mux->pf_mux = Mux;
- p_mux->p_sys = p_sys;
- srand( (uint32_t)mdate() );
- for ( i = 0; i < MAX_PMT; i++ )
- p_sys->sdt_descriptors[i].psz_service_name
- = p_sys->sdt_descriptors[i].psz_provider = NULL;
- memset( p_sys->sdt_descriptors, 0, sizeof(sdt_desc_t) );
- p_sys->i_audio_bound = 0;
- p_sys->i_video_bound = 0;
- var_Get( p_mux, SOUT_CFG_PREFIX "es-id-pid", &val );
- p_sys->b_es_id_pid = val.b_bool;
- var_Get( p_mux, SOUT_CFG_PREFIX "muxpmt", &val );
- /*
- fetch string of pmts. Here's a sample: --sout-ts-muxpmt="0x451,0x200,0x28a,0x240,,0x450,0x201,0x28b,0x241,,0x452,0x202,0x28c,0x242"
- This would mean 0x451, 0x200, 0x28a, 0x240 would fall under one pmt (program), 0x450,0x201,0x28b,0x241 would fall under another
- */
- if( val.psz_string != NULL && *val.psz_string )
- {
- char *psz_next;
- char *psz = val.psz_string;
- uint16_t i_pid;
- psz_next = psz;
- while( psz != NULL )
- {
- i_pid = strtoul( psz, &psz_next, 0 );
- if ( strlen(psz_next) > 0 )
- psz = &psz_next[1];
- if ( i_pid == 0 )
- {
- p_sys->i_num_pmt++;
- if ( p_sys->i_num_pmt > MAX_PMT )
- {
- msg_Err( p_mux,
- "Number of PMTs greater than compiled maximum (%d)", MAX_PMT );
- p_sys->i_num_pmt = MAX_PMT;
- }
- }
- else
- {
- p_sys->pmtmap[p_sys->i_pmtslots].i_pid = i_pid;
- p_sys->pmtmap[p_sys->i_pmtslots].i_prog = p_sys->i_num_pmt - 1;
- p_sys->i_pmtslots++;
- if ( p_sys->i_pmtslots > MAX_PMT_PID )
- {
- msg_Err( p_mux,
- "Number of pids in PMT greater than compiled maximum (%d)",
- MAX_PMT_PID );
- p_sys->i_pmtslots = MAX_PMT_PID;
- }
- }
- /* Now sort according to pids for fast search later on */
- qsort( (void *)p_sys->pmtmap, p_sys->i_pmtslots,
- sizeof(pmt_map_t), &pmtcompare );
- if ( !*psz_next )
- psz = NULL;
- }
- }
- free( val.psz_string );
- p_sys->i_pat_version_number = rand() % 32;
- p_sys->pat.i_pid = 0;
- p_sys->pat.i_continuity_counter = 0;
- p_sys->pat.b_discontinuity = false;
- var_Get( p_mux, SOUT_CFG_PREFIX "tsid", &val );
- if ( val.i_int )
- p_sys->i_tsid = val.i_int;
- else
- p_sys->i_tsid = rand() % 65536;
- p_sys->i_netid = rand() % 65536;
- #ifdef HAVE_DVBPSI_SDT
- var_Get( p_mux, SOUT_CFG_PREFIX "netid", &val );
- if ( val.i_int )
- p_sys->i_netid = val.i_int;
- #endif
- p_sys->i_pmt_version_number = rand() % 32;
- for( i = 0; i < p_sys->i_num_pmt; i++ )
- {
- p_sys->pmt[i].i_continuity_counter = 0;
- p_sys->pmt[i].b_discontinuity = false;
- }
- p_sys->sdt.i_pid = 0x11;
- p_sys->sdt.i_continuity_counter = 0;
- p_sys->sdt.b_discontinuity = false;
- #ifdef HAVE_DVBPSI_SDT
- var_Get( p_mux, SOUT_CFG_PREFIX "sdtdesc", &val );
- p_sys->b_sdt = val.psz_string && *val.psz_string ? true : false;
- /* Syntax is provider_sdt1,service_name_sdt1,provider_sdt2,service_name_sdt2... */
- if( p_sys->b_sdt )
- {
- char *psz = val.psz_string;
- char *psz_sdttoken = psz;
- i = 0;
- while ( psz_sdttoken != NULL )
- {
- char *psz_end = strchr( psz_sdttoken, ',' );
- if( psz_end != NULL )
- {
- *psz_end++ = ' ';
- }
- if ( !(i % 2) )
- {
- p_sys->sdt_descriptors[i/2].psz_provider
- = strdup(psz_sdttoken);
- }
- else
- {
- p_sys->sdt_descriptors[i/2].psz_service_name
- = strdup(psz_sdttoken);
- }
- i++;
- psz_sdttoken = psz_end;
- }
- }
- free( val.psz_string );
- #else
- p_sys->b_sdt = false;
- #endif
- var_Get( p_mux, SOUT_CFG_PREFIX "alignment", &val );
- p_sys->b_data_alignment = val.b_bool;
- var_Get( p_mux, SOUT_CFG_PREFIX "program-pmt", &val );
- if( val.psz_string && *val.psz_string )
- {
- char *psz_next;
- char *psz = val.psz_string;
- uint16_t i_pid;
- psz_next = psz;
- i = 0;
- while ( psz != NULL )
- {
- i_pid = strtoul( psz, &psz_next, 0 );
- if( strlen(psz_next) > 0 )
- psz = &psz_next[1];
- else
- psz = NULL;
- if( i_pid == 0 )
- {
- if( i > MAX_PMT )
- msg_Err( p_mux, "Number of PMTs > maximum (%d)",
- MAX_PMT );
- }
- else
- {
- p_sys->i_pmt_program_number[i] = i_pid;
- i++;
- }
- }
- }
- else
- {
- /* Option not specified, use 1, 2, 3... */
- for( i = 0; i < p_sys->i_num_pmt; i++ )
- p_sys->i_pmt_program_number[i] = i + 1;
- }
- free( val.psz_string );
- var_Get( p_mux, SOUT_CFG_PREFIX "pid-pmt", &val );
- if( val.i_int )
- {
- for( i = 0; i < p_sys->i_num_pmt; i++ )
- p_sys->pmt[i].i_pid = val.i_int + i; /* Does this make any sense? */
- }
- else
- {
- for( i = 0; i < p_sys->i_num_pmt; i++ )
- p_sys->pmt[i].i_pid = 0x42 + i;
- }
- p_sys->i_pid_free = p_sys->pmt[p_sys->i_num_pmt - 1].i_pid + 1;
- var_Get( p_mux, SOUT_CFG_PREFIX "pid-video", &val );
- p_sys->i_pid_video = val.i_int;
- if ( p_sys->i_pid_video > p_sys->i_pid_free )
- {
- p_sys->i_pid_free = p_sys->i_pid_video + 1;
- }
- var_Get( p_mux, SOUT_CFG_PREFIX "pid-audio", &val );
- p_sys->i_pid_audio = val.i_int;
- if ( p_sys->i_pid_audio > p_sys->i_pid_free )
- {
- p_sys->i_pid_free = p_sys->i_pid_audio + 1;
- }
- var_Get( p_mux, SOUT_CFG_PREFIX "pid-spu", &val );
- p_sys->i_pid_spu = val.i_int;
- if ( p_sys->i_pid_spu > p_sys->i_pid_free )
- {
- p_sys->i_pid_free = p_sys->i_pid_spu + 1;
- }
- p_sys->i_pcr_pid = 0x1fff;
- p_sys->p_pcr_input = NULL;
- p_sys->i_mpeg4_streams = 0;
- p_sys->i_null_continuity_counter = 0;
- /* Allow to create constrained stream */
- var_Get( p_mux, SOUT_CFG_PREFIX "bmin", &val );
- p_sys->i_bitrate_min = val.i_int;
- var_Get( p_mux, SOUT_CFG_PREFIX "bmax", &val );
- p_sys->i_bitrate_max = val.i_int;
- if( p_sys->i_bitrate_min > 0 && p_sys->i_bitrate_max > 0 &&
- p_sys->i_bitrate_min > p_sys->i_bitrate_max )
- {
- msg_Err( p_mux, "incompatible minimum and maximum bitrate, "
- "disabling bitrate control" );
- p_sys->i_bitrate_min = 0;
- p_sys->i_bitrate_max = 0;
- }
- if( p_sys->i_bitrate_min > 0 || p_sys->i_bitrate_max > 0 )
- {
- msg_Err( p_mux, "bmin and bmax no more supported "
- "(if you need them report it)" );
- }
- var_Get( p_mux, SOUT_CFG_PREFIX "shaping", &val );
- p_sys->i_shaping_delay = (int64_t)val.i_int * 1000;
- if( p_sys->i_shaping_delay <= 0 )
- {
- msg_Err( p_mux,
- "invalid shaping (%"PRId64"ms) resetting to 200ms",
- p_sys->i_shaping_delay / 1000 );
- p_sys->i_shaping_delay = 200000;
- }
- var_Get( p_mux, SOUT_CFG_PREFIX "pcr", &val );
- p_sys->i_pcr_delay = (int64_t)val.i_int * 1000;
- if( p_sys->i_pcr_delay <= 0 ||
- p_sys->i_pcr_delay >= p_sys->i_shaping_delay )
- {
- msg_Err( p_mux,
- "invalid pcr delay (%"PRId64"ms) resetting to 70ms",
- p_sys->i_pcr_delay / 1000 );
- p_sys->i_pcr_delay = 70000;
- }
- var_Get( p_mux, SOUT_CFG_PREFIX "dts-delay", &val );
- p_sys->i_dts_delay = (int64_t)val.i_int * 1000;
- msg_Dbg( p_mux, "shaping=%"PRId64" pcr=%"PRId64" dts_delay=%"PRId64,
- p_sys->i_shaping_delay, p_sys->i_pcr_delay, p_sys->i_dts_delay );
- var_Get( p_mux, SOUT_CFG_PREFIX "use-key-frames", &val );
- p_sys->b_use_key_frames = val.b_bool;
- /* for TS generation */
- p_sys->i_pcr = 0;
- p_sys->csa = NULL;
- var_Create( p_mux, SOUT_CFG_PREFIX "csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
- var_Get( p_mux, SOUT_CFG_PREFIX "csa-ck", &val );
- if( val.psz_string && *val.psz_string )
- {
- int i_res;
- vlc_value_t csa2;
- p_sys->csa = csa_New();
- var_Create( p_mux, SOUT_CFG_PREFIX "csa2-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
- var_Get( p_mux, SOUT_CFG_PREFIX "csa2-ck", &csa2 );
- i_res = csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, true );
- if( i_res == VLC_SUCCESS && csa2.psz_string && *csa2.psz_string )
- {
- if( csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, csa2.psz_string, false ) != VLC_SUCCESS )
- {
- csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, false );
- }
- }
- else if( i_res == VLC_SUCCESS )
- {
- csa_SetCW( (vlc_object_t*)p_mux, p_sys->csa, val.psz_string, false );
- }
- else
- {
- csa_Delete( p_sys->csa );
- p_sys->csa = NULL;
- }
- if( p_sys->csa )
- {
- vlc_value_t use_val, pkt_val;
- var_Create( p_mux, SOUT_CFG_PREFIX "csa-use", VLC_VAR_STRING | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
- var_Get( p_mux, SOUT_CFG_PREFIX "csa-use", &use_val );
- var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa-use", ActiveKeyCallback, NULL );
- var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa-ck", ChangeKeyCallback, (void *)1 );
- var_AddCallback( p_mux, SOUT_CFG_PREFIX "csa2-ck", ChangeKeyCallback, NULL );
- if ( var_Set( p_mux, SOUT_CFG_PREFIX "csa-use", use_val ) != VLC_SUCCESS )
- {
- var_SetString( p_mux, SOUT_CFG_PREFIX "csa-use", "odd" );
- }
- free( use_val.psz_string );
- var_Get( p_mux, SOUT_CFG_PREFIX "csa-pkt", &pkt_val );
- if( pkt_val.i_int < 12 || pkt_val.i_int > 188 )
- {
- msg_Err( p_mux, "wrong packet size %d specified.", pkt_val.i_int );
- msg_Warn( p_mux, "using default packet size of 188 bytes" );
- p_sys->i_csa_pkt_size = 188;
- }
- else p_sys->i_csa_pkt_size = pkt_val.i_int;
- msg_Dbg( p_mux, "encrypting %d bytes of packet", p_sys->i_csa_pkt_size );
- }
- free( csa2.psz_string );
- }
- free( val.psz_string );
- var_Get( p_mux, SOUT_CFG_PREFIX "crypt-audio", &val );
- p_sys->b_crypt_audio = val.b_bool;
- var_Get( p_mux, SOUT_CFG_PREFIX "crypt-video", &val );
- p_sys->b_crypt_video = val.b_bool;
- return VLC_SUCCESS;
- }
- /*****************************************************************************
- * Close:
- *****************************************************************************/
- static void Close( vlc_object_t * p_this )
- {
- sout_mux_t *p_mux = (sout_mux_t*)p_this;
- sout_mux_sys_t *p_sys = p_mux->p_sys;
- int i;
- vlc_mutex_lock( &p_sys->csa_lock );
- if( p_sys->csa )
- {
- var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa-ck", ChangeKeyCallback, NULL );
- var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa2-ck", ChangeKeyCallback, NULL );
- var_DelCallback( p_mux, SOUT_CFG_PREFIX "csa-use", ActiveKeyCallback, NULL );
- csa_Delete( p_sys->csa );
- p_sys->csa = NULL;
- }
- vlc_mutex_unlock( &p_sys->csa_lock );
- for( i = 0; i < MAX_PMT; i++ )
- {
- free( p_sys->sdt_descriptors[i].psz_service_name );
- free( p_sys->sdt_descriptors[i].psz_provider );
- }
- vlc_mutex_destroy( &p_sys->csa_lock );
- free( p_sys->dvbpmt );
- free( p_sys );
- }
- /*****************************************************************************
- * ChangeKeyCallback: called when changing the odd encryption key on the fly.
- *****************************************************************************/
- static int ChangeKeyCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval,
- void *p_data )
- {
- VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
- sout_mux_t *p_mux = (sout_mux_t*)p_this;
- sout_mux_sys_t *p_sys = p_mux->p_sys;
- int ret;
- vlc_mutex_lock( &p_sys->csa_lock );
- ret = csa_SetCW( p_this, p_sys->csa, newval.psz_string,
- !!(intptr_t)p_data );
- vlc_mutex_unlock( &p_sys->csa_lock );
- return ret;
- }
- /*****************************************************************************
- * ActiveKeyCallback: called when changing the active (in use) encryption key on the fly.
- *****************************************************************************/
- static int ActiveKeyCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval,
- void *p_data )
- {
- VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
- sout_mux_t *p_mux = (sout_mux_t*)p_this;
- sout_mux_sys_t *p_sys = p_mux->p_sys;
- int i_res = VLC_EBADVAR;
- vlc_mutex_lock( &p_sys->csa_lock );
- if( !strcmp(newval.psz_string, "odd" ) || !strcmp(newval.psz_string, "first" ) || !strcmp(newval.psz_string, "1" ) )
- {
- i_res = csa_UseKey( (vlc_object_t*)p_mux, p_sys->csa, 1 );
- }
- else if( !strcmp(newval.psz_string, "even" ) || !strcmp(newval.psz_string, "second" ) || !strcmp(newval.psz_string, "2" ) )
- {
- i_res = csa_UseKey( (vlc_object_t*)p_mux, p_sys->csa, 0 );
- }
- vlc_mutex_unlock( &p_sys->csa_lock );
- return i_res;
- }
- /*****************************************************************************
- * Control:
- *****************************************************************************/
- static int Control( sout_mux_t *p_mux, int i_query, va_list args )
- {
- VLC_UNUSED(p_mux);
- bool *pb_bool;
- char **ppsz;
- switch( i_query )
- {
- case MUX_CAN_ADD_STREAM_WHILE_MUXING:
- pb_bool = (bool*)va_arg( args, bool * );
- *pb_bool = true;
- return VLC_SUCCESS;
- case MUX_GET_ADD_STREAM_WAIT:
- pb_bool = (bool*)va_arg( args, bool * );
- *pb_bool = false;
- return VLC_SUCCESS;
- case MUX_GET_MIME:
- ppsz = (char**)va_arg( args, char ** );
- *ppsz = strdup( "video/mpeg" ); /* FIXME not sure */
- return VLC_SUCCESS;
- default:
- return VLC_EGENERIC;
- }
- }
- /*****************************************************************************
- * AddStream: called for each stream addition
- *****************************************************************************/
- static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
- {
- sout_mux_sys_t *p_sys = p_mux->p_sys;
- ts_stream_t *p_stream;
- int i;
- p_input->p_sys = p_stream = malloc( sizeof( ts_stream_t ) );
- if( !p_input->p_sys )
- return VLC_ENOMEM;
- /* Init this new stream */
- if ( p_sys->b_es_id_pid )
- p_stream->i_pid = p_input->p_fmt->i_id & 0x1fff;
- else
- p_stream->i_pid = AllocatePID( p_sys, p_input->p_fmt->i_cat );
- p_stream->i_codec = p_input->p_fmt->i_codec;
- p_stream->i_continuity_counter = 0;
- p_stream->b_discontinuity = false;
- p_stream->i_decoder_specific_info = 0;
- p_stream->p_decoder_specific_info = NULL;
- msg_Dbg( p_mux, "adding input codec=%4.4s pid=%d",
- (char*)&p_input->p_fmt->i_codec, p_stream->i_pid );
- /* All others fields depand on codec */
- switch( p_input->p_fmt->i_cat )
- {
- case VIDEO_ES:
- switch( p_input->p_fmt->i_codec )
- {
- case VLC_FOURCC( 'm', 'p','g', 'v' ):
- /* TODO: do we need to check MPEG-I/II ? */
- p_stream->i_stream_type = 0x02;
- p_stream->i_stream_id = 0xe0;
- break;
- case VLC_FOURCC( 'm', 'p','4', 'v' ):
- p_stream->i_stream_type = 0x10;
- p_stream->i_stream_id = 0xe0;
- p_stream->i_es_id = p_stream->i_pid;
- break;
- case VLC_FOURCC( 'h', '2','6', '4' ):
- p_stream->i_stream_type = 0x1b;
- p_stream->i_stream_id = 0xe0;
- break;
- /* 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' ):
- case VLC_FOURCC( 'W', 'M', 'V', '3' ):
- case VLC_FOURCC( 'W', 'M', 'V', '2' ):
- 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' ):
- case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
- p_stream->i_stream_type = 0xa0; /* private */
- p_stream->i_stream_id = 0xa0; /* beurk */
- p_stream->i_bih_codec = p_input->p_fmt->i_codec;
- p_stream->i_bih_width = p_input->p_fmt->video.i_width;
- p_stream->i_bih_height = p_input->p_fmt->video.i_height;
- break;
- case VLC_FOURCC( 'd', 'r', 'a', 'c' ):
- /* stream_id makes use of stream_id_extension */
- p_stream->i_stream_id = (PES_EXTENDED_STREAM_ID << 8) | 0x60;
- p_stream->i_stream_type = 0xd1;
- break;
- default:
- free( p_stream );
- return VLC_EGENERIC;
- }
- p_sys->i_video_bound++;
- break;
- case AUDIO_ES:
- switch( p_input->p_fmt->i_codec )
- {
- case VLC_FOURCC( 'm', 'p','g', 'a' ):
- case VLC_FOURCC( 'm', 'p', '3', ' ' ):
- p_stream->i_stream_type =
- p_input->p_fmt->audio.i_rate >= 32000 ? 0x03 : 0x04;
- p_stream->i_stream_id = 0xc0;
- break;
- case VLC_FOURCC( 'a', '5','2', ' ' ):
- p_stream->i_stream_type = 0x81;
- p_stream->i_stream_id = 0xbd;
- break;
- case VLC_FOURCC( 'l', 'p','c', 'm' ):
- p_stream->i_stream_type = 0x83;
- p_stream->i_stream_id = 0xbd;
- break;
- case VLC_FOURCC( 'd', 't','s', ' ' ):
- p_stream->i_stream_type = 0x06;
- p_stream->i_stream_id = 0xbd;
- break;
- case VLC_FOURCC( 'm', 'p','4', 'a' ):
- /* XXX: make that configurable in some way when LOAS
- * is implemented for AAC in TS */
- //p_stream->i_stream_type = 0x11; /* LOAS/LATM */
- p_stream->i_stream_type = 0x0f; /* ADTS */
- p_stream->i_stream_id = 0xc0;
- p_sys->i_mpeg4_streams++;
- p_stream->i_es_id = p_stream->i_pid;
- break;
- default:
- free( p_stream );
- return VLC_EGENERIC;
- }
- p_sys->i_audio_bound++;
- break;
- case SPU_ES:
- switch( p_input->p_fmt->i_codec )
- {
- case VLC_FOURCC( 's', 'p','u', ' ' ):
- p_stream->i_stream_type = 0x82;
- p_stream->i_stream_id = 0xbd;
- break;
- case VLC_FOURCC( 's', 'u','b', 't' ):
- p_stream->i_stream_type = 0x12;
- p_stream->i_stream_id = 0xfa;
- p_sys->i_mpeg4_streams++;
- p_stream->i_es_id = p_stream->i_pid;
- break;
- case VLC_FOURCC('d','v','b','s'):
- p_stream->i_stream_type = 0x06;
- p_stream->i_es_id = p_input->p_fmt->subs.dvb.i_id;
- p_stream->i_stream_id = 0xbd;
- break;
- case VLC_FOURCC('t','e','l','x'):
- p_stream->i_stream_type = 0x06;
- p_stream->i_stream_id = 0xbd; /* FIXME */
- break;
- default:
- free( p_stream );
- return VLC_EGENERIC;
- }
- break;
- default:
- free( p_stream );
- return VLC_EGENERIC;
- }
- p_stream->i_langs = 1+p_input->p_fmt->i_extra_languages;
- p_stream->lang = malloc(p_stream->i_langs*3);
- if( !p_stream->lang )
- {
- p_stream->i_langs = 0;
- free( p_stream );
- return VLC_ENOMEM;
- }
- i = 1;
- p_stream->lang[0] =
- p_stream->lang[1] =
- p_stream->lang[2] = ' ';
- if( p_input->p_fmt->psz_language )
- {
- char *psz = p_input->p_fmt->psz_language;
- const iso639_lang_t *pl = NULL;
- if( strlen( psz ) == 2 )
- {
- pl = GetLang_1( psz );
- }
- else if( strlen( psz ) == 3 )
- {
- pl = GetLang_2B( psz );
- if( !strcmp( pl->psz_iso639_1, "??" ) )
- {
- pl = GetLang_2T( psz );
- }
- }
- if( pl && strcmp( pl->psz_iso639_1, "??" ) )
- {
- p_stream->lang[0] = pl->psz_iso639_2T[0];
- p_stream->lang[1] = pl->psz_iso639_2T[1];
- p_stream->lang[2] = pl->psz_iso639_2T[2];
- msg_Dbg( p_mux, " - lang=%c%c%c",
- p_stream->lang[0], p_stream->lang[1],
- p_stream->lang[2] );
- }
- }
- while( i < p_stream->i_langs ) {
- if( p_input->p_fmt->p_extra_languages[i-1].psz_language )
- {
- char *psz = p_input->p_fmt->p_extra_languages[i-1].psz_language;
- const iso639_lang_t *pl = NULL;
- if( strlen( psz ) == 2 )
- {
- pl = GetLang_1( psz );
- }
- else if( strlen( psz ) == 3 )
- {
- pl = GetLang_2B( psz );
- if( !strcmp( pl->psz_iso639_1, "??" ) )
- {
- pl = GetLang_2T( psz );
- }
- }
- if( pl && strcmp( pl->psz_iso639_1, "??" ) )
- {
- p_stream->lang[i*3+0] = pl->psz_iso639_2T[0];
- p_stream->lang[i*3+1] = pl->psz_iso639_2T[1];
- p_stream->lang[i*3+2] = pl->psz_iso639_2T[2];
- msg_Dbg( p_mux, " - lang=%c%c%c",
- p_stream->lang[i*3+0], p_stream->lang[i*3+1],
- p_stream->lang[i*3+2] );
- }
- }
- i++;
- }
- /* Create decoder specific info for subt */
- if( p_stream->i_codec == VLC_FOURCC( 's', 'u','b', 't' ) )
- {
- uint8_t *p;
- p_stream->i_decoder_specific_info = 55;
- p_stream->p_decoder_specific_info = p =
- malloc( p_stream->i_decoder_specific_info );
- if( p )
- {
- p[0] = 0x10; /* textFormat, 0x10 for 3GPP TS 26.245 */
- p[1] = 0x00; /* flags: 1b: associated video info flag
- 3b: reserved
- 1b: duration flag
- 3b: reserved */
- p[2] = 52; /* remaining size */
- p += 3;
- p[0] = p[1] = p[2] = p[3] = 0; p+=4; /* display flags */
- *p++ = 0; /* horizontal justification (-1: left, 0 center, 1 right) */
- *p++ = 1; /* vertical justification (-1: top, 0 center, 1 bottom) */
- p[0] = p[1] = p[2] = 0x00; p+=3;/* background rgb */
- *p++ = 0xff; /* background a */
- p[0] = p[1] = 0; p += 2; /* text box top */
- p[0] = p[1] = 0; p += 2; /* text box left */
- p[0] = p[1] = 0; p += 2; /* text box bottom */
- p[0] = p[1] = 0; p += 2; /* text box right */
- p[0] = p[1] = 0; p += 2; /* start char */
- p[0] = p[1] = 0; p += 2; /* end char */
- p[0] = p[1] = 0; p += 2; /* default font id */
- *p++ = 0; /* font style flags */
- *p++ = 12; /* font size */
- p[0] = p[1] = p[2] = 0x00; p+=3;/* foreground rgb */
- *p++ = 0x00; /* foreground a */
- p[0] = p[1] = p[2] = 0; p[3] = 22; p += 4;
- memcpy( p, "ftab", 4 ); p += 4;
- *p++ = 0; *p++ = 1; /* entry count */
- p[0] = p[1] = 0; p += 2; /* font id */
- *p++ = 9; /* font name length */
- memcpy( p, "Helvetica", 9 ); /* font name */
- }
- else p_stream->i_decoder_specific_info = 0;
- }
- else
- {
- /* Copy extra data (VOL for MPEG-4 and extra BitMapInfoHeader for VFW */
- p_stream->i_decoder_specific_info = p_input->p_fmt->i_extra;
- if( p_stream->i_decoder_specific_info > 0 )
- {
- p_stream->p_decoder_specific_info =
- malloc( p_stream->i_decoder_specific_info );
- if( p_stream->p_decoder_specific_info )
- {
- memcpy( p_stream->p_decoder_specific_info,
- p_input->p_fmt->p_extra,
- p_input->p_fmt->i_extra );
- }
- else p_stream->i_decoder_specific_info = 0;
- }
- }
- /* Init pes chain */
- BufferChainInit( &p_stream->chain_pes );
- p_stream->i_pes_dts = 0;
- p_stream->i_pes_length = 0;
- p_stream->i_pes_used = 0;
- p_stream->b_key_frame = 0;
- /* 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 ) )
- {
- if( p_sys->p_pcr_input )
- {
- /* There was already a PCR stream, so clean context */
- /* FIXME */
- }
- p_sys->i_pcr_pid = p_stream->i_pid;
- p_sys->p_pcr_input = p_input;
- msg_Dbg( p_mux, "new PCR PID is %d", p_sys->i_pcr_pid );
- }
- return VLC_SUCCESS;
- }
- /*****************************************************************************
- * DelStream: called before a stream deletion
- *****************************************************************************/
- static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
- {
- sout_mux_sys_t *p_sys = p_mux->p_sys;
- ts_stream_t *p_stream;
- vlc_value_t val;
- p_stream = (ts_stream_t*)p_input->p_sys;
- msg_Dbg( p_mux, "removing input pid=%d", p_stream->i_pid );
- 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;
- p_sys->p_pcr_input = NULL;
- 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 )
- {
- p_sys->i_pcr_pid =
- ((ts_stream_t*)p_mux->pp_inputs[i]->p_sys)->i_pid;
- p_sys->p_pcr_input= p_mux->pp_inputs[i];
- break;
- }
- else if( p_mux->pp_inputs[i]->p_fmt->i_cat != SPU_ES &&
- p_sys->i_pcr_pid == 0x1fff )
- {
- p_sys->i_pcr_pid =
- ((ts_stream_t*)p_mux->pp_inputs[i]->p_sys)->i_pid;
- p_sys->p_pcr_input= p_mux->pp_inputs[i];
- }
- }
- if( p_sys->p_pcr_input )
- {
- /* Empty TS buffer */
- /* FIXME */
- }
- msg_Dbg( p_mux, "new PCR PID is %d", p_sys->i_pcr_pid );
- }
- /* Empty all data in chain_pes */
- BufferChainClean( &p_stream->chain_pes );
- free(p_stream->lang);
- free( p_stream->p_decoder_specific_info );
- if( p_stream->i_stream_id == 0xfa ||
- p_stream->i_stream_id == 0xfb ||
- p_stream->i_stream_id == 0xfe )
- {
- p_sys->i_mpeg4_streams--;
- }
- var_Get( p_mux, SOUT_CFG_PREFIX "pid-video", &val );
- if( val.i_int > 0 )
- {
- int i_pid_video = val.i_int;
- if ( i_pid_video == p_stream->i_pid )
- {
- p_sys->i_pid_video = i_pid_video;
- msg_Dbg( p_mux, "freeing video PID %d", i_pid_video );
- }
- }
- var_Get( p_mux, SOUT_CFG_PREFIX "pid-audio", &val );
- if( val.i_int > 0 )
- {
- int i_pid_audio = val.i_int;
- if ( i_pid_audio == p_stream->i_pid )
- {
- p_sys->i_pid_audio = i_pid_audio;
- msg_Dbg( p_mux, "freeing audio PID %d", i_pid_audio );
- }
- }
- var_Get( p_mux, SOUT_CFG_PREFIX "pid-spu", &val );
- if( val.i_int > 0 )
- {
- int i_pid_spu = val.i_int;
- if ( i_pid_spu == p_stream->i_pid )
- {
- p_sys->i_pid_spu = i_pid_spu;
- msg_Dbg( p_mux, "freeing spu PID %d", i_pid_spu );
- }
- }
- free( p_stream );
- /* We only change PMT version (PAT isn't changed) */
- p_sys->i_pmt_version_number++; p_sys->i_pmt_version_number %= 32;
- return VLC_SUCCESS;
- }
- /*****************************************************************************
- * 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;
- ts_stream_t *p_pcr_stream;
- if( p_sys->i_pcr_pid == 0x1fff )
- {
- int i;
- for( i = 0; i < p_mux->i_nb_inputs; i++ )
- {
- block_FifoEmpty( p_mux->pp_inputs[i]->p_fifo );
- }
- msg_Dbg( p_mux, "waiting for PCR streams" );
- msleep( 1000 );
- return VLC_SUCCESS;
- }
- p_pcr_stream = (ts_stream_t*)p_sys->p_pcr_input->p_sys;
- for( ;; )
- {
- sout_buffer_chain_t chain_ts;
- int i_packet_count;
- int i_packet_pos;
- mtime_t i_pcr_dts;
- mtime_t i_pcr_length;
- mtime_t i_shaping_delay;
- int i;
- if( p_pcr_stream->b_key_frame )
- {
- i_shaping_delay = p_pcr_stream->i_pes_length;
- }
- else
- {
- i_shaping_delay = p_sys->i_shaping_delay;
- }
- /* 1: get enough PES packet for all input */
- for( ;; )
- {
- bool b_ok = true;
- block_t *p_data;
- /* Accumulate enough data in the pcr stream (>i_shaping_delay) */
- /* Accumulate enough data in all other stream ( >= length of pcr)*/
- for( i = -1; i < p_mux->i_nb_inputs; i++ )
- {
- sout_input_t *p_input;
- ts_stream_t *p_stream;
- int64_t i_spu_delay = 0;
- if( i == -1 )
- p_input = p_sys->p_pcr_input;
- else if( p_mux->pp_inputs[i]->p_sys == p_pcr_stream )
- continue;
- else
- p_input = p_mux->pp_inputs[i];
- p_stream = (ts_stream_t*)p_input->p_sys;
- if( ( ( p_stream == p_pcr_stream ) &&
- ( p_stream->i_pes_length < i_shaping_delay ) ) ||
- ( p_stream->i_pes_dts + p_stream->i_pes_length <
- p_pcr_stream->i_pes_dts + p_pcr_stream->i_pes_length ) )
- {
- /* Need more data */
- if( block_FifoCount( p_input->p_fifo ) <= 1 )
- {
- if( ( p_input->p_fmt->i_cat == AUDIO_ES ) ||
- ( p_input->p_fmt->i_cat == VIDEO_ES ) )
- {
- /* We need more data */
- return VLC_SUCCESS;
- }
- else if( block_FifoCount( p_input->p_fifo ) <= 0 )
- {
- /* spu, only one packet is needed */
- continue;
- }
- else if( p_input->p_fmt->i_cat == SPU_ES )
- {
- /* Don't mux the SPU yet if it is too early */
- block_t *p_spu = block_FifoShow( p_input->p_fifo );
- i_spu_delay =
- p_spu->i_dts - p_pcr_stream->i_pes_dts;
- if( ( i_spu_delay > i_shaping_delay ) &&
- ( i_spu_delay < INT64_C(100000000) ) )
- continue;
- if ( ( i_spu_delay >= INT64_C(100000000) ) ||
- ( i_spu_delay < INT64_C(10000) ) )
- {
- BufferChainClean( &p_stream->chain_pes );
- p_stream->i_pes_dts = 0;
- p_stream->i_pes_used = 0;
- p_stream->i_pes_length = 0;
- continue;
- }
- }
- }
- b_ok = false;
- if( p_stream == p_pcr_stream || p_sys->b_data_alignment
- || p_input->p_fmt->i_codec !=
- VLC_FOURCC('m', 'p', 'g', 'a') )
- {
- p_data = block_FifoGet( p_input->p_fifo );
- if( p_input->p_fmt->i_codec ==
- VLC_FOURCC('m', 'p', '4', 'a' ) )
- p_data = Add_ADTS( p_data, p_input->p_fmt );
- }
- else
- p_data = FixPES( p_mux, p_input->p_fifo );
- if( block_FifoCount( p_input->p_fifo ) > 0 &&
- p_input->p_fmt->i_cat != SPU_ES )
- {
- block_t *p_next = block_FifoShow( p_input->p_fifo );
- p_data->i_length = p_next->i_dts - p_data->i_dts;
- }
- else if( p_input->p_fmt->i_codec !=
- VLC_FOURCC('s', 'u', 'b', 't' ) )
- p_data->i_length = 1000;
- if( ( p_pcr_stream->i_pes_dts > 0 &&
- p_data->i_dts - 10000000 > p_pcr_stream->i_pes_dts +
- p_pcr_stream->i_pes_length ) ||
- p_data->i_dts < p_stream->i_pes_dts ||
- ( p_stream->i_pes_dts > 0 &&
- p_input->p_fmt->i_cat != SPU_ES &&
- p_data->i_dts - 10000000 > p_stream->i_pes_dts +
- p_stream->i_pes_length ) )
- {
- msg_Warn( p_mux, "packet with too strange dts "
- "(dts=%"PRId64",old=%"PRId64",pcr=%"PRId64")",
- p_data->i_dts, p_stream->i_pes_dts,
- p_pcr_stream->i_pes_dts );
- block_Release( p_data );
- BufferChainClean( &p_stream->chain_pes );
- p_stream->i_pes_dts = 0;
- p_stream->i_pes_used = 0;
- p_stream->i_pes_length = 0;
- if( p_input->p_fmt->i_cat != SPU_ES )
- {
- BufferChainClean( &p_pcr_stream->chain_pes );
- p_pcr_stream->i_pes_dts = 0;
- p_pcr_stream->i_pes_used = 0;
- p_pcr_stream->i_pes_length = 0;
- }
- }
- else
- {
- int i_header_size = 0;
- int i_max_pes_size = 0;
- int b_data_alignment = 0;
- if( p_input->p_fmt->i_cat == SPU_ES )
- {
- if( p_input->p_fmt->i_codec ==
- VLC_FOURCC('s','u','b','t') )
- {
- /* Prepend header */
- p_data = block_Realloc( p_data, 2,
- p_data->i_buffer );
- p_data->p_buffer[0] =
- ( (p_data->i_buffer - 2) >> 8) & 0xff;
- p_data->p_buffer[1] =
- ( (p_data->i_buffer - 2) ) & 0xff;
- /* remove trailling