ts.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:93k
- /*****************************************************************************
- * ts.c: Transport Stream input module for VLC.
- *****************************************************************************
- * Copyright (C) 2004 VideoLAN
- * $Id: ts.c 9138 2004-11-04 20:58:51Z hartman $
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- *
- * 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> /* malloc(), free() */
- #include <vlc/vlc.h>
- #include <vlc/input.h>
- #include "iso_lang.h"
- #include "network.h"
- #include "../mux/mpeg/csa.h"
- /* Include dvbpsi headers */
- #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:
- * - XXX: do not mark options message to be translated, they are too osbcure for now ...
- * - test it
- * - ...
- */
- /*****************************************************************************
- * Module descriptor
- *****************************************************************************/
- static int Open ( vlc_object_t * );
- static void Close ( vlc_object_t * );
- #define PMT_TEXT N_("Extra PMT")
- #define PMT_LONGTEXT N_(
- "Allows a user to specify an extra pmt (pmt_pid=pid:stream_type[,...])" )
- #define PID_TEXT N_("Set id of ES to PID")
- #define PID_LONGTEXT N_("set id of es to pid")
- #define TSOUT_TEXT N_("Fast udp streaming")
- #define TSOUT_LONGTEXT N_(
- "Sends TS to specific ip:port by udp (you must know what you are doing)")
- #define MTUOUT_TEXT N_("MTU for out mode")
- #define MTUOUT_LONGTEXT N_("MTU for out mode")
- #define CSA_TEXT N_("CSA ck")
- #define CSA_LONGTEXT N_("CSA ck")
- #define SILENT_TEXT N_("Silent mode")
- #define SILENT_LONGTEXT N_("do not complain on encrypted PES")
- vlc_module_begin();
- set_description( _("ISO 13818-1 MPEG Transport Stream input - new" ) );
- add_string( "ts-extra-pmt", NULL, NULL, PMT_TEXT, PMT_LONGTEXT, VLC_TRUE );
- add_bool( "ts-es-id-pid", 0, NULL, PID_TEXT, PID_LONGTEXT, VLC_TRUE );
- add_string( "ts-out", NULL, NULL, TSOUT_TEXT, TSOUT_LONGTEXT, VLC_TRUE );
- add_integer( "ts-out-mtu", 1500, NULL, MTUOUT_TEXT,
- MTUOUT_LONGTEXT, VLC_TRUE );
- add_string( "ts-csa-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, VLC_TRUE );
- add_bool( "ts-silent", 0, NULL, SILENT_TEXT, SILENT_LONGTEXT, VLC_TRUE );
- set_capability( "demux2", 10 );
- set_callbacks( Open, Close );
- add_shortcut( "ts" );
- vlc_module_end();
- /*****************************************************************************
- * Local prototypes
- *****************************************************************************/
- typedef struct
- {
- uint8_t i_objectTypeIndication;
- uint8_t i_streamType;
- vlc_bool_t b_upStream;
- uint32_t i_bufferSizeDB;
- uint32_t i_maxBitrate;
- uint32_t i_avgBitrate;
- int i_decoder_specific_info_len;
- uint8_t *p_decoder_specific_info;
- } decoder_config_descriptor_t;
- typedef struct
- {
- vlc_bool_t b_useAccessUnitStartFlag;
- vlc_bool_t b_useAccessUnitEndFlag;
- vlc_bool_t b_useRandomAccessPointFlag;
- vlc_bool_t b_useRandomAccessUnitsOnlyFlag;
- vlc_bool_t b_usePaddingFlag;
- vlc_bool_t b_useTimeStampsFlags;
- vlc_bool_t b_useIdleFlag;
- vlc_bool_t b_durationFlag;
- uint32_t i_timeStampResolution;
- uint32_t i_OCRResolution;
- uint8_t i_timeStampLength;
- uint8_t i_OCRLength;
- uint8_t i_AU_Length;
- uint8_t i_instantBitrateLength;
- uint8_t i_degradationPriorityLength;
- uint8_t i_AU_seqNumLength;
- uint8_t i_packetSeqNumLength;
- uint32_t i_timeScale;
- uint16_t i_accessUnitDuration;
- uint16_t i_compositionUnitDuration;
- uint64_t i_startDecodingTimeStamp;
- uint64_t i_startCompositionTimeStamp;
- } sl_config_descriptor_t;
- typedef struct
- {
- vlc_bool_t b_ok;
- uint16_t i_es_id;
- vlc_bool_t b_streamDependenceFlag;
- vlc_bool_t b_OCRStreamFlag;
- uint8_t i_streamPriority;
- char *psz_url;
- uint16_t i_dependOn_es_id;
- uint16_t i_OCR_es_id;
- decoder_config_descriptor_t dec_descr;
- sl_config_descriptor_t sl_descr;
- } es_mpeg4_descriptor_t;
- typedef struct
- {
- uint8_t i_iod_label;
- /* IOD */
- uint16_t i_od_id;
- char *psz_url;
- uint8_t i_ODProfileLevelIndication;
- uint8_t i_sceneProfileLevelIndication;
- uint8_t i_audioProfileLevelIndication;
- uint8_t i_visualProfileLevelIndication;
- uint8_t i_graphicsProfileLevelIndication;
- es_mpeg4_descriptor_t es_descr[255];
- } iod_descriptor_t;
- typedef struct
- {
- dvbpsi_handle handle;
- int i_version;
- int i_number;
- int i_pid_pcr;
- int i_pid_pmt;
- /* IOD stuff (mpeg4) */
- iod_descriptor_t *iod;
- /* Conditional Access PMT (EN 50 221) */
- uint8_t *p_capmt;
- int i_capmt_size;
- } ts_prg_psi_t;
- typedef struct
- {
- /* for special PAT case */
- dvbpsi_handle handle;
- int i_pat_version;
- /* For PMT */
- int i_prg;
- ts_prg_psi_t **prg;
- } ts_psi_t;
- typedef struct
- {
- es_format_t fmt;
- es_out_id_t *id;
- int i_pes_size;
- int i_pes_gathered;
- block_t *p_pes;
- block_t **pp_last;
- es_mpeg4_descriptor_t *p_mpeg4desc;
- int b_gather;
- } ts_es_t;
- typedef struct
- {
- int i_pid;
- vlc_bool_t b_seen;
- vlc_bool_t b_valid;
- int i_cc; /* countinuity counter */
- /* PSI owner (ie PMT -> PAT, ES -> PMT */
- ts_psi_t *p_owner;
- int i_owner_number;
- /* */
- ts_psi_t *psi;
- ts_es_t *es;
- /* Some private streams encapsulate several ES (eg. DVB subtitles)*/
- ts_es_t **extra_es;
- int i_extra_es;
- } ts_pid_t;
- struct demux_sys_t
- {
- /* TS packet size (188, 192, 204) */
- int i_packet_size;
- /* how many TS packet we read at once */
- int i_ts_read;
- /* All pid */
- ts_pid_t pid[8192];
- /* All PMT */
- int i_pmt;
- ts_pid_t **pmt;
- /* */
- vlc_bool_t b_es_id_pid;
- csa_t *csa;
- vlc_bool_t b_silent;
- vlc_bool_t b_udp_out;
- int fd; /* udp socket */
- uint8_t *buffer;
- vlc_bool_t b_dvb_control;
- int i_dvb_program;
- vlc_list_t *p_programs_list;
- };
- static int Demux ( demux_t *p_demux );
- static int Control( demux_t *p_demux, int i_query, va_list args );
- static void PIDInit ( ts_pid_t *pid, vlc_bool_t b_psi, ts_psi_t *p_owner );
- static void PIDClean( es_out_t *out, ts_pid_t *pid );
- static int PIDFillFormat( ts_pid_t *pid, int i_stream_type );
- static void PATCallBack( demux_t *, dvbpsi_pat_t * );
- static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt );
- static inline int PIDGet( block_t *p )
- {
- return ( (p->p_buffer[1]&0x1f)<<8 )|p->p_buffer[2];
- }
- static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
- static void PCRHandle( demux_t *p_demux, ts_pid_t *, block_t * );
- static iod_descriptor_t *IODNew( int , uint8_t * );
- static void IODFree( iod_descriptor_t * );
- static void DVBCAPMTSend( demux_t *p_demux );
- #define TS_PACKET_SIZE_188 188
- #define TS_PACKET_SIZE_192 192
- #define TS_PACKET_SIZE_204 204
- #define TS_PACKET_SIZE_MAX 204
- /*****************************************************************************
- * Open
- *****************************************************************************/
- static int Open( vlc_object_t *p_this )
- {
- demux_t *p_demux = (demux_t*)p_this;
- demux_sys_t *p_sys;
- uint8_t *p_peek;
- int i_sync, i_peek, i;
- int i_packet_size;
- ts_pid_t *pat;
- vlc_value_t val;
- if( stream_Peek( p_demux->s, &p_peek, TS_PACKET_SIZE_MAX ) <
- TS_PACKET_SIZE_MAX )
- {
- msg_Err( p_demux, "cannot peek" );
- return VLC_EGENERIC;
- }
- /* Search first sync byte */
- for( i_sync = 0; i_sync < TS_PACKET_SIZE_MAX; i_sync++ )
- {
- if( p_peek[i_sync] == 0x47 ) break;
- }
- if( i_sync >= TS_PACKET_SIZE_MAX )
- {
- if( strcmp( p_demux->psz_demux, "ts" ) )
- {
- msg_Warn( p_demux, "TS module discarded" );
- return VLC_EGENERIC;
- }
- msg_Warn( p_demux, "this does not look like a TS stream, continuing" );
- }
- /* Check next 3 sync bytes */
- i_peek = TS_PACKET_SIZE_MAX * 3 + i_sync + 1;
- if( ( stream_Peek( p_demux->s, &p_peek, i_peek ) ) < i_peek )
- {
- msg_Err( p_demux, "cannot peek" );
- return VLC_EGENERIC;
- }
- if( p_peek[i_sync + TS_PACKET_SIZE_188] == 0x47 &&
- p_peek[i_sync + 2 * TS_PACKET_SIZE_188] == 0x47 &&
- p_peek[i_sync + 3 * TS_PACKET_SIZE_188] == 0x47 )
- {
- i_packet_size = TS_PACKET_SIZE_188;
- }
- else if( p_peek[i_sync + TS_PACKET_SIZE_192] == 0x47 &&
- p_peek[i_sync + 2 * TS_PACKET_SIZE_192] == 0x47 &&
- p_peek[i_sync + 3 * TS_PACKET_SIZE_192] == 0x47 )
- {
- i_packet_size = TS_PACKET_SIZE_192;
- }
- else if( p_peek[i_sync + TS_PACKET_SIZE_204] == 0x47 &&
- p_peek[i_sync + 2 * TS_PACKET_SIZE_204] == 0x47 &&
- p_peek[i_sync + 3 * TS_PACKET_SIZE_204] == 0x47 )
- {
- i_packet_size = TS_PACKET_SIZE_204;
- }
- else if( !strcmp( p_demux->psz_demux, "ts" ) )
- {
- i_packet_size = TS_PACKET_SIZE_188;
- }
- else
- {
- msg_Warn( p_demux, "TS module discarded (lost sync)" );
- return VLC_EGENERIC;
- }
- /* Fill p_demux field */
- p_demux->pf_demux = Demux;
- p_demux->pf_control = Control;
- p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
- memset( p_sys, 0, sizeof( demux_sys_t ) );
- /* Init p_sys field */
- p_sys->b_dvb_control = VLC_TRUE;
- p_sys->i_dvb_program = 0;
- for( i = 0; i < 8192; i++ )
- {
- ts_pid_t *pid = &p_sys->pid[i];
- pid->i_pid = i;
- pid->b_seen = VLC_FALSE;
- pid->b_valid = VLC_FALSE;
- }
- p_sys->i_packet_size = i_packet_size;
- p_sys->b_udp_out = VLC_FALSE;
- p_sys->i_ts_read = 50;
- p_sys->csa = NULL;
- /* Init PAT handler */
- pat = &p_sys->pid[0];
- PIDInit( pat, VLC_TRUE, NULL );
- pat->psi->handle = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack,
- p_demux );
- /* Init PMT array */
- p_sys->i_pmt = 0;
- p_sys->pmt = NULL;
- /* Read config */
- var_Create( p_demux, "ts-es-id-pid", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- var_Get( p_demux, "ts-es-id-pid", &val );
- p_sys->b_es_id_pid = val.b_bool,
- var_Create( p_demux, "ts-out", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Get( p_demux, "ts-out", &val );
- if( val.psz_string && *val.psz_string )
- {
- vlc_value_t mtu;
- char *psz = strchr( val.psz_string, ':' );
- int i_port = 0;
- p_sys->b_udp_out = VLC_TRUE;
- if( psz )
- {
- *psz++ = ' ';
- i_port = atoi( psz );
- }
- if( i_port <= 0 ) i_port = 1234;
- msg_Dbg( p_demux, "resend ts to '%s:%d'", val.psz_string, i_port );
- p_sys->fd = net_OpenUDP( p_demux, "", 0, val.psz_string, i_port );
- if( p_sys->fd < 0 )
- {
- msg_Err( p_demux, "failed to open udp socket, send disabled" );
- p_sys->b_udp_out = VLC_FALSE;
- }
- else
- {
- var_Create( p_demux, "ts-out-mtu",
- VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
- var_Get( p_demux, "ts-out-mtu", &mtu );
- p_sys->i_ts_read = mtu.i_int / p_sys->i_packet_size;
- if( p_sys->i_ts_read <= 0 )
- {
- p_sys->i_ts_read = 1500 / p_sys->i_packet_size;
- }
- p_sys->buffer = malloc( p_sys->i_packet_size * p_sys->i_ts_read );
- }
- }
- if( val.psz_string )
- {
- free( val.psz_string );
- }
- /* We handle description of an extra PMT */
- var_Create( p_demux, "ts-extra-pmt", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Get( p_demux, "ts-extra-pmt", &val );
- if( val.psz_string && strchr( val.psz_string, '=' ) != NULL )
- {
- char *psz = val.psz_string;
- int i_pid = strtol( psz, &psz, 0 );
- if( i_pid >= 2 && i_pid < 8192 )
- {
- ts_pid_t *pmt = &p_sys->pid[i_pid];
- msg_Dbg( p_demux, "extra pmt specified (pid=%d)", i_pid );
- PIDInit( pmt, VLC_TRUE, NULL );
- /* FIXME we should also ask for a number */
- pmt->psi->prg[0]->handle =
- dvbpsi_AttachPMT( 1, (dvbpsi_pmt_callback)PMTCallBack,
- p_demux );
- pmt->psi->prg[0]->i_number = 0; /* special one */
- psz = strchr( psz, '=' ) + 1; /* can't failed */
- while( psz && *psz )
- {
- char *psz_next = strchr( psz, ',' );
- int i_pid, i_stream_type;
- if( psz_next )
- {
- *psz_next++ = ' ';
- }
- i_pid = strtol( psz, &psz, 0 );
- if( *psz == ':' )
- {
- i_stream_type = strtol( psz + 1, &psz, 0 );
- if( i_pid >= 2 && i_pid < 8192 &&
- !p_sys->pid[i_pid].b_valid )
- {
- ts_pid_t *pid = &p_sys->pid[i_pid];
- PIDInit( pid, VLC_FALSE, pmt->psi);
- if( pmt->psi->prg[0]->i_pid_pcr <= 0 )
- {
- pmt->psi->prg[0]->i_pid_pcr = i_pid;
- }
- PIDFillFormat( pid, i_stream_type);
- if( pid->es->fmt.i_cat != UNKNOWN_ES )
- {
- if( p_sys->b_es_id_pid )
- {
- pid->es->fmt.i_id = i_pid;
- }
- msg_Dbg( p_demux, " * es pid=%d type=%d "
- "fcc=%4.4s", i_pid, i_stream_type,
- (char*)&pid->es->fmt.i_codec );
- pid->es->id = es_out_Add( p_demux->out,
- &pid->es->fmt );
- }
- }
- }
- psz = psz_next;
- }
- }
- }
- if( val.psz_string )
- {
- free( val.psz_string );
- }
- var_Create( p_demux, "ts-csa-ck", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Get( p_demux, "ts-csa-ck", &val );
- if( val.psz_string && *val.psz_string )
- {
- char *psz = val.psz_string;
- if( psz[0] == '0' && ( psz[1] == 'x' || psz[1] == 'X' ) )
- {
- psz += 2;
- }
- if( strlen( psz ) != 16 )
- {
- msg_Warn( p_demux, "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_demux, "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_Create( p_demux, "ts-silent", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- var_Get( p_demux, "ts-silent", &val );
- p_sys->b_silent = val.b_bool;
- return VLC_SUCCESS;
- }
- /*****************************************************************************
- * Close
- *****************************************************************************/
- static void Close( vlc_object_t *p_this )
- {
- demux_t *p_demux = (demux_t*)p_this;
- demux_sys_t *p_sys = p_demux->p_sys;
- int i;
- msg_Dbg( p_demux, "pid list:" );
- for( i = 0; i < 8192; i++ )
- {
- ts_pid_t *pid = &p_sys->pid[i];
- if( pid->b_valid && pid->psi )
- {
- switch( pid->i_pid )
- {
- case 0: /* PAT */
- dvbpsi_DetachPAT( pid->psi->handle );
- free( pid->psi );
- break;
- case 1: /* CAT */
- free( pid->psi );
- break;
- default:
- PIDClean( p_demux->out, pid );
- break;
- }
- }
- else if( pid->b_valid && pid->es )
- {
- PIDClean( p_demux->out, pid );
- }
- if( pid->b_seen )
- {
- msg_Dbg( p_demux, " - pid[%d] seen", pid->i_pid );
- }
- if( p_sys->b_dvb_control && pid->i_pid > 0 )
- {
- /* too much */
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_SET_PRIVATE_ID_STATE, pid->i_pid, VLC_FALSE );
- }
- }
- if( p_sys->b_udp_out )
- {
- net_Close( p_sys->fd );
- free( p_sys->buffer );
- }
- if( p_sys->csa )
- {
- csa_Delete( p_sys->csa );
- }
- if( p_sys->i_pmt ) free( p_sys->pmt );
- if ( p_sys->p_programs_list )
- {
- vlc_value_t val;
- val.p_list = p_sys->p_programs_list;
- var_Change( p_demux, "programs", VLC_VAR_FREELIST, &val, NULL );
- }
- free( p_sys );
- }
- /*****************************************************************************
- * Demux:
- *****************************************************************************/
- static int Demux( demux_t *p_demux )
- {
- demux_sys_t *p_sys = p_demux->p_sys;
- int i_pkt;
- /* We read at most 100 TS packet or until a frame is completed */
- for( i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
- {
- vlc_bool_t b_frame = VLC_FALSE;
- block_t *p_pkt;
- ts_pid_t *p_pid;
- /* Get a new TS packet */
- if( !( p_pkt = stream_Block( p_demux->s, p_sys->i_packet_size ) ) )
- {
- msg_Dbg( p_demux, "eof ?" );
- return 0;
- }
- /* Check sync byte and re-sync if needed */
- if( p_pkt->p_buffer[0] != 0x47 )
- {
- msg_Warn( p_demux, "lost synchro" );
- block_Release( p_pkt );
- while( !p_demux->b_die )
- {
- uint8_t *p_peek;
- int i_peek, i_skip = 0;
- i_peek = stream_Peek( p_demux->s, &p_peek,
- p_sys->i_packet_size * 10 );
- if( i_peek < p_sys->i_packet_size + 1 )
- {
- msg_Dbg( p_demux, "eof ?" );
- return 0;
- }
- while( i_skip < i_peek - p_sys->i_packet_size )
- {
- if( p_peek[i_skip] == 0x47 &&
- p_peek[i_skip + p_sys->i_packet_size] == 0x47 )
- {
- break;
- }
- i_skip++;
- }
- msg_Dbg( p_demux, "skipping %d bytes of garbage", i_skip );
- stream_Read( p_demux->s, NULL, i_skip );
- if( i_skip < i_peek - p_sys->i_packet_size )
- {
- break;
- }
- }
- if( !( p_pkt = stream_Block( p_demux->s, p_sys->i_packet_size ) ) )
- {
- msg_Dbg( p_demux, "eof ?" );
- return 0;
- }
- }
- if( p_sys->b_udp_out )
- {
- memcpy( &p_sys->buffer[i_pkt * p_sys->i_packet_size],
- p_pkt->p_buffer, p_sys->i_packet_size );
- }
- /* Parse the TS packet */
- p_pid = &p_sys->pid[PIDGet( p_pkt )];
- if( p_pid->b_valid )
- {
- if( p_pid->psi )
- {
- if( p_pid->i_pid == 0 )
- {
- dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer );
- }
- else
- {
- int i_prg;
- for( i_prg = 0; i_prg < p_pid->psi->i_prg; i_prg++ )
- {
- dvbpsi_PushPacket( p_pid->psi->prg[i_prg]->handle,
- p_pkt->p_buffer );
- }
- }
- block_Release( p_pkt );
- }
- else if( !p_sys->b_udp_out )
- {
- b_frame = GatherPES( p_demux, p_pid, p_pkt );
- }
- else
- {
- PCRHandle( p_demux, p_pid, p_pkt );
- block_Release( p_pkt );
- }
- }
- else
- {
- if( !p_pid->b_seen )
- {
- msg_Dbg( p_demux, "pid[%d] unknown", p_pid->i_pid );
- }
- /* We have to handle PCR if present */
- PCRHandle( p_demux, p_pid, p_pkt );
- block_Release( p_pkt );
- }
- p_pid->b_seen = VLC_TRUE;
- if( b_frame )
- {
- break;
- }
- }
- if( p_sys->b_udp_out )
- {
- /* Send the complete block */
- net_Write( p_demux, p_sys->fd, p_sys->buffer,
- p_sys->i_ts_read * p_sys->i_packet_size );
- }
- return 1;
- }
- /*****************************************************************************
- * Control:
- *****************************************************************************/
- static int Control( demux_t *p_demux, int i_query, va_list args )
- {
- demux_sys_t *p_sys = p_demux->p_sys;
- double f, *pf;
- int64_t i64;
- int i_int;
- switch( i_query )
- {
- case DEMUX_GET_POSITION:
- pf = (double*) va_arg( args, double* );
- i64 = stream_Size( p_demux->s );
- if( i64 > 0 )
- {
- *pf = (double)stream_Tell( p_demux->s ) / (double)i64;
- }
- else
- {
- *pf = 0.0;
- }
- return VLC_SUCCESS;
- case DEMUX_SET_POSITION:
- f = (double) va_arg( args, double );
- i64 = stream_Size( p_demux->s );
- es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
- if( stream_Seek( p_demux->s, (int64_t)(i64 * f) ) )
- {
- return VLC_EGENERIC;
- }
- return VLC_SUCCESS;
- #if 0
- case DEMUX_GET_TIME:
- pi64 = (int64_t*)va_arg( args, int64_t * );
- if( p_sys->i_time < 0 )
- {
- *pi64 = 0;
- return VLC_EGENERIC;
- }
- *pi64 = p_sys->i_time;
- return VLC_SUCCESS;
- case DEMUX_GET_LENGTH:
- pi64 = (int64_t*)va_arg( args, int64_t * );
- if( p_sys->i_mux_rate > 0 )
- {
- *pi64 = I64C(1000000) * ( stream_Size( p_demux->s ) / 50 ) /
- p_sys->i_mux_rate;
- return VLC_SUCCESS;
- }
- *pi64 = 0;
- return VLC_EGENERIC;
- #endif
- case DEMUX_SET_GROUP:
- {
- uint16_t i_vpid = 0, i_apid1 = 0, i_apid2 = 0, i_apid3 = 0;
- ts_prg_psi_t *p_prg = NULL;
- vlc_list_t *p_list;
- i_int = (int)va_arg( args, int );
- p_list = (vlc_list_t *)va_arg( args, vlc_list_t * );
- msg_Dbg( p_demux, "DEMUX_SET_GROUP %d %p", i_int, p_list );
- if( p_sys->b_dvb_control && i_int > 0 && i_int != p_sys->i_dvb_program )
- {
- int i_pmt_pid = -1;
- int i;
- /* Search pmt to be unselected */
- for( i = 0; i < p_sys->i_pmt; i++ )
- {
- ts_pid_t *pmt = p_sys->pmt[i];
- int i_prg;
- for( i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
- {
- if( pmt->psi->prg[i_prg]->i_number == p_sys->i_dvb_program )
- {
- i_pmt_pid = p_sys->pmt[i]->i_pid;
- break;
- }
- }
- if( i_pmt_pid > 0 ) break;
- }
- if( i_pmt_pid > 0 )
- {
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, i_pmt_pid,
- VLC_FALSE );
- /* All ES */
- for( i = 2; i < 8192; i++ )
- {
- ts_pid_t *pid = &p_sys->pid[i];
- int i_prg;
- if( !pid->b_valid || pid->psi ) continue;
- for( i_prg = 0; i_prg < pid->p_owner->i_prg; i_prg++ )
- {
- if( pid->p_owner->prg[i_prg]->i_pid_pmt == i_pmt_pid && pid->es->id )
- {
- /* We only remove es that aren't defined by extra pmt */
- stream_Control( p_demux->s,
- STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE,
- i, VLC_FALSE );
- break;
- }
- }
- }
- }
- /* select new program */
- p_sys->i_dvb_program = i_int;
- i_pmt_pid = -1;
- for( i = 0; i < p_sys->i_pmt; i++ )
- {
- ts_pid_t *pmt = p_sys->pmt[i];
- int i_prg;
- for( i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
- {
- if( pmt->psi->prg[i_prg]->i_number == i_int )
- {
- i_pmt_pid = p_sys->pmt[i]->i_pid;
- p_prg = p_sys->pmt[i]->psi->prg[i_prg];
- break;
- }
- }
- if( i_pmt_pid > 0 ) break;
- }
- if( i_pmt_pid > 0 )
- {
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, i_pmt_pid,
- VLC_TRUE );
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, p_prg->i_pid_pcr,
- VLC_TRUE );
- for( i = 2; i < 8192; i++ )
- {
- ts_pid_t *pid = &p_sys->pid[i];
- int i_prg;
- if( !pid->b_valid || pid->psi ) continue;
- for( i_prg = 0; i_prg < pid->p_owner->i_prg; i_prg++ )
- {
- if( pid->p_owner->prg[i_prg]->i_pid_pmt == i_pmt_pid && pid->es->id )
- {
- if ( pid->es->fmt.i_cat == VIDEO_ES && !i_vpid )
- i_vpid = i;
- if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid1 )
- i_apid1 = i;
- else if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid2 )
- i_apid2 = i;
- else if ( pid->es->fmt.i_cat == AUDIO_ES && !i_apid3 )
- i_apid3 = i;
- stream_Control( p_demux->s,
- STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE,
- i, VLC_TRUE );
- break;
- }
- }
- }
- /* Set CAM descrambling */
- DVBCAPMTSend( p_demux );
- }
- }
- else
- {
- p_sys->i_dvb_program = -1;
- p_sys->p_programs_list = p_list;
- }
- return VLC_SUCCESS;
- }
- case DEMUX_GET_FPS:
- case DEMUX_SET_TIME:
- default:
- return VLC_EGENERIC;
- }
- }
- static void PIDInit( ts_pid_t *pid, vlc_bool_t b_psi, ts_psi_t *p_owner )
- {
- vlc_bool_t b_old_valid = pid->b_valid;
- pid->b_valid = VLC_TRUE;
- pid->i_cc = 0xff;
- pid->p_owner = p_owner;
- pid->i_owner_number = 0;
- pid->extra_es = NULL;
- pid->i_extra_es = 0;
- if( b_psi )
- {
- pid->es = NULL;
- if( !b_old_valid )
- {
- pid->psi = malloc( sizeof( ts_psi_t ) );
- pid->psi->i_prg = 0;
- pid->psi->prg = NULL;
- pid->psi->handle= NULL;
- }
- pid->psi->i_pat_version = -1;
- if( p_owner )
- {
- ts_prg_psi_t *prg = malloc( sizeof( ts_prg_psi_t ) );
- /* PMT */
- prg->i_version = -1;
- prg->i_number = -1;
- prg->i_pid_pcr = -1;
- prg->i_pid_pmt = -1;
- prg->iod = NULL;
- prg->p_capmt = NULL;
- prg->i_capmt_size = 0;
- prg->handle = NULL;
- TAB_APPEND( pid->psi->i_prg, pid->psi->prg, prg );
- }
- }
- else
- {
- pid->psi = NULL;
- pid->es = malloc( sizeof( ts_es_t ) );
- es_format_Init( &pid->es->fmt, UNKNOWN_ES, 0 );
- pid->es->id = NULL;
- pid->es->p_pes = NULL;
- pid->es->i_pes_size= 0;
- pid->es->i_pes_gathered= 0;
- pid->es->pp_last = &pid->es->p_pes;
- pid->es->p_mpeg4desc = NULL;
- pid->es->b_gather = VLC_FALSE;
- }
- }
- static void PIDClean( es_out_t *out, ts_pid_t *pid )
- {
- if( pid->psi )
- {
- int i;
- if( pid->psi->handle ) dvbpsi_DetachPMT( pid->psi->handle );
- for( i = 0; i < pid->psi->i_prg; i++ )
- {
- if( pid->psi->prg[i]->iod )
- IODFree( pid->psi->prg[i]->iod );
- if ( pid->psi->prg[i]->i_capmt_size )
- free( pid->psi->prg[i]->p_capmt );
- if( pid->psi->prg[i]->handle )
- dvbpsi_DetachPMT( pid->psi->prg[i]->handle );
- free( pid->psi->prg[i] );
- }
- if( pid->psi->prg ) free( pid->psi->prg );
- free( pid->psi );
- }
- else
- {
- int i;
- if( pid->es->id )
- es_out_Del( out, pid->es->id );
- if( pid->es->p_pes )
- block_ChainRelease( pid->es->p_pes );
- es_format_Clean( &pid->es->fmt );
- free( pid->es );
- for( i = 0; i < pid->i_extra_es; i++ )
- {
- if( pid->extra_es[i]->id )
- es_out_Del( out, pid->extra_es[i]->id );
- if( pid->extra_es[i]->p_pes )
- block_ChainRelease( pid->extra_es[i]->p_pes );
- es_format_Clean( &pid->extra_es[i]->fmt );
- free( pid->extra_es[i] );
- }
- if( pid->i_extra_es ) free( pid->extra_es );
- }
- pid->b_valid = VLC_FALSE;
- }
- /****************************************************************************
- * gathering stuff
- ****************************************************************************/
- static void ParsePES( demux_t *p_demux, ts_pid_t *pid )
- {
- block_t *p_pes = pid->es->p_pes;
- uint8_t header[30];
- int i_pes_size = 0;
- int i_skip = 0;
- mtime_t i_dts = -1;
- mtime_t i_pts = -1;
- mtime_t i_length = 0;
- int i_max;
- /* remove the pes from pid */
- pid->es->p_pes = NULL;
- pid->es->i_pes_size= 0;
- pid->es->i_pes_gathered= 0;
- pid->es->pp_last = &pid->es->p_pes;
- /* FIXME find real max size */
- i_max = block_ChainExtract( p_pes, header, 30 );
- if( header[0] != 0 || header[1] != 0 || header[2] != 1 )
- {
- if( !p_demux->p_sys->b_silent )
- msg_Warn( p_demux, "invalid header [0x%x:%x:%x:%x] (pid: %d)",
- header[0], header[1],header[2],header[3], pid->i_pid );
- block_ChainRelease( p_pes );
- return;
- }
- /* TODO check size */
- switch( header[3] )
- {
- case 0xBC: /* Program stream map */
- case 0xBE: /* Padding */
- case 0xBF: /* Private stream 2 */
- case 0xB0: /* ECM */
- case 0xB1: /* EMM */
- case 0xFF: /* Program stream directory */
- case 0xF2: /* DSMCC stream */
- case 0xF8: /* ITU-T H.222.1 type E stream */
- i_skip = 6;
- break;
- default:
- if( ( header[6]&0xC0 ) == 0x80 )
- {
- /* mpeg2 PES */
- i_skip = header[8] + 9;
- if( header[7]&0x80 ) /* has pts */
- {
- i_pts = ((mtime_t)(header[ 9]&0x0e ) << 29)|
- (mtime_t)(header[10] << 22)|
- ((mtime_t)(header[11]&0xfe) << 14)|
- (mtime_t)(header[12] << 7)|
- (mtime_t)(header[13] >> 1);
- if( header[7]&0x40 ) /* has dts */
- {
- i_dts = ((mtime_t)(header[14]&0x0e ) << 29)|
- (mtime_t)(header[15] << 22)|
- ((mtime_t)(header[16]&0xfe) << 14)|
- (mtime_t)(header[17] << 7)|
- (mtime_t)(header[18] >> 1);
- }
- }
- }
- else
- {
- i_skip = 6;
- while( i_skip < 23 && header[i_skip] == 0xff )
- {
- i_skip++;
- }
- if( i_skip == 23 )
- {
- msg_Err( p_demux, "too much MPEG-1 stuffing" );
- block_ChainRelease( p_pes );
- return;
- }
- if( ( header[i_skip] & 0xC0 ) == 0x40 )
- {
- i_skip += 2;
- }
- if( header[i_skip]&0x20 )
- {
- i_pts = ((mtime_t)(header[i_skip]&0x0e ) << 29)|
- (mtime_t)(header[i_skip+1] << 22)|
- ((mtime_t)(header[i_skip+2]&0xfe) << 14)|
- (mtime_t)(header[i_skip+3] << 7)|
- (mtime_t)(header[i_skip+4] >> 1);
- if( header[i_skip]&0x10 ) /* has dts */
- {
- i_dts = ((mtime_t)(header[i_skip+5]&0x0e ) << 29)|
- (mtime_t)(header[i_skip+6] << 22)|
- ((mtime_t)(header[i_skip+7]&0xfe) << 14)|
- (mtime_t)(header[i_skip+8] << 7)|
- (mtime_t)(header[i_skip+9] >> 1);
- i_skip += 10;
- }
- else
- {
- i_skip += 5;
- }
- }
- else
- {
- i_skip += 1;
- }
- }
- break;
- }
- if( pid->es->fmt.i_codec == VLC_FOURCC( 'a', '5', '2', 'b' ) ||
- pid->es->fmt.i_codec == VLC_FOURCC( 'd', 't', 's', 'b' ) )
- {
- i_skip += 4;
- }
- else if( pid->es->fmt.i_codec == VLC_FOURCC( 'l', 'p', 'c', 'b' ) ||
- pid->es->fmt.i_codec == VLC_FOURCC( 's', 'p', 'u', 'b' ) ||
- pid->es->fmt.i_codec == VLC_FOURCC( 's', 'd', 'd', 'b' ) )
- {
- i_skip += 1;
- }
- else if( pid->es->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) &&
- pid->es->p_mpeg4desc )
- {
- decoder_config_descriptor_t *dcd = &pid->es->p_mpeg4desc->dec_descr;
- if( dcd->i_decoder_specific_info_len > 2 &&
- dcd->p_decoder_specific_info[0] == 0x10 &&
- ( dcd->p_decoder_specific_info[1]&0x10 ) )
- {
- /* display length */
- if( p_pes->i_buffer + 2 <= i_skip )
- {
- i_length = GetWBE( &p_pes->p_buffer[i_skip] );
- }
- i_skip += 2;
- }
- if( p_pes->i_buffer + 2 <= i_skip )
- {
- i_pes_size = GetWBE( &p_pes->p_buffer[i_skip] );
- }
- /* */
- i_skip += 2;
- }
- /* skip header */
- while( p_pes && i_skip > 0 )
- {
- if( p_pes->i_buffer <= i_skip )
- {
- block_t *p_next = p_pes->p_next;
- i_skip -= p_pes->i_buffer;
- block_Release( p_pes );
- p_pes = p_next;
- }
- else
- {
- p_pes->i_buffer -= i_skip;
- p_pes->p_buffer += i_skip;
- break;
- }
- }
- if( p_pes )
- {
- block_t *p_block;
- int i;
- if( i_dts >= 0 )
- {
- p_pes->i_dts = i_dts * 100 / 9;
- }
- if( i_pts >= 0 )
- {
- p_pes->i_pts = i_pts * 100 / 9;
- }
- p_pes->i_length = i_length * 100 / 9;
- p_block = block_ChainGather( p_pes );
- if( pid->es->fmt.i_codec == VLC_FOURCC( 's', 'u', 'b', 't' ) )
- {
- if( i_pes_size > 0 && p_block->i_buffer > i_pes_size )
- {
- p_block->i_buffer = i_pes_size;
- }
- /* Append a