ts.c
资源名称:vlc-1.0.5.zip [点击查看]
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:136k
源码类别:
midi
开发平台:
Unix_Linux
- /*****************************************************************************
- * ts.c: Transport Stream input module for VLC.
- *****************************************************************************
- * Copyright (C) 2004-2005 the VideoLAN team
- * $Id: b36dc4f95c879180c1d0893655b12ff7590b9f81 $
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- * Jean-Paul Saman <jpsaman #_at_# m2x.nl>
- *
- * 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 <vlc_common.h>
- #include <vlc_plugin.h>
- #include <ctype.h>
- #include <assert.h>
- #include <vlc_access.h> /* DVB-specific things */
- #include <vlc_demux.h>
- #include <vlc_meta.h>
- #include <vlc_epg.h>
- #include <vlc_iso_lang.h>
- #include <vlc_network.h>
- #include <vlc_charset.h>
- #include "../mux/mpeg/csa.h"
- /* Include dvbpsi headers */
- #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
- /* EIT support */
- #ifdef _DVBPSI_DR_4D_H_
- # define TS_USE_DVB_SI 1
- # ifdef HAVE_DVBPSI_DR_H
- # include <dvbpsi/eit.h>
- # else
- # include "tables/eit.h"
- # endif
- #endif
- #include <time.h>
- #undef TS_DEBUG
- /*****************************************************************************
- * Module descriptor
- *****************************************************************************/
- static int Open ( vlc_object_t * );
- static void Close ( vlc_object_t * );
- /* TODO
- * - Rename "extra pmt" to "user pmt"
- * - Update extra pmt description
- * pmt_pid[:pmt_number][=pid_description[,pid_description]]
- * where pid_description could take 3 forms:
- * 1. pid:pcr (to force the pcr pid)
- * 2. pid:stream_type
- * 3. pid:type=fourcc where type=(video|audio|spu)
- */
- #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 the internal ID of each elementary stream"
- " handled by VLC to the same value as the PID in"
- " the TS stream, instead of 1, 2, 3, etc. Useful to"
- " do '#duplicate{..., select="es=<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_("Control word for the CSA encryption algorithm")
- #define CSA2_TEXT N_("Second CSA Key")
- #define CSA2_LONGTEXT N_("The even CSA encryption key. This must be a "
- "16 char string (8 hexadecimal bytes).")
- #define SILENT_TEXT N_("Silent mode")
- #define SILENT_LONGTEXT N_("Do not complain on encrypted PES.")
- #define CAPMT_SYSID_TEXT N_("CAPMT System ID")
- #define CAPMT_SYSID_LONGTEXT N_("Only forward descriptors from this SysID to the CAM.")
- #define CPKT_TEXT N_("Packet size in bytes to decrypt")
- #define CPKT_LONGTEXT N_("Specify the size of the TS packet to decrypt. "
- "The decryption routines subtract the TS-header from the value before "
- "decrypting. " )
- #define TSDUMP_TEXT N_("Filename of dump")
- #define TSDUMP_LONGTEXT N_("Specify a filename where to dump the TS in.")
- #define APPEND_TEXT N_("Append")
- #define APPEND_LONGTEXT N_(
- "If the file exists and this option is selected, the existing file "
- "will not be overwritten." )
- #define DUMPSIZE_TEXT N_("Dump buffer size")
- #define DUMPSIZE_LONGTEXT N_(
- "Tweak the buffer size for reading and writing an integer number of packets."
- "Specify the size of the buffer here and not the number of packets." )
- vlc_module_begin ()
- set_description( N_("MPEG Transport Stream demuxer") )
- set_shortname ( "MPEG-TS" )
- set_category( CAT_INPUT )
- set_subcategory( SUBCAT_INPUT_DEMUX )
- add_string( "ts-extra-pmt", NULL, NULL, PMT_TEXT, PMT_LONGTEXT, true )
- add_bool( "ts-es-id-pid", 1, NULL, PID_TEXT, PID_LONGTEXT, true )
- add_string( "ts-out", NULL, NULL, TSOUT_TEXT, TSOUT_LONGTEXT, true )
- add_integer( "ts-out-mtu", 1400, NULL, MTUOUT_TEXT,
- MTUOUT_LONGTEXT, true )
- add_string( "ts-csa-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true )
- add_string( "ts-csa2-ck", NULL, NULL, CSA_TEXT, CSA_LONGTEXT, true )
- add_integer( "ts-csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, true )
- add_bool( "ts-silent", 0, NULL, SILENT_TEXT, SILENT_LONGTEXT, true )
- add_file( "ts-dump-file", NULL, NULL, TSDUMP_TEXT, TSDUMP_LONGTEXT, false )
- add_bool( "ts-dump-append", 0, NULL, APPEND_TEXT, APPEND_LONGTEXT, false )
- add_integer( "ts-dump-size", 16384, NULL, DUMPSIZE_TEXT,
- DUMPSIZE_LONGTEXT, true )
- set_capability( "demux", 10 )
- set_callbacks( Open, Close )
- add_shortcut( "ts" )
- vlc_module_end ()
- /*****************************************************************************
- * Local prototypes
- *****************************************************************************/
- static const char *const ppsz_teletext_type[] = {
- "",
- N_("Teletext"),
- N_("Teletext subtitles"),
- N_("Teletext: additional information"),
- N_("Teletext: program schedule"),
- N_("Teletext subtitles: hearing impaired")
- };
- typedef struct
- {
- uint8_t i_objectTypeIndication;
- uint8_t i_streamType;
- bool 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
- {
- bool b_useAccessUnitStartFlag;
- bool b_useAccessUnitEndFlag;
- bool b_useRandomAccessPointFlag;
- bool b_useRandomAccessUnitsOnlyFlag;
- bool b_usePaddingFlag;
- bool b_useTimeStampsFlags;
- bool b_useIdleFlag;
- bool 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
- {
- bool b_ok;
- uint16_t i_es_id;
- bool b_streamDependenceFlag;
- bool 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, i_iod_label_scope;
- /* 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;
- } ts_prg_psi_t;
- typedef struct
- {
- /* for special PAT/SDT case */
- dvbpsi_handle handle; /* PAT/SDT/EIT */
- int i_pat_version;
- int i_sdt_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;
- bool b_seen;
- bool b_valid;
- int i_cc; /* countinuity counter */
- bool b_scrambled;
- /* 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
- {
- vlc_mutex_t csa_lock;
- /* 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 */
- bool b_user_pmt;
- int i_pmt;
- ts_pid_t **pmt;
- /* */
- bool b_es_id_pid;
- csa_t *csa;
- int i_csa_pkt_size;
- bool b_silent;
- bool b_udp_out;
- int fd; /* udp socket */
- uint8_t *buffer;
- /* */
- bool b_access_control;
- /* */
- bool b_dvb_meta;
- int64_t i_dvb_start;
- int64_t i_dvb_length;
- /* */
- int i_current_program;
- vlc_list_t *p_programs_list;
- /* TS dump */
- char *psz_file; /* file to dump data in */
- FILE *p_file; /* filehandle */
- uint64_t i_write; /* bytes written */
- bool b_file_out; /* dump mode enabled */
- /* */
- bool b_start_record;
- };
- static int i_broken_epg;
- static int Demux ( demux_t *p_demux );
- static int DemuxFile( demux_t *p_demux );
- static int Control( demux_t *p_demux, int i_query, va_list args );
- static void PIDInit ( ts_pid_t *pid, bool 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 );
- #ifdef TS_USE_DVB_SI
- static void PSINewTableCallBack( demux_t *, dvbpsi_handle,
- uint8_t i_table_id, uint16_t i_extension );
- #endif
- static int ChangeKeyCallback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
- static inline int PIDGet( block_t *p )
- {
- return ( (p->p_buffer[1]&0x1f)<<8 )|p->p_buffer[2];
- }
- static bool 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 * );
- #define TS_USER_PMT_NUMBER (0)
- static int UserPmt( demux_t *p_demux, const char * );
- #define TS_PACKET_SIZE_188 188
- #define TS_PACKET_SIZE_192 192
- #define TS_PACKET_SIZE_204 204
- #define TS_PACKET_SIZE_MAX 204
- #define TS_TOPFIELD_HEADER 1320
- /*****************************************************************************
- * Open
- *****************************************************************************/
- static int Open( vlc_object_t *p_this )
- {
- demux_t *p_demux = (demux_t*)p_this;
- demux_sys_t *p_sys;
- const uint8_t *p_peek;
- int i_sync, i_peek, i;
- int i_packet_size;
- ts_pid_t *pat;
- const char *psz_mode;
- bool b_append;
- bool b_topfield = false;
- if( stream_Peek( p_demux->s, &p_peek, TS_PACKET_SIZE_MAX ) <
- TS_PACKET_SIZE_MAX ) return VLC_EGENERIC;
- if( memcmp( p_peek, "TFrc", 4 ) == 0 )
- {
- b_topfield = true;
- msg_Dbg( p_demux, "this is a topfield file" );
- }
- /* 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 && !b_topfield )
- {
- if( !p_demux->b_force )
- return VLC_EGENERIC;
- msg_Warn( p_demux, "this does not look like a TS stream, continuing" );
- }
- if( b_topfield )
- {
- /* Read the entire Topfield header */
- i_peek = TS_TOPFIELD_HEADER;
- }
- else
- {
- /* 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( p_demux->b_force )
- {
- i_packet_size = TS_PACKET_SIZE_188;
- }
- else if( b_topfield )
- {
- i_packet_size = TS_PACKET_SIZE_188;
- #if 0
- /* I used the TF5000PVR 2004 Firmware .doc header documentation,
- * http://www.i-topfield.com/data/product/firmware/Structure%20of%20Recorded%20File%20in%20TF5000PVR%20(Feb%2021%202004).doc
- * but after the filename the offsets seem to be incorrect. - DJ */
- int i_duration, i_name;
- char *psz_name = malloc(25);
- char *psz_event_name;
- char *psz_event_text = malloc(130);
- char *psz_ext_text = malloc(1025);
- // 2 bytes version Uimsbf (4,5)
- // 2 bytes reserved (6,7)
- // 2 bytes duration in minutes Uimsbf (8,9(
- i_duration = (int) (p_peek[8] << 8) | p_peek[9];
- msg_Dbg( p_demux, "Topfield recording length: +/- %d minutes", i_duration);
- // 2 bytes service number in channel list (10, 11)
- // 2 bytes service type Bslbf 0=TV 1=Radio Bslb (12, 13)
- // 4 bytes of reserved + tuner info (14,15,16,17)
- // 2 bytes of Service ID Bslbf (18,19)
- // 2 bytes of PMT PID Uimsbf (20,21)
- // 2 bytes of PCR PID Uimsbf (22,23)
- // 2 bytes of Video PID Uimsbf (24,25)
- // 2 bytes of Audio PID Uimsbf (26,27)
- // 24 bytes filename Bslbf
- memcpy( psz_name, &p_peek[28], 24 );
- psz_name[24] = ' ';
- msg_Dbg( p_demux, "recordingname=%s", psz_name );
- // 1 byte of sat index Uimsbf (52)
- // 3 bytes (1 bit of polarity Bslbf +23 bits reserved)
- // 4 bytes of freq. Uimsbf (56,57,58,59)
- // 2 bytes of symbol rate Uimsbf (60,61)
- // 2 bytes of TS stream ID Uimsbf (62,63)
- // 4 bytes reserved
- // 2 bytes reserved
- // 2 bytes duration Uimsbf (70,71)
- //i_duration = (int) (p_peek[70] << 8) | p_peek[71];
- //msg_Dbg( p_demux, "Topfield 2nd duration field: +/- %d minutes", i_duration);
- // 4 bytes EventID Uimsbf (72-75)
- // 8 bytes of Start and End time info (76-83)
- // 1 byte reserved (84)
- // 1 byte event name length Uimsbf (89)
- i_name = (int)(p_peek[89]&~0x81);
- msg_Dbg( p_demux, "event name length = %d", i_name);
- psz_event_name = malloc( i_name+1 );
- // 1 byte parental rating (90)
- // 129 bytes of event text
- memcpy( psz_event_name, &p_peek[91], i_name );
- psz_event_name[i_name] = ' ';
- memcpy( psz_event_text, &p_peek[91+i_name], 129-i_name );
- psz_event_text[129-i_name] = ' ';
- msg_Dbg( p_demux, "event name=%s", psz_event_name );
- msg_Dbg( p_demux, "event text=%s", psz_event_text );
- // 12 bytes reserved (220)
- // 6 bytes reserved
- // 2 bytes Event Text Length Uimsbf
- // 4 bytes EventID Uimsbf
- // FIXME We just have 613 bytes. not enough for this entire text
- // 1024 bytes Extended Event Text Bslbf
- memcpy( psz_ext_text, p_peek+372, 1024 );
- psz_ext_text[1024] = ' ';
- msg_Dbg( p_demux, "extended event text=%s", psz_ext_text );
- // 52 bytes reserved Bslbf
- #endif
- }
- else
- {
- msg_Warn( p_demux, "TS module discarded (lost sync)" );
- return VLC_EGENERIC;
- }
- p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
- if( !p_sys )
- return VLC_ENOMEM;
- memset( p_sys, 0, sizeof( demux_sys_t ) );
- p_sys->i_packet_size = i_packet_size;
- vlc_mutex_init( &p_sys->csa_lock );
- /* Fill dump mode fields */
- p_sys->i_write = 0;
- p_sys->buffer = NULL;
- p_sys->p_file = NULL;
- p_sys->b_file_out = false;
- p_sys->psz_file = var_CreateGetString( p_demux, "ts-dump-file" );
- if( *p_sys->psz_file != ' ' )
- {
- p_sys->b_file_out = true;
- b_append = var_CreateGetBool( p_demux, "ts-dump-append" );
- if ( b_append )
- psz_mode = "ab";
- else
- psz_mode = "wb";
- if( !strcmp( p_sys->psz_file, "-" ) )
- {
- msg_Info( p_demux, "dumping raw stream to standard output" );
- p_sys->p_file = stdout;
- }
- else if( ( p_sys->p_file = utf8_fopen( p_sys->psz_file, psz_mode ) ) == NULL )
- {
- msg_Err( p_demux, "cannot create `%s' for writing", p_sys->psz_file );
- p_sys->b_file_out = false;
- }
- if( p_sys->b_file_out )
- {
- /* Determine how many packets to read. */
- int bufsize = var_CreateGetInteger( p_demux, "ts-dump-size" );
- p_sys->i_ts_read = (int) (bufsize / 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 );
- msg_Info( p_demux, "%s raw stream to file `%s' reading packets %d",
- b_append ? "appending" : "dumping", p_sys->psz_file,
- p_sys->i_ts_read );
- }
- }
- /* Fill p_demux field */
- if( p_sys->b_file_out )
- p_demux->pf_demux = DemuxFile;
- else
- p_demux->pf_demux = Demux;
- p_demux->pf_control = Control;
- /* Init p_sys field */
- p_sys->b_dvb_meta = true;
- p_sys->b_access_control = true;
- p_sys->i_current_program = 0;
- p_sys->i_dvb_start = 0;
- p_sys->i_dvb_length = 0;
- for( i = 0; i < 8192; i++ )
- {
- ts_pid_t *pid = &p_sys->pid[i];
- pid->i_pid = i;
- pid->b_seen = false;
- pid->b_valid = false;
- }
- /* PID 8191 is padding */
- p_sys->pid[8191].b_seen = true;
- p_sys->i_packet_size = i_packet_size;
- p_sys->b_udp_out = false;
- p_sys->fd = -1;
- p_sys->i_ts_read = 50;
- p_sys->csa = NULL;
- p_sys->b_start_record = false;
- /* Init PAT handler */
- pat = &p_sys->pid[0];
- PIDInit( pat, true, NULL );
- pat->psi->handle = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack,
- p_demux );
- #ifdef TS_USE_DVB_SI
- if( p_sys->b_dvb_meta )
- {
- ts_pid_t *sdt = &p_sys->pid[0x11];
- ts_pid_t *eit = &p_sys->pid[0x12];
- PIDInit( sdt, true, NULL );
- sdt->psi->handle =
- dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
- p_demux );
- PIDInit( eit, true, NULL );
- eit->psi->handle =
- dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
- p_demux );
- if( p_sys->b_access_control )
- {
- if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, 0x11, true ) ||
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, 0x12, true ) )
- p_sys->b_access_control = false;
- }
- }
- #endif
- /* Init PMT array */
- TAB_INIT( p_sys->i_pmt, p_sys->pmt );
- /* Read config */
- p_sys->b_es_id_pid = var_CreateGetBool( p_demux, "ts-es-id-pid" );
- char* psz_string = var_CreateGetString( p_demux, "ts-out" );
- if( psz_string && *psz_string && !p_sys->b_file_out )
- {
- char *psz = strchr( psz_string, ':' );
- int i_port = 0;
- p_sys->b_udp_out = true;
- if( psz )
- {
- *psz++ = ' ';
- i_port = atoi( psz );
- }
- if( i_port <= 0 ) i_port = 1234;
- msg_Dbg( p_demux, "resend ts to '%s:%d'", psz_string, i_port );
- p_sys->fd = net_ConnectUDP( VLC_OBJECT(p_demux), psz_string, i_port, -1 );
- if( p_sys->fd < 0 )
- {
- msg_Err( p_demux, "failed to open udp socket, send disabled" );
- p_sys->b_udp_out = false;
- }
- else
- {
- int i_mtu = var_CreateGetInteger( p_demux, "ts-out-mtu" );
- p_sys->i_ts_read = i_mtu / 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 );
- }
- }
- free( psz_string );
- /* We handle description of an extra PMT */
- psz_string = var_CreateGetString( p_demux, "ts-extra-pmt" );
- p_sys->b_user_pmt = false;
- if( psz_string && *psz_string )
- UserPmt( p_demux, psz_string );
- free( psz_string );
- psz_string = var_CreateGetStringCommand( p_demux, "ts-csa-ck" );
- if( psz_string && *psz_string )
- {
- int i_res;
- char* psz_csa2;
- p_sys->csa = csa_New();
- psz_csa2 = var_CreateGetStringCommand( p_demux, "ts-csa2-ck" );
- i_res = csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, true );
- if( i_res == VLC_SUCCESS && psz_csa2 && *psz_csa2 )
- {
- if( csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_csa2, false ) != VLC_SUCCESS )
- {
- csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, false );
- }
- }
- else if ( i_res == VLC_SUCCESS )
- {
- csa_SetCW( (vlc_object_t*)p_demux, p_sys->csa, psz_string, false );
- }
- else
- {
- csa_Delete( p_sys->csa );
- p_sys->csa = NULL;
- }
- if( p_sys->csa )
- {
- var_AddCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, (void *)1 );
- var_AddCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
- int i_pkt = var_CreateGetInteger( p_demux, "ts-csa-pkt" );
- if( i_pkt < 4 || i_pkt > 188 )
- {
- msg_Err( p_demux, "wrong packet size %d specified.", i_pkt );
- msg_Warn( p_demux, "using default packet size of 188 bytes" );
- p_sys->i_csa_pkt_size = 188;
- }
- else
- p_sys->i_csa_pkt_size = i_pkt;
- msg_Dbg( p_demux, "decrypting %d bytes of packet", p_sys->i_csa_pkt_size );
- }
- free( psz_csa2 );
- }
- free( psz_string );
- p_sys->b_silent = var_CreateGetBool( p_demux, "ts-silent" );
- 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;
- msg_Dbg( p_demux, "pid list:" );
- for( int 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:
- if( p_sys->b_dvb_meta && ( pid->i_pid == 0x11 || pid->i_pid == 0x12 ) )
- {
- /* SDT or EIT */
- dvbpsi_DetachDemux( pid->psi->handle );
- free( pid->psi );
- }
- else
- {
- 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_access_control && pid->i_pid > 0 )
- {
- /* too much */
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, pid->i_pid,
- false );
- }
- }
- vlc_mutex_lock( &p_sys->csa_lock );
- if( p_sys->csa )
- {
- var_DelCallback( p_demux, "ts-csa-ck", ChangeKeyCallback, NULL );
- var_DelCallback( p_demux, "ts-csa2-ck", ChangeKeyCallback, NULL );
- csa_Delete( p_sys->csa );
- }
- vlc_mutex_unlock( &p_sys->csa_lock );
- TAB_CLEAN( p_sys->i_pmt, 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 );
- }
- /* If in dump mode, then close the file */
- if( p_sys->b_file_out )
- {
- msg_Info( p_demux ,"closing %s (%"PRId64" Kbytes dumped)",
- p_sys->psz_file, p_sys->i_write / 1024 );
- if( p_sys->p_file != stdout )
- {
- fclose( p_sys->p_file );
- }
- }
- /* When streaming, close the port */
- if( p_sys->fd > -1 )
- {
- net_Close( p_sys->fd );
- }
- free( p_sys->buffer );
- free( p_sys->psz_file );
- vlc_mutex_destroy( &p_sys->csa_lock );
- 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);
- demux_t *p_demux = (demux_t*)p_this;
- demux_sys_t *p_sys = p_demux->p_sys;
- int i_tmp = (intptr_t)p_data;
- vlc_mutex_lock( &p_sys->csa_lock );
- if ( i_tmp )
- i_tmp = csa_SetCW( p_this, p_sys->csa, newval.psz_string, true );
- else
- i_tmp = csa_SetCW( p_this, p_sys->csa, newval.psz_string, false );
- vlc_mutex_unlock( &p_sys->csa_lock );
- return i_tmp;
- }
- /*****************************************************************************
- * DemuxFile:
- *****************************************************************************/
- static int DemuxFile( demux_t *p_demux )
- {
- demux_sys_t *p_sys = p_demux->p_sys;
- const int i_bufsize = p_sys->i_packet_size * p_sys->i_ts_read;
- uint8_t *p_buffer = p_sys->buffer; /* Put first on sync byte */
- const int i_data = stream_Read( p_demux->s, p_sys->buffer, i_bufsize );
- if( i_data <= 0 && i_data < p_sys->i_packet_size )
- {
- msg_Dbg( p_demux, "error reading malformed packets" );
- return i_data;
- }
- /* Test continuity counter */
- for( int i_pos = 0; i_pos < i_data; )
- {
- if( p_sys->buffer[i_pos] != 0x47 )
- {
- msg_Warn( p_demux, "lost sync" );
- while( vlc_object_alive (p_demux) && (i_pos < i_data) )
- {
- i_pos++;
- if( p_sys->buffer[i_pos] == 0x47 )
- break;
- }
- if( vlc_object_alive (p_demux) )
- msg_Warn( p_demux, "sync found" );
- }
- /* continuous when (one of this):
- * diff == 1
- * diff == 0 and payload == 0
- * diff == 0 and duplicate packet (playload != 0) <- should we
- * test the content ?
- */
- const int i_cc = p_buffer[i_pos+3]&0x0f;
- const bool b_payload = p_buffer[i_pos+3]&0x10;
- const bool b_adaptation = p_buffer[i_pos+3]&0x20;
- /* Get the PID */
- ts_pid_t *p_pid = &p_sys->pid[ ((p_buffer[i_pos+1]&0x1f)<<8)|p_buffer[i_pos+2] ];
- /* Detect discontinuity indicator in adaptation field */
- if( b_adaptation && p_buffer[i_pos + 4] > 0 )
- {
- if( p_buffer[i_pos+5]&0x80 )
- msg_Warn( p_demux, "discontinuity indicator (pid=%d) ", p_pid->i_pid );
- if( p_buffer[i_pos+5]&0x40 )
- msg_Warn( p_demux, "random access indicator (pid=%d) ", p_pid->i_pid );
- }
- const int i_diff = ( i_cc - p_pid->i_cc )&0x0f;
- if( b_payload && i_diff == 1 )
- {
- p_pid->i_cc = ( p_pid->i_cc + 1 ) & 0xf;
- }
- else
- {
- if( p_pid->i_cc == 0xff )
- {
- msg_Warn( p_demux, "first packet for pid=%d cc=0x%x",
- p_pid->i_pid, i_cc );
- p_pid->i_cc = i_cc;
- }
- else if( i_diff != 0 )
- {
- /* FIXME what to do when discontinuity_indicator is set ? */
- msg_Warn( p_demux, "transport error detected 0x%x instead of 0x%x",
- i_cc, ( p_pid->i_cc + 1 )&0x0f );
- p_pid->i_cc = i_cc;
- /* Mark transport error in the TS packet. */
- p_buffer[i_pos+1] |= 0x80;
- }
- }
- /* Test if user wants to decrypt it first */
- if( p_sys->csa )
- {
- vlc_mutex_lock( &p_sys->csa_lock );
- csa_Decrypt( p_demux->p_sys->csa, &p_buffer[i_pos], p_demux->p_sys->i_csa_pkt_size );
- vlc_mutex_unlock( &p_sys->csa_lock );
- }
- i_pos += p_sys->i_packet_size;
- }
- /* Then write */
- const int i_write = fwrite( p_sys->buffer, 1, i_data, p_sys->p_file );
- if( i_write < 0 )
- {
- msg_Err( p_demux, "failed to write data" );
- return -1;
- }
- p_sys->i_write += i_write;
- return 1;
- }
- /*****************************************************************************
- * Demux:
- *****************************************************************************/
- static int Demux( demux_t *p_demux )
- {
- demux_sys_t *p_sys = p_demux->p_sys;
- /* We read at most 100 TS packet or until a frame is completed */
- for( int i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
- {
- bool b_frame = false;
- block_t *p_pkt;
- /* 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( vlc_object_alive (p_demux) )
- {
- const 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_start_record )
- {
- /* Enable recording once synchronized */
- stream_Control( p_demux->s, STREAM_SET_RECORD_STATE, true, "ts" );
- p_sys->b_start_record = false;
- }
- 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 */
- ts_pid_t *p_pid = &p_sys->pid[PIDGet( p_pkt )];
- if( p_pid->b_valid )
- {
- if( p_pid->psi )
- {
- if( p_pid->i_pid == 0 || ( p_sys->b_dvb_meta && ( p_pid->i_pid == 0x11 || p_pid->i_pid == 0x12 ) ) )
- {
- dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer );
- }
- else
- {
- for( int 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 = true;
- if( b_frame )
- break;
- }
- if( p_sys->b_udp_out )
- {
- /* Send the complete block */
- net_Write( p_demux, p_sys->fd, NULL, p_sys->buffer,
- p_sys->i_ts_read * p_sys->i_packet_size );
- }
- return 1;
- }
- /*****************************************************************************
- * Control:
- *****************************************************************************/
- static int DVBEventInformation( demux_t *p_demux, int64_t *pi_time, int64_t *pi_length )
- {
- demux_sys_t *p_sys = p_demux->p_sys;
- if( pi_length )
- *pi_length = 0;
- if( pi_time )
- *pi_time = 0;
- if( p_sys->b_access_control && p_sys->i_dvb_length > 0 )
- {
- /* FIXME we should not use time() but read the date from the tdt */
- const time_t t = time( NULL );
- if( p_sys->i_dvb_start <= t && t < p_sys->i_dvb_start + p_sys->i_dvb_length )
- {
- if( pi_length )
- *pi_length = p_sys->i_dvb_length * INT64_C(1000000);
- if( pi_time )
- *pi_time = (t - p_sys->i_dvb_start) * INT64_C(1000000);
- return VLC_SUCCESS;
- }
- }
- return VLC_EGENERIC;
- }
- 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;
- bool b_bool, *pb_bool;
- int64_t i64;
- int64_t *pi64;
- int i_int;
- if( p_sys->b_file_out )
- return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args );
- 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
- {
- int64_t i_time, i_length;
- if( !DVBEventInformation( p_demux, &i_time, &i_length ) && i_length > 0 )
- *pf = (double)i_time/(double)i_length;
- else
- *pf = 0.0;
- }
- return VLC_SUCCESS;
- case DEMUX_SET_POSITION:
- f = (double) va_arg( args, double );
- i64 = stream_Size( p_demux->s );
- 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 = INT64_C(1000000) * ( stream_Size( p_demux->s ) / 50 ) /
- p_sys->i_mux_rate;
- return VLC_SUCCESS;
- }
- *pi64 = 0;
- return VLC_EGENERIC;
- #else
- case DEMUX_GET_TIME:
- pi64 = (int64_t*)va_arg( args, int64_t * );
- if( DVBEventInformation( p_demux, pi64, NULL ) )
- *pi64 = 0;
- return VLC_SUCCESS;
- case DEMUX_GET_LENGTH:
- pi64 = (int64_t*)va_arg( args, int64_t * );
- if( DVBEventInformation( p_demux, NULL, pi64 ) )
- *pi64 = 0;
- return VLC_SUCCESS;
- #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_access_control && i_int > 0 && i_int != p_sys->i_current_program )
- {
- int i_pmt_pid = -1;
- /* Search pmt to be unselected */
- for( int i = 0; i < p_sys->i_pmt; i++ )
- {
- ts_pid_t *pmt = p_sys->pmt[i];
- for( int i_prg = 0; i_prg < pmt->psi->i_prg; i_prg++ )
- {
- if( pmt->psi->prg[i_prg]->i_number == p_sys->i_current_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,
- false );
- /* All ES */
- for( int i = 2; i < 8192; i++ )
- {
- ts_pid_t *pid = &p_sys->pid[i];
- if( !pid->b_valid || pid->psi )
- continue;
- for( int 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, false );
- break;
- }
- }
- }
- }
- /* select new program */
- p_sys->i_current_program = i_int;
- i_pmt_pid = -1;
- for( int i = 0; i < p_sys->i_pmt; i++ )
- {
- ts_pid_t *pmt = p_sys->pmt[i];
- for( int 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,
- true );
- stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
- ACCESS_SET_PRIVATE_ID_STATE, p_prg->i_pid_pcr,
- true );
- for( int i = 2; i < 8192; i++ )
- {
- ts_pid_t *pid = &p_sys->pid[i];
- if( !pid->b_valid || pid->psi )
- continue;
- for( int 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, true );
- break;
- }
- }
- }
- }
- }
- else
- {
- p_sys->i_current_program = -1;
- p_sys->p_programs_list = p_list;
- }
- return VLC_SUCCESS;
- }
- case DEMUX_CAN_RECORD:
- pb_bool = (bool*)va_arg( args, bool * );
- *pb_bool = true;
- return VLC_SUCCESS;
- case DEMUX_SET_RECORD_STATE:
- b_bool = (bool)va_arg( args, int );
- if( !b_bool )
- stream_Control( p_demux->s, STREAM_SET_RECORD_STATE, false );
- p_sys->b_start_record = b_bool;
- return VLC_SUCCESS;
- case DEMUX_GET_FPS:
- case DEMUX_SET_TIME:
- default:
- return VLC_EGENERIC;
- }
- }
- /*****************************************************************************
- *
- *****************************************************************************/
- static int UserPmt( demux_t *p_demux, const char *psz_fmt )
- {
- demux_sys_t *p_sys = p_demux->p_sys;
- char *psz_dup = strdup( psz_fmt );
- char *psz = psz_dup;
- int i_pid;
- int i_number;
- if( !psz_dup )
- return VLC_ENOMEM;
- /* Parse PID */
- i_pid = strtol( psz, &psz, 0 );
- if( i_pid < 2 || i_pid >= 8192 )
- goto error;
- /* Parse optional program number */
- i_number = 0;
- if( *psz == ':' )
- i_number = strtol( &psz[1], &psz, 0 );
- /* */
- ts_pid_t *pmt = &p_sys->pid[i_pid];
- ts_prg_psi_t *prg;
- msg_Dbg( p_demux, "user pmt specified (pid=%d,number=%d)", i_pid, i_number );
- PIDInit( pmt, true, NULL );
- /* Dummy PMT */
- prg = malloc( sizeof( ts_prg_psi_t ) );
- if( !prg )
- goto error;
- memset( prg, 0, sizeof( ts_prg_psi_t ) );
- prg->i_pid_pcr = -1;
- prg->i_pid_pmt = -1;
- prg->i_version = -1;
- prg->i_number = i_number != 0 ? i_number : TS_USER_PMT_NUMBER;
- prg->handle = dvbpsi_AttachPMT( i_number != TS_USER_PMT_NUMBER ? i_number : 1, (dvbpsi_pmt_callback)PMTCallBack, p_demux );
- TAB_APPEND( pmt->psi->i_prg, pmt->psi->prg, prg );
- psz = strchr( psz, '=' );
- if( psz )
- psz++;
- while( psz && *psz )
- {
- char *psz_next = strchr( psz, ',' );
- int i_pid;
- if( psz_next )
- *psz_next++ = ' ';
- i_pid = strtol( psz, &psz, 0 );
- if( *psz != ':' || i_pid < 2 || i_pid >= 8192 )
- goto next;
- char *psz_opt = &psz[1];
- if( !strcmp( psz_opt, "pcr" ) )
- {
- prg->i_pid_pcr = i_pid;
- }
- else if( !p_sys->pid[i_pid].b_valid )
- {
- ts_pid_t *pid = &p_sys->pid[i_pid];
- char *psz_arg = strchr( psz_opt, '=' );
- if( psz_arg )
- *psz_arg++ = ' ';
- PIDInit( pid, false, pmt->psi);
- if( prg->i_pid_pcr <= 0 )
- prg->i_pid_pcr = i_pid;
- if( psz_arg && strlen( psz_arg ) == 4 )
- {
- const vlc_fourcc_t i_codec = VLC_FOURCC( psz_arg[0], psz_arg[1],
- psz_arg[2], psz_arg[3] );
- int i_cat = UNKNOWN_ES;
- es_format_t *fmt = &pid->es->fmt;
- if( !strcmp( psz_opt, "video" ) )
- i_cat = VIDEO_ES;
- else if( !strcmp( psz_opt, "audio" ) )
- i_cat = AUDIO_ES;
- else if( !strcmp( psz_opt, "spu" ) )
- i_cat = SPU_ES;
- es_format_Init( fmt, i_cat, i_codec );
- fmt->b_packetized = false;
- }
- else
- {
- const int i_stream_type = strtol( psz_opt, NULL, 0 );
- PIDFillFormat( pid, i_stream_type );
- }
- pid->es->fmt.i_group = i_number;
- if( p_sys->b_es_id_pid )
- pid->es->fmt.i_id = i_pid;
- if( pid->es->fmt.i_cat != UNKNOWN_ES )
- {
- msg_Dbg( p_demux, " * es pid=%d fcc=%4.4s", i_pid,
- (char*)&pid->es->fmt.i_codec );
- pid->es->id = es_out_Add( p_demux->out,
- &pid->es->fmt );
- }
- }
- next:
- psz = psz_next;
- }
- p_sys->b_user_pmt = true;
- TAB_APPEND( p_sys->i_pmt, p_sys->pmt, pmt );
- free( psz_dup );
- return VLC_SUCCESS;
- error:
- free( psz_dup );
- return VLC_EGENERIC;
- }
- static void PIDInit( ts_pid_t *pid, bool b_psi, ts_psi_t *p_owner )
- {
- bool b_old_valid = pid->b_valid;
- pid->b_valid = true;
- pid->i_cc = 0xff;
- pid->b_scrambled = false;
- pid->p_owner = p_owner;
- pid->i_owner_number = 0;
- TAB_INIT( pid->i_extra_es, pid->extra_es );
- if( b_psi )
- {
- pid->es = NULL;
- if( !b_old_valid )
- {
- pid->psi = malloc( sizeof( ts_psi_t ) );
- if( pid->psi )
- {
- pid->psi->handle = NULL;
- TAB_INIT( pid->psi->i_prg, pid->psi->prg );
- }
- }
- assert( pid->psi );
- pid->psi->i_pat_version = -1;
- pid->psi->i_sdt_version = -1;
- if( p_owner )
- {
- ts_prg_psi_t *prg = malloc( sizeof( ts_prg_psi_t ) );
- if( prg )
- {
- /* PMT */
- prg->i_version = -1;
- prg->i_number = -1;
- prg->i_pid_pcr = -1;
- prg->i_pid_pmt = -1;
- prg->iod = NULL;
- prg->handle = NULL;
- TAB_APPEND( pid->psi->i_prg, pid->psi->prg, prg );
- }
- }
- }
- else
- {
- pid->psi = NULL;
- pid->es = malloc( sizeof( ts_es_t ) );
- if( pid->es )
- {
- 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 = false;
- }
- }
- }
- static void PIDClean( es_out_t *out, ts_pid_t *pid )
- {
- if( pid->psi )
- {
- if( pid->psi->handle )
- dvbpsi_DetachPMT( pid->psi->handle );
- for( int 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]->handle )
- dvbpsi_DetachPMT( pid->psi->prg[i]->handle );
- free( pid->psi->prg[i] );
- }
- free( pid->psi->prg );
- free( pid->psi );
- }
- else
- {
- 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( int 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 = 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[34];
- int i_pes_size = 0;
- int i_skip = 0;
- mtime_t i_dts = -1;
- mtime_t i_pts = -1;
- mtime_t i_length = 0;
- /* 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 */
- const int i_max = block_ChainExtract( p_pes, header, 34 );
- 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 0xF0: /* ECM */
- case 0xF1: /* 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;
- }
- #ifdef ZVBI_COMPILED
- else if( pid->es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
- i_skip = 0; /*hack for zvbi support */
- #endif
- /* 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;
- }
- }
- /* ISO/IEC 13818-1 2.7.5: if no pts and no dts, then dts == pts */
- if( i_pts >= 0 && i_dts < 0 )
- i_dts = i_pts;
- 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