ts.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:68k
- /*****************************************************************************
- * ts.c: MPEG-II TS Muxer
- *****************************************************************************
- * Copyright (C) 2001, 2002 VideoLAN
- * $Id: ts.c 9132 2004-11-04 13:02:38Z zorglub $
- *
- * 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 "iso_lang.h"
- #include "bits.h"
- #include "pes.h"
- #include "csa.h"
- #ifdef HAVE_DVBPSI_DR_H
- # include <dvbpsi/dvbpsi.h>
- # include <dvbpsi/descriptor.h>
- # include <dvbpsi/pat.h>
- # include <dvbpsi/pmt.h>
- # include <dvbpsi/dr.h>
- # include <dvbpsi/psi.h>
- #else
- # include "dvbpsi.h"
- # include "descriptor.h"
- # include "tables/pat.h"
- # include "tables/pmt.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)
- */
- /*****************************************************************************
- * Module descriptor
- *****************************************************************************/
- static int Open ( vlc_object_t * );
- static void Close ( vlc_object_t * );
- #define VPID_TEXT N_("Video PID")
- #define VPID_LONGTEXT N_("Assigns 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_("Assigns a fixed PID to the audio stream.")
- #define SPUPID_TEXT N_("SPU PID")
- #define SPUPID_LONGTEXT N_("Assigns a fixed PID to the SPU.")
- #define PMTPID_TEXT N_("PMT PID")
- #define PMTPID_LONGTEXT N_("Assings a fixed PID to the PMT")
- #define TSID_TEXT N_("TS ID")
- #define TSID_LONGTEXT N_("Assigns a fixed Transport Stream ID.")
- #define SHAPING_TEXT N_("Shaping delay (ms)")
- #define SHAPING_LONGTEXT N_("If enabled, the TS muxer will cut the "
- "stream in slices of the given duration, and ensure a constant bitrate "
- "between the two boundaries. This avoids having huge bitrate peaks for "
- "reference frames, in particular.")
- #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_("This option allows you to set at which interval "
- "PCRs (Program Clock Reference) will be sent. "
- "This value should be below 100ms. (default is 30)")
- #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_("This option will 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 CK_TEXT N_("CSA Key")
- #define CK_LONGTEXT N_("Defines the CSA encryption key. This must be a "
- "16 char string (8 hexadecimal bytes).")
- #define SOUT_CFG_PREFIX "sout-ts-"
- vlc_module_begin();
- set_description( _("TS muxer (libdvbpsi)") );
- set_capability( "sout mux", 120 );
- add_shortcut( "ts" );
- add_integer( SOUT_CFG_PREFIX "pid-video", 0, NULL,VPID_TEXT, VPID_LONGTEXT,
- VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "pid-audio", 0, NULL, APID_TEXT,
- APID_LONGTEXT, VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "pid-spu", 0, NULL, SPUPID_TEXT,
- SPUPID_LONGTEXT, VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "pid-pmt", 0, NULL, PMTPID_TEXT,
- PMTPID_LONGTEXT, VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "tsid", 0, NULL, TSID_TEXT,
- TSID_LONGTEXT, VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "shaping", 200, NULL,SHAPING_TEXT,
- SHAPING_LONGTEXT, VLC_TRUE );
- add_bool( SOUT_CFG_PREFIX "use-key-frames", VLC_FALSE, NULL, KEYF_TEXT,
- KEYF_LONGTEXT, VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "pcr", 30, NULL, PCR_TEXT, PCR_LONGTEXT,
- VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "bmin", 0, NULL, BMIN_TEXT, BMIN_LONGTEXT,
- VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "bmax", 0, NULL, BMAX_TEXT, BMAX_LONGTEXT,
- VLC_TRUE );
- add_integer( SOUT_CFG_PREFIX "dts-delay", 200, NULL, DTS_TEXT,
- DTS_LONGTEXT, VLC_TRUE );
- add_bool( SOUT_CFG_PREFIX "crypt-audio", VLC_TRUE, NULL, ACRYPT_TEXT,
- ACRYPT_LONGTEXT, VLC_TRUE );
- add_string( SOUT_CFG_PREFIX "csa-ck", NULL, NULL, CK_TEXT, CK_LONGTEXT,
- VLC_TRUE );
- set_callbacks( Open, Close );
- vlc_module_end();
- /*****************************************************************************
- * Local data structures
- *****************************************************************************/
- static const char *ppsz_sout_options[] = {
- "pid-video", "pid-audio", "pid-spu", "pid-pmt", "tsid", "shaping", "pcr",
- "bmin", "bmax", "use-key-frames", "dts-delay", "csa-ck", "crypt-audio",
- NULL
- };
- #define SOUT_BUFFER_FLAGS_PRIVATE_PCR ( 1 << BLOCK_FLAG_PRIVATE_SHIFT )
- #define SOUT_BUFFER_FLAGS_PRIVATE_CSA ( 2 << BLOCK_FLAG_PRIVATE_SHIFT )
- 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_instance_t *p_sout,
- 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;
- /* 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 */
- uint8_t lang[3];
- sout_buffer_chain_t chain_pes;
- mtime_t i_pes_dts;
- mtime_t i_pes_length;
- int i_pes_used;
- vlc_bool_t b_key_frame;
- } ts_stream_t;
- struct sout_mux_sys_t
- {
- int i_pcr_pid;
- sout_input_t *p_pcr_input;
- int i_audio_bound;
- int i_video_bound;
- int i_pid_video;
- int i_pid_audio;
- int i_pid_spu;
- int i_pid_free; // first usable pid
- int i_tsid;
- int i_pat_version_number;
- ts_stream_t pat;
- int i_pmt_version_number;
- ts_stream_t pmt; // Up to now only one program
- int i_mpeg4_streams;
- int i_null_continuity_counter; /* Needed ? */
- /* 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;
- vlc_bool_t b_use_key_frames;
- mtime_t i_pcr; /* last PCR emited */
- csa_t *csa;
- vlc_bool_t b_crypt_audio;
- };
- /* 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;
- }
- /*****************************************************************************
- * 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 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, vlc_bool_t 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;
- vlc_value_t val;
- msg_Dbg( p_mux, "Open" );
- sout_CfgParse( p_mux, SOUT_CFG_PREFIX, ppsz_sout_options, p_mux->p_cfg );
- p_sys = malloc( sizeof( sout_mux_sys_t ) );
- 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() );
- p_sys->i_audio_bound = 0;
- p_sys->i_video_bound = 0;
- p_sys->i_pat_version_number = rand() % 32;
- p_sys->pat.i_pid = 0;
- p_sys->pat.i_continuity_counter = 0;
- 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_pmt_version_number = rand() % 32;
- p_sys->pmt.i_continuity_counter = 0;
- var_Get( p_mux, SOUT_CFG_PREFIX "pid-pmt", &val );
- if (val.i_int )
- {
- p_sys->pmt.i_pid = val.i_int;
- }
- else
- {
- p_sys->pmt.i_pid = 0x42;
- }
- p_sys->i_pid_free = p_sys->pmt.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 ("I64Fd"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 ("I64Fd"ms) resetting to 30ms",
- p_sys->i_pcr_delay / 1000 );
- p_sys->i_pcr_delay = 30000;
- }
- 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="I64Fd" pcr="I64Fd" dts_delay="I64Fd,
- 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_Get( p_mux, SOUT_CFG_PREFIX "csa-ck", &val );
- if( val.psz_string )
- {
- char *psz = val.psz_string;
- /* skip 0x */
- if( psz[0] == '0' && ( psz[1] == 'x' || psz[1] == 'X' ) )
- {
- psz += 2;
- }
- if( strlen( psz ) != 16 )
- {
- msg_Dbg( p_mux, "invalid csa ck (it must be 16 chars long)" );
- }
- else
- {
- uint64_t i_ck = strtoull( psz, NULL, 16 );
- uint8_t ck[8];
- int i;
- for( i = 0; i < 8; i++ )
- {
- ck[i] = ( i_ck >> ( 56 - 8*i) )&0xff;
- }
- msg_Dbg( p_mux, "using CSA scrambling with ck=%x:%x:%x:%x:%x:%x:%x:%x",
- ck[0], ck[1], ck[2], ck[3], ck[4], ck[5], ck[6], ck[7] );
- p_sys->csa = csa_New();
- csa_SetCW( p_sys->csa, ck, ck );
- }
- }
- if( val.psz_string ) free( val.psz_string );
- var_Get( p_mux, SOUT_CFG_PREFIX "crypt-audio", &val );
- p_sys->b_crypt_audio = 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;
- msg_Dbg( p_mux, "Close" );
- if( p_sys->csa )
- {
- csa_Delete( p_sys->csa );
- }
- free( p_sys );
- }
- /*****************************************************************************
- * Control:
- *****************************************************************************/
- static int Control( sout_mux_t *p_mux, int i_query, va_list args )
- {
- vlc_bool_t *pb_bool;
- char **ppsz;
- switch( i_query )
- {
- case MUX_CAN_ADD_STREAM_WHILE_MUXING:
- pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
- *pb_bool = VLC_TRUE;
- return VLC_SUCCESS;
- case MUX_GET_ADD_STREAM_WAIT:
- pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
- *pb_bool = VLC_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;
- p_input->p_sys = p_stream = malloc( sizeof( ts_stream_t ) );
- /* Init this new stream */
- 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->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 = 0xfa;
- p_sys->i_mpeg4_streams++;
- 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;
- 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' ):
- 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' ):
- p_stream->i_stream_type = 0x11;
- p_stream->i_stream_id = 0xfa;
- 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->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] );
- }
- }
- /* 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 );
- memcpy( p_stream->p_decoder_specific_info,
- p_input->p_fmt->p_extra,
- p_input->p_fmt->i_extra );
- }
- /* 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 );
- 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 */
- }
- /* 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_mux->p_sout, &p_stream->chain_pes );
- 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 ||
- 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 )
- {
- 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( ;; )
- {
- vlc_bool_t b_ok = VLC_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 = 0; i < p_mux->i_nb_inputs; i++ )
- {
- sout_input_t *p_input = p_mux->pp_inputs[i];
- ts_stream_t *p_stream = (ts_stream_t*)p_input->p_sys;
- int64_t i_spu_delay = 0;
- 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( p_input->p_fifo->i_depth <= 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( p_input->p_fifo->i_depth <= 0 )
- {
- /* spu, only one packet is needed */
- continue;
- }
- else
- {
- /* 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 < I64C(100000000) )
- continue;
- if ( i_spu_delay >= I64C(100000000)
- || i_spu_delay < 10000 )
- {
- BufferChainClean( p_mux->p_sout,
- &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 = VLC_FALSE;
- p_data = block_FifoGet( p_input->p_fifo );
- if( p_input->p_fifo->i_depth > 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
- 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="I64Fd",old="I64Fd",pcr="I64Fd")",
- p_data->i_dts, p_stream->i_pes_dts,
- p_pcr_stream->i_pes_dts );
- block_Release( p_data );
- BufferChainClean( p_mux->p_sout,
- &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_mux->p_sout,
- &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 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