/*****************************************************************************
* ts.c: Transport Stream input module for VLC.
*****************************************************************************
- * Copyright (C) 2004 VideoLAN
+ * Copyright (C) 2004-2005 VideoLAN (Centrale Réseaux) and its contributors
* $Id$
*
* 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
*
* 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
+#include <ctype.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "iso_lang.h"
#include "network.h"
+#include "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
+
/* TODO:
* - XXX: do not mark options message to be translated, they are too osbcure for now ...
* - test it
* - ...
*/
+#define vlc_meta_Add(a,b,c) fprintf(stderr, "FIXME: TS demuxer meta is broken\n" )
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define PMT_TEXT N_("Extra PMT")
#define PMT_LONGTEXT N_( \
- "Allows a user to specify an extra pmt (pmt_pid=pid:stream_type[,...])" )
+ "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 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)")
+ "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 MTUOUT_LONGTEXT N_("MTU for out mode.")
#define CSA_TEXT N_("CSA ck")
-#define CSA_LONGTEXT N_("CSA ck")
+#define CSA_LONGTEXT N_("Control word for the CSA encryption algorithm")
#define SILENT_TEXT N_("Silent mode")
-#define SILENT_LONGTEXT N_("do not complain on encrypted PES")
+#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 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( _("ISO 13818-1 MPEG Transport Stream input - new" ) );
- set_shortname ( _("MPEG-TS") );
+ set_description( _("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, VLC_TRUE );
- add_bool( "ts-es-id-pid", 0, NULL, PID_TEXT, PID_LONGTEXT, VLC_TRUE );
+ add_bool( "ts-es-id-pid", 1, 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_integer( "ts-csa-pkt", 188, NULL, CPKT_TEXT, CPKT_LONGTEXT, VLC_TRUE );
add_bool( "ts-silent", 0, NULL, SILENT_TEXT, SILENT_LONGTEXT, VLC_TRUE );
- add_integer( "ts-capmt-sysid", 0, NULL, CAPMT_SYSID_TEXT,
- CAPMT_SYSID_LONGTEXT, VLC_TRUE );
+
+ add_file( "ts-dump-file", NULL, NULL, TSDUMP_TEXT, TSDUMP_LONGTEXT, VLC_FALSE );
+ add_bool( "ts-dump-append", 0, NULL, APPEND_TEXT, APPEND_LONGTEXT, VLC_FALSE );
+ add_integer( "ts-dump-size", 16384, NULL, DUMPSIZE_TEXT,
+ DUMPSIZE_LONGTEXT, VLC_TRUE );
set_capability( "demux2", 10 );
set_callbacks( Open, Close );
typedef struct
{
- uint8_t i_iod_label;
+ uint8_t i_iod_label, i_iod_label_scope;
/* IOD */
uint16_t i_od_id;
typedef struct
{
- /* for special PAT case */
- dvbpsi_handle handle;
+ /* for special PAT/SDT case */
+ dvbpsi_handle handle; /* PAT/SDT/EIT */
int i_pat_version;
+ int i_sdt_version;
/* For PMT */
int i_prg;
/* */
vlc_bool_t b_es_id_pid;
csa_t *csa;
+ int i_csa_pkt_size;
vlc_bool_t b_silent;
- uint16_t i_capmt_sysid;
vlc_bool_t b_udp_out;
int fd; /* udp socket */
vlc_bool_t b_dvb_control;
int i_dvb_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 */
+ vlc_bool_t b_file_out; /* dump mode enabled */
+
+ /* */
+ vlc_bool_t b_meta;
};
-static int Demux ( demux_t *p_demux );
+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, 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 );
+#ifdef TS_USE_DVB_SI
+static void PSINewTableCallBack( demux_t *, dvbpsi_handle,
+ uint8_t i_table_id, uint16_t i_extension );
+#endif
static inline int PIDGet( block_t *p )
{
#define TS_PACKET_SIZE_192 192
#define TS_PACKET_SIZE_204 204
#define TS_PACKET_SIZE_MAX 204
+#define TS_TOPFIELD_HEADER 1320
/*****************************************************************************
* Open
int i_sync, i_peek, i;
int i_packet_size;
- ts_pid_t *pat;
+ ts_pid_t *pat;
+ char *psz_mode;
+ vlc_bool_t b_append;
+ vlc_bool_t b_topfield = VLC_FALSE;
vlc_value_t val;
if( stream_Peek( p_demux->s, &p_peek, TS_PACKET_SIZE_MAX ) <
TS_PACKET_SIZE_MAX ) return VLC_EGENERIC;
+ if( p_peek[0] == 'T' && p_peek[1] == 'F' &&
+ p_peek[2] == 'r' && p_peek[3] == 'c' )
+ {
+ b_topfield = VLC_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 )
+ if( i_sync >= TS_PACKET_SIZE_MAX && !b_topfield )
{
if( strcmp( p_demux->psz_demux, "ts" ) ) 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( 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" );
{
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] = '\0';
+ 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] = '\0';
+ memcpy( psz_event_text, &p_peek[91+i_name], 129-i_name );
+ psz_event_text[129-i_name] = '\0';
+ 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] = '\0';
+ 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;
}
- /* 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 ) );
+ p_sys->i_packet_size = i_packet_size;
+
+ /* Fill dump mode fields */
+ p_sys->i_write = 0;
+ p_sys->p_file = NULL;
+ p_sys->b_file_out = VLC_FALSE;
+ p_sys->psz_file = var_CreateGetString( p_demux, "ts-dump-file" );
+ if( *p_sys->psz_file != '\0' )
+ {
+ p_sys->b_file_out = VLC_TRUE;
+
+ var_Create( p_demux, "ts-dump-append", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
+ var_Get( p_demux, "ts-dump-append", &val );
+ b_append = val.b_bool;
+ 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 = VLC_FALSE;
+ }
+
+ if( p_sys->b_file_out )
+ {
+ vlc_value_t bufsize;
+
+ /* Determine how many packets to read. */
+ var_Create( p_demux, "ts-dump-size",
+ VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_demux, "ts-dump-size", &bufsize );
+ p_sys->i_ts_read = (int) (bufsize.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 );
+ 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_meta = VLC_TRUE;
p_sys->b_dvb_control = VLC_TRUE;
p_sys->i_dvb_program = 0;
for( i = 0; i < 8192; i++ )
pid->b_seen = VLC_FALSE;
pid->b_valid = VLC_FALSE;
}
+ /* PID 8191 is padding */
+ p_sys->pid[8191].b_seen = VLC_TRUE;
p_sys->i_packet_size = i_packet_size;
p_sys->b_udp_out = VLC_FALSE;
p_sys->i_ts_read = 50;
PIDInit( pat, VLC_TRUE, NULL );
pat->psi->handle = dvbpsi_AttachPAT( (dvbpsi_pat_callback)PATCallBack,
p_demux );
+#ifdef TS_USE_DVB_SI
+ if( p_sys->b_meta )
+ {
+ ts_pid_t *sdt = &p_sys->pid[0x11];
+ ts_pid_t *eit = &p_sys->pid[0x12];
+
+ PIDInit( sdt, VLC_TRUE, NULL );
+ sdt->psi->handle =
+ dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
+ p_demux );
+ PIDInit( eit, VLC_TRUE, NULL );
+ eit->psi->handle =
+ dvbpsi_AttachDemux( (dvbpsi_demux_new_cb_t)PSINewTableCallBack,
+ p_demux );
+ if( p_sys->b_dvb_control )
+ {
+ stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
+ ACCESS_SET_PRIVATE_ID_STATE, 0x11, VLC_TRUE );
+ stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
+ ACCESS_SET_PRIVATE_ID_STATE, 0x12, VLC_TRUE );
+ }
+ }
+#endif
/* Init PMT array */
p_sys->i_pmt = 0;
/* 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,
+ 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 )
+ if( val.psz_string && *val.psz_string && !p_sys->b_file_out )
{
vlc_value_t mtu;
char *psz = strchr( val.psz_string, ':' );
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 );
+ p_sys->fd = net_ConnectUDP( p_demux, val.psz_string, i_port, 0 );
if( p_sys->fd < 0 )
{
msg_Err( p_demux, "failed to open udp socket, send disabled" );
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 );
{
ck[i] = ( i_ck >> ( 56 - 8*i) )&0xff;
}
-
+#ifndef TS_NO_CSA_CK_MSG
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] );
-
+#endif
p_sys->csa = csa_New();
- csa_SetCW( p_sys->csa, ck, ck );
+
+ if( p_sys->csa )
+ {
+ vlc_value_t pkt_val;
+
+ csa_SetCW( p_sys->csa, ck, ck );
+
+ var_Create( p_demux, "ts-csa-pkt", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+ var_Get( p_demux, "ts-csa-pkt", &pkt_val );
+ if( pkt_val.i_int < 4 || pkt_val.i_int > 188 )
+ {
+ msg_Err( p_demux, "wrong packet size %d specified.", pkt_val.i_int );
+ 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 = pkt_val.i_int;
+ msg_Dbg( p_demux, "decrypting %d bytes of packet", p_sys->i_csa_pkt_size );
+ }
}
}
if( val.psz_string )
var_Get( p_demux, "ts-silent", &val );
p_sys->b_silent = val.b_bool;
- var_Create( p_demux, "ts-capmt-sysid", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
- var_Get( p_demux, "ts-capmt-sysid", &val );
- p_sys->i_capmt_sysid = val.i_int;
-
return VLC_SUCCESS;
}
case 1: /* CAT */
free( pid->psi );
break;
+ case 0x11: /* SDT */
+ case 0x12: /* EIT */
+ dvbpsi_DetachDemux( pid->psi->handle );
+ free( pid->psi );
+ break;
default:
PIDClean( p_demux->out, pid );
break;
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 ("I64Fd" Kbytes dumped)", p_sys->psz_file,
+ p_sys->i_write / 1024 );
+
+ if( p_sys->p_file != stdout )
+ {
+ fclose( p_sys->p_file );
+ p_sys->p_file = NULL;
+ }
+
+ free( p_sys->buffer );
+ }
+
+ free( p_sys->psz_file );
+ p_sys->psz_file = NULL;
+
free( p_sys );
}
+/*****************************************************************************
+ * DemuxFile:
+ *****************************************************************************/
+static int DemuxFile( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ uint8_t *p_buffer = p_sys->buffer; /* Put first on sync byte */
+ int i_diff= 0;
+ int i_data= 0;
+ int i_pos = 0;
+ int i_bufsize = p_sys->i_packet_size * p_sys->i_ts_read;
+
+ 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 */
+ while( i_pos < i_data )
+ {
+ ts_pid_t *p_pid; /* point to a PID structure */
+ vlc_bool_t b_payload; /* indicates a packet with payload */
+ vlc_bool_t b_adaptation; /* adaptation field */
+ int i_cc = 0; /* continuity counter */
+
+ if( p_sys->buffer[i_pos] != 0x47 )
+ {
+ msg_Warn( p_demux, "lost sync" );
+ while( !p_demux->b_die && (i_pos < i_data) )
+ {
+ i_pos++;
+ if( p_sys->buffer[i_pos] == 0x47 )
+ break;
+ }
+ if( !p_demux->b_die )
+ 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 ?
+ */
+ i_cc = p_buffer[i_pos+3]&0x0f;
+ b_payload = p_buffer[i_pos+3]&0x10;
+ b_adaptation = p_buffer[i_pos+3]&0x20;
+
+ /* Get the PID */
+ 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 )
+ {
+ 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 );
+ }
+
+ i_diff = ( i_cc - p_pid->i_cc )&0x0f;
+ if( b_payload && i_diff == 1 )
+ {
+ p_pid->i_cc++;
+ }
+ 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 )
+ csa_Decrypt( p_demux->p_sys->csa, &p_buffer[i_pos], p_demux->p_sys->i_csa_pkt_size );
+
+ i_pos += p_sys->i_packet_size;
+ }
+
+ /* Then write */
+ i_data = fwrite( p_sys->buffer, 1, i_data, p_sys->p_file );
+ if( i_data < 0 )
+ {
+ msg_Err( p_demux, "failed to write data" );
+ return -1;
+ }
+#if 0
+ msg_Dbg( p_demux, "dumped %d bytes", i_data );
+#endif
+
+ p_sys->i_write += i_data;
+ return 1;
+}
+
/*****************************************************************************
* Demux:
*****************************************************************************/
{
if( p_pid->psi )
{
- if( p_pid->i_pid == 0 )
+ if( p_pid->i_pid == 0 || p_pid->i_pid == 0x11 || p_pid->i_pid == 0x12 )
{
dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer );
}
demux_sys_t *p_sys = p_demux->p_sys;
double f, *pf;
int64_t i64;
+ int64_t *pi64;
int i_int;
+ if( p_sys->b_file_out )
+ return demux2_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args );
+
switch( i_query )
{
case DEMUX_GET_POSITION:
}
*pi64 = 0;
return VLC_EGENERIC;
+#else
+ case DEMUX_GET_TIME:
+ case DEMUX_GET_LENGTH:
+ pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = 0;
+ return VLC_SUCCESS;
#endif
case DEMUX_SET_GROUP:
{
if( !b_old_valid )
{
pid->psi = malloc( sizeof( ts_psi_t ) );
+ pid->psi->handle= NULL;
pid->psi->i_prg = 0;
pid->psi->prg = NULL;
- pid->psi->handle= NULL;
}
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 ) );
const vlc_bool_t b_adaptation = p[3]&0x20;
const vlc_bool_t b_payload = p[3]&0x10;
const int i_cc = p[3]&0x0f; /* continuity counter */
+ vlc_bool_t b_discontinuity = VLC_FALSE;/* discontinuity */
/* transport_scrambling_control is ignored */
-
int i_skip = 0;
vlc_bool_t i_ret = VLC_FALSE;
int i_diff;
{
msg_Dbg( p_demux, "transport_error_indicator set (pid=%d)",
pid->i_pid );
+ if( pid->es->p_pes ) //&& pid->es->fmt.i_cat == VIDEO_ES )
+ pid->es->p_pes->i_flags |= BLOCK_FLAG_CORRUPTED;
}
if( p_demux->p_sys->csa )
{
- csa_Decrypt( p_demux->p_sys->csa, p_bk->p_buffer );
+ csa_Decrypt( p_demux->p_sys->csa, p_bk->p_buffer, p_demux->p_sys->i_csa_pkt_size );
}
if( !b_adaptation )
i_skip = 5 + p[4];
if( p[4] > 0 )
{
- if( p[5]&0x80 )
+ /* discontinuity indicator found in stream */
+ b_discontinuity = (p[5]&0x80) ? VLC_TRUE : VLC_FALSE;
+ if( b_discontinuity && pid->es->p_pes )
{
- msg_Warn( p_demux, "discontinuity_indicator (pid=%d) "
- "ignored", pid->i_pid );
+ msg_Warn( p_demux, "discontinuity indicator (pid=%d) ",
+ pid->i_pid );
+ /* pid->es->p_pes->i_flags |= BLOCK_FLAG_DISCONTINUITY; */
}
+#if 0
+ if( p[5]&0x40 )
+ msg_Dbg( p_demux, "random access indicator (pid=%d) ", pid->i_pid );
+#endif
}
}
* diff == 0 and duplicate packet (playload != 0) <- should we
* test the content ?
*/
-
i_diff = ( i_cc - pid->i_cc )&0x0f;
if( b_payload && i_diff == 1 )
{
pid->i_pid, i_cc );
pid->i_cc = i_cc;
}
- else if( i_diff != 0 )
+ else if( i_diff != 0 && !b_discontinuity )
{
- /* FIXME what to do when discontinuity_indicator is set ? */
- msg_Warn( p_demux, "discontinuity received 0x%x instead of 0x%x",
- i_cc, ( pid->i_cc + 1 )&0x0f );
+ msg_Warn( p_demux, "discontinuity received 0x%x instead of 0x%x (pid=%d)",
+ i_cc, ( pid->i_cc + 1 )&0x0f, pid->i_pid );
pid->i_cc = i_cc;
-
if( pid->es->p_pes && pid->es->fmt.i_cat != VIDEO_ES )
{
/* Small video artifacts are usually better then
case 0x92: /* DVD_SPU vls (sub) */
es_format_Init( fmt, SPU_ES, VLC_FOURCC( 's', 'p', 'u', 'b' ) );
break;
- case 0x93: /* LPCM vls (audio) */
- es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 'l', 'p', 'c', 'b' ) );
- break;
+
case 0x94: /* SDDS (audio) */
es_format_Init( fmt, AUDIO_ES, VLC_FOURCC( 's', 'd', 'd', 'b' ) );
break;
iod_descriptor_t *p_iod;
int i;
int i_es_index;
- uint8_t i_flags;
+ uint8_t i_flags, i_iod_tag, byte1, byte2, byte3;
vlc_bool_t b_url;
int i_iod_length;
p_iod = malloc( sizeof( iod_descriptor_t ) );
memset( p_iod, 0, sizeof( iod_descriptor_t ) );
+#ifdef DEBUG
fprintf( stderr, "\n************ IOD ************" );
+#endif
for( i = 0; i < 255; i++ )
{
p_iod->es_descr[i].b_ok = 0;
return p_iod;
}
- p_iod->i_iod_label = IODGetByte( &i_data, &p_data );
+ byte1 = IODGetByte( &i_data, &p_data );
+ byte2 = IODGetByte( &i_data, &p_data );
+ byte3 = IODGetByte( &i_data, &p_data );
+ if( byte2 == 0x02 ) //old vlc's buggy implementation of the IOD_descriptor
+ {
+ p_iod->i_iod_label_scope = 0x11;
+ p_iod->i_iod_label = byte1;
+ i_iod_tag = byte2;
+ }
+ else //correct implementation of the IOD_descriptor
+ {
+ p_iod->i_iod_label_scope = byte1;
+ p_iod->i_iod_label = byte2;
+ i_iod_tag = byte3;
+ }
+#ifdef DEBUG
fprintf( stderr, "\n* iod_label:%d", p_iod->i_iod_label );
fprintf( stderr, "\n* ===========" );
- fprintf( stderr, "\n* tag:0x%x", p_data[0] );
-
- if( IODGetByte( &i_data, &p_data ) != 0x02 )
+ fprintf( stderr, "\n* tag:0x%x", i_iod_tag );
+#endif
+ if( i_iod_tag != 0x02 )
{
- fprintf( stderr, "\n ERR: tag != 0x02" );
+#ifdef DEBUG
+ fprintf( stderr, "\n ERR: tag %02x != 0x02", i_iod_tag );
+#endif
return p_iod;
}
i_iod_length = IODDescriptorLength( &i_data, &p_data );
+#ifdef DEBUG
fprintf( stderr, "\n* length:%d", i_iod_length );
+#endif
if( i_iod_length > i_data )
{
i_iod_length = i_data;
i_flags = IODGetByte( &i_data, &p_data );
p_iod->i_od_id |= i_flags >> 6;
b_url = ( i_flags >> 5 )&0x01;
-
+#ifdef DEBUG
fprintf( stderr, "\n* od_id:%d", p_iod->i_od_id );
fprintf( stderr, "\n* url flag:%d", b_url );
fprintf( stderr, "\n* includeInlineProfileLevel flag:%d", ( i_flags >> 4 )&0x01 );
-
+#endif
if( b_url )
{
p_iod->psz_url = IODGetURL( &i_data, &p_data );
+#ifdef DEBUG
fprintf( stderr, "\n* url string:%s", p_iod->psz_url );
fprintf( stderr, "\n*****************************\n" );
+#endif
return p_iod;
}
else
p_iod->i_audioProfileLevelIndication = IODGetByte( &i_data, &p_data );
p_iod->i_visualProfileLevelIndication = IODGetByte( &i_data, &p_data );
p_iod->i_graphicsProfileLevelIndication = IODGetByte( &i_data, &p_data );
-
+#ifdef DEBUG
fprintf( stderr, "\n* ODProfileLevelIndication:%d", p_iod->i_ODProfileLevelIndication );
fprintf( stderr, "\n* sceneProfileLevelIndication:%d", p_iod->i_sceneProfileLevelIndication );
fprintf( stderr, "\n* audioProfileLevelIndication:%d", p_iod->i_audioProfileLevelIndication );
fprintf( stderr, "\n* visualProfileLevelIndication:%d", p_iod->i_visualProfileLevelIndication );
fprintf( stderr, "\n* graphicsProfileLevelIndication:%d", p_iod->i_graphicsProfileLevelIndication );
-
+#endif
while( i_data > 0 && i_es_index < 255)
{
{
#define es_descr p_iod->es_descr[i_es_index]
int i_decoderConfigDescr_length;
+#ifdef DEBUG
fprintf( stderr, "\n* - ES_Descriptor length:%d", i_length );
+#endif
es_descr.b_ok = 1;
es_descr.i_es_id = IODGetWord( &i_data, &p_data );
b_url = ( i_flags >> 6 )&0x01;
es_descr.b_OCRStreamFlag = ( i_flags >> 5 )&0x01;
es_descr.i_streamPriority = i_flags & 0x1f;
+#ifdef DEBUG
fprintf( stderr, "\n* * streamDependenceFlag:%d", es_descr.b_streamDependenceFlag );
fprintf( stderr, "\n* * OCRStreamFlag:%d", es_descr.b_OCRStreamFlag );
fprintf( stderr, "\n* * streamPriority:%d", es_descr.i_streamPriority );
-
+#endif
if( es_descr.b_streamDependenceFlag )
{
es_descr.i_dependOn_es_id = IODGetWord( &i_data, &p_data );
+#ifdef DEBUG
fprintf( stderr, "\n* * dependOn_es_id:%d", es_descr.i_dependOn_es_id );
+#endif
}
if( b_url )
{
es_descr.psz_url = IODGetURL( &i_data, &p_data );
+#ifdef DEBUG
fprintf( stderr, "\n* url string:%s", es_descr.psz_url );
+#endif
}
else
{
if( es_descr.b_OCRStreamFlag )
{
es_descr.i_OCR_es_id = IODGetWord( &i_data, &p_data );
+#ifdef DEBUG
fprintf( stderr, "\n* * OCR_es_id:%d", es_descr.i_OCR_es_id );
+#endif
}
if( IODGetByte( &i_data, &p_data ) != 0x04 )
{
+#ifdef DEBUG
fprintf( stderr, "\n* ERR missing DecoderConfigDescr" );
+#endif
es_descr.b_ok = 0;
break;
}
i_decoderConfigDescr_length = IODDescriptorLength( &i_data, &p_data );
-
+#ifdef DEBUG
fprintf( stderr, "\n* - DecoderConfigDesc length:%d", i_decoderConfigDescr_length );
+#endif
#define dec_descr es_descr.dec_descr
dec_descr.i_objectTypeIndication = IODGetByte( &i_data, &p_data );
i_flags = IODGetByte( &i_data, &p_data );
dec_descr.i_bufferSizeDB = IODGet3Bytes( &i_data, &p_data );
dec_descr.i_maxBitrate = IODGetDWord( &i_data, &p_data );
dec_descr.i_avgBitrate = IODGetDWord( &i_data, &p_data );
+#ifdef DEBUG
fprintf( stderr, "\n* * objectTypeIndication:0x%x", dec_descr.i_objectTypeIndication );
fprintf( stderr, "\n* * streamType:0x%x", dec_descr.i_streamType );
fprintf( stderr, "\n* * upStream:%d", dec_descr.b_upStream );
fprintf( stderr, "\n* * bufferSizeDB:%d", dec_descr.i_bufferSizeDB );
fprintf( stderr, "\n* * maxBitrate:%d", dec_descr.i_maxBitrate );
fprintf( stderr, "\n* * avgBitrate:%d", dec_descr.i_avgBitrate );
+#endif
if( i_decoderConfigDescr_length > 13 && IODGetByte( &i_data, &p_data ) == 0x05 )
{
int i;
if( IODGetByte( &i_data, &p_data ) != 0x06 )
{
+#ifdef DEBUG
fprintf( stderr, "\n* ERR missing SLConfigDescr" );
+#endif
es_descr.b_ok = 0;
break;
}
i_SLConfigDescr_length = IODDescriptorLength( &i_data, &p_data );
-
+#ifdef DEBUG
fprintf( stderr, "\n* - SLConfigDescr length:%d", i_SLConfigDescr_length );
+#endif
i_predefined = IODGetByte( &i_data, &p_data );
+#ifdef DEBUG
fprintf( stderr, "\n* * i_predefined:0x%x", i_predefined );
+#endif
switch( i_predefined )
{
case 0x01:
}
break;
default:
+#ifdef DEBUG
fprintf( stderr, "\n* ERR unsupported SLConfigDescr predefined" );
+#endif
es_descr.b_ok = 0;
break;
}
#undef sl_descr
#undef es_descr
default:
+#ifdef DEBUG
fprintf( stderr, "\n* - OD tag:0x%x length:%d (Unsupported)", i_tag, i_length );
+#endif
break;
}
i_data = i_data_sav - i_length;
i_es_index++;
}
-
-
+#ifdef DEBUG
fprintf( stderr, "\n*****************************\n" );
+#endif
return p_iod;
}
demux_sys_t *p_sys = p_demux->p_sys;
if ( !p_sys->b_dvb_control ) return VLC_FALSE;
- if ( p_sys->i_dvb_program == -1 && p_sys->p_programs_list == NULL )
+ if ( (p_sys->i_dvb_program == -1 && p_sys->p_programs_list == NULL)
+ || p_sys->i_dvb_program == 0 )
return VLC_TRUE;
if ( p_sys->i_dvb_program == i_pgrm ) return VLC_TRUE;
return VLC_FALSE;
}
+#ifdef TS_USE_DVB_SI
+static void SDTCallBack( demux_t *p_demux, dvbpsi_sdt_t *p_sdt )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ ts_pid_t *sdt = &p_sys->pid[0x11];
+ dvbpsi_sdt_service_t *p_srv;
+
+ msg_Dbg( p_demux, "SDTCallBack called" );
+
+ if( sdt->psi->i_sdt_version != -1 &&
+ ( !p_sdt->b_current_next ||
+ p_sdt->i_version == sdt->psi->i_sdt_version ) )
+ {
+ dvbpsi_DeleteSDT( p_sdt );
+ return;
+ }
+
+ msg_Dbg( p_demux, "new SDT ts_id=%d version=%d current_next=%d "
+ "network_id=%d",
+ p_sdt->i_ts_id, p_sdt->i_version, p_sdt->b_current_next,
+ p_sdt->i_network_id );
+
+ for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next )
+ {
+ vlc_meta_t *p_meta = vlc_meta_New();
+ dvbpsi_descriptor_t *p_dr;
+
+ msg_Dbg( p_demux, " * service id=%d eit schedule=%d present=%d "
+ "running=%d free_ca=%d",
+ p_srv->i_service_id, p_srv->b_eit_schedule,
+ p_srv->b_eit_present, p_srv->i_running_status,
+ p_srv->b_free_ca );
+
+ for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
+ {
+ if( p_dr->i_tag == 0x48 )
+ {
+ static const char *psz_type[0x11] = {
+ "Reserved",
+ "Digital television service",
+ "Digital radio sound service",
+ "Teletext service",
+ "NVOD reference service",
+ "NVOD time-shifted service",
+ "Mosaic service",
+ "PAL coded signal",
+ "SECAM coded signal",
+ "D/D2-MAC",
+ "FM Radio",
+ "NTSC coded signal",
+ "Data broadcast service",
+ "Reserved for Common Interface Usage",
+ "RCS Map (see EN 301 790 [35])",
+ "RCS FLS (see EN 301 790 [35])",
+ "DVB MHP service"
+ };
+ dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr );
+ char str1[257];
+ char str2[257];
+
+ memcpy( str1, pD->i_service_provider_name,
+ pD->i_service_provider_name_length );
+ str1[pD->i_service_provider_name_length] = '\0';
+ memcpy( str2, pD->i_service_name, pD->i_service_name_length );
+ str2[pD->i_service_name_length] = '\0';
+
+ msg_Dbg( p_demux, " - type=%d provider=%s name=%s",
+ pD->i_service_type, str1, str2 );
+
+ vlc_meta_Add( p_meta, "Name", str2 );
+ vlc_meta_Add( p_meta, "Provider", str1 );
+ if( pD->i_service_type >= 0x01 && pD->i_service_type <= 0x10 )
+ vlc_meta_Add( p_meta, "Type", psz_type[pD->i_service_type] );
+ }
+ }
+
+ if( p_srv->i_running_status == 0x01 )
+ vlc_meta_Add( p_meta, "Status", "Not running" );
+ else if( p_srv->i_running_status == 0x02 )
+ vlc_meta_Add( p_meta, "Status", "Starts in a few seconds" );
+ else if( p_srv->i_running_status == 0x03 )
+ vlc_meta_Add( p_meta, "Status", "Pausing" );
+ else if( p_srv->i_running_status == 0x04 )
+ vlc_meta_Add( p_meta, "Status", "Running" );
+ else
+ vlc_meta_Add( p_meta, "Status", "Unknown" );
+
+
+ es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META,
+ p_srv->i_service_id, p_meta );
+ vlc_meta_Delete( p_meta );
+ }
+
+ sdt->psi->i_sdt_version = p_sdt->i_version;
+ dvbpsi_DeleteSDT( p_sdt );
+}
+#if 0
+static void DecodeMjd( int i_mjd, int *p_y, int *p_m, int *p_d )
+{
+ int yp = (int)( ( (double)i_mjd - 15078.2)/365.25 );
+ int mp = (int)( ((double)i_mjd - 14956.1 - (int)(yp * 365.25)) / 30.6001 );
+
+ *p_d = i_mjd - 14956 - (int)(yp*365.25) - (int)(mp*30.6001);
+
+ if( mp == 14 || mp == 15 )
+ {
+ *p_y = yp + 1;
+ *p_m = mp - 1 + 12;
+ }
+ else
+ {
+ *p_y = yp;
+ *p_m = mp - 1;
+ }
+}
+#endif
+static void EITEventFixString( unsigned char *psz )
+{
+ int i_len;
+ /* Sometimes the first char isn't a normal char but designed
+ * caracters encoding, for now lets skip it */
+ if( psz[0] >= 0x20 )
+ return;
+ if( ( i_len = strlen( (char *) psz ) ) > 0 )
+ memmove( &psz[0], &psz[1], i_len ); /* Copy the \0 too */
+}
+static void EITCallBack( demux_t *p_demux, dvbpsi_eit_t *p_eit )
+{
+ dvbpsi_eit_event_t *p_evt;
+ vlc_meta_t *p_meta;
+ vlc_bool_t b_event_active = VLC_FALSE;
+
+ msg_Dbg( p_demux, "EITCallBack called" );
+ if( !p_eit->b_current_next )
+ {
+ dvbpsi_DeleteEIT( p_eit );
+ return;
+ }
+
+ msg_Dbg( p_demux, "new EIT service_id=%d version=%d current_next=%d "
+ "ts_id=%d network_id=%d segment_last_section_number=%d "
+ "last_table_id=%d",
+ p_eit->i_service_id, p_eit->i_version, p_eit->b_current_next,
+ p_eit->i_ts_id, p_eit->i_network_id,
+ p_eit->i_segment_last_section_number, p_eit->i_last_table_id );
+
+ p_meta = vlc_meta_New();
+ for( p_evt = p_eit->p_first_event; p_evt; p_evt = p_evt->p_next )
+ {
+ dvbpsi_descriptor_t *p_dr;
+ char *psz_cat = malloc( strlen("Event")+10 );
+ char psz_start[15];
+ char psz_duration[15];
+ char psz_name[256];
+ char psz_text[256];
+ char *psz_extra = strdup("");
+ char *psz_value;
+
+ sprintf( psz_cat, "Event %d", p_evt->i_event_id );
+ sprintf( psz_start, "%d%d:%d%d:%d%d",
+ (int)(p_evt->i_start_time >> 20)&0xf,
+ (int)(p_evt->i_start_time >> 16)&0xf,
+ (int)(p_evt->i_start_time >> 12)&0xf,
+ (int)(p_evt->i_start_time >> 8)&0xf,
+ (int)(p_evt->i_start_time >> 4)&0xf,
+ (int)(p_evt->i_start_time )&0xf );
+ sprintf( psz_duration, "%d%d:%d%d:%d%d",
+ (p_evt->i_duration >> 20)&0xf, (p_evt->i_duration >> 16)&0xf,
+ (p_evt->i_duration >> 12)&0xf, (p_evt->i_duration >> 8)&0xf,
+ (p_evt->i_duration >> 4)&0xf, (p_evt->i_duration )&0xf );
+ psz_name[0] = psz_text[0] = '\0';
+
+ msg_Dbg( p_demux, " * event id=%d start_time:mjd=%d %s duration=%s "
+ "running=%d free_ca=%d",
+ p_evt->i_event_id,
+ (int)(p_evt->i_start_time >> 24),
+ psz_start, psz_duration,
+ p_evt->i_running_status, p_evt->b_free_ca );
+
+ for( p_dr = p_evt->p_first_descriptor; p_dr; p_dr = p_dr->p_next )
+ {
+ if( p_dr->i_tag == 0x4d )
+ {
+ dvbpsi_short_event_dr_t *pE = dvbpsi_DecodeShortEventDr( p_dr );
+
+ if( pE )
+ {
+ memcpy( psz_name, pE->i_event_name, pE->i_event_name_length);
+ psz_name[pE->i_event_name_length] = '\0';
+ memcpy( psz_text, pE->i_text, pE->i_text_length );
+ psz_text[pE->i_text_length] = '\0';
+
+ EITEventFixString((unsigned char *)&psz_name);
+ EITEventFixString((unsigned char *)&psz_text);
+ msg_Dbg( p_demux, " - short event lang=%3.3s '%s' : '%s'",
+ pE->i_iso_639_code, psz_name, psz_text );
+ }
+ }
+ else if( p_dr->i_tag == 0x4e )
+ {
+ dvbpsi_extended_event_dr_t *pE = dvbpsi_DecodeExtendedEventDr( p_dr );
+ char str1[257];
+ char str2[257];
+
+ if( pE )
+ {
+ int i;
+ msg_Dbg( p_demux, " - extended event lang=%3.3s",
+ pE->i_iso_639_code );
+ for( i = 0; i < pE->i_entry_count; i++ )
+ {
+ memcpy( str1, pE->i_item_description[i],
+ pE->i_item_description_length[i] );
+ str1[pE->i_item_description_length[i]] = '\0';
+ EITEventFixString((unsigned char *)&str1);
+
+ memcpy( str2, pE->i_item[i],
+ pE->i_item_length[i] );
+ str2[pE->i_item_length[i]] = '\0';
+ EITEventFixString((unsigned char *)&str2);
+
+ msg_Dbg( p_demux, " - desc='%s' item='%s'", str1, str2 );
+ psz_extra = realloc( psz_extra,
+ strlen(psz_extra) +
+ strlen(str1) +strlen(str2) + 1 + 3 );
+ strcat( psz_extra, str1 );
+ strcat( psz_extra, "(" );
+ strcat( psz_extra, str2 );
+ strcat( psz_extra, ") " );
+ }
+
+ memcpy( str1, pE->i_text, pE->i_text_length );
+ str1[pE->i_text_length] = '\0';
+ EITEventFixString((unsigned char *)&str1);
+
+ msg_Dbg( p_demux, " - text='%s'", str1 );
+ psz_extra = realloc( psz_extra,
+ strlen(psz_extra) + strlen(str1) + 2 );
+ strcat( psz_extra, str1 );
+ strcat( psz_extra, " " );
+ }
+ }
+ else
+ {
+ msg_Dbg( p_demux, " - tag=0x%x(%d)", p_dr->i_tag, p_dr->i_tag );
+ }
+ }
+
+ asprintf( &psz_value, "%s: %s (+%s) %s (%s)",
+ psz_start,
+ psz_name,
+ psz_duration,
+ psz_text, psz_extra );
+ vlc_meta_Add( p_meta, psz_cat, psz_value );
+ free( psz_value );
+
+ if( p_evt->i_running_status == 0x04 )
+ {
+ vlc_meta_Add( p_meta, VLC_META_NOW_PLAYING, psz_name );
+ b_event_active = VLC_TRUE;
+ }
+
+ free( psz_cat );
+ free( psz_extra );
+ }
+
+ if( !b_event_active )
+ vlc_meta_Add( p_meta, VLC_META_NOW_PLAYING, "" );
+ es_out_Control( p_demux->out, ES_OUT_SET_GROUP_META,
+ p_eit->i_service_id, p_meta );
+ vlc_meta_Delete( p_meta );
+
+ dvbpsi_DeleteEIT( p_eit );
+}
+
+static void PSINewTableCallBack( demux_t *p_demux, dvbpsi_handle h,
+ uint8_t i_table_id, uint16_t i_extension )
+{
+#if 0
+ msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)",
+ i_table_id, i_table_id, i_extension, i_extension );
+#endif
+
+ if( i_table_id == 0x42 )
+ {
+ msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)",
+ i_table_id, i_table_id, i_extension, i_extension );
+
+ dvbpsi_AttachSDT( h, i_table_id, i_extension,
+ (dvbpsi_sdt_callback)SDTCallBack, p_demux );
+ }
+ else if( i_table_id == 0x4e || /* Current/Following */
+ ( i_table_id >= 0x50 && i_table_id <= 0x5f ) ) /* Schedule */
+ {
+ msg_Dbg( p_demux, "PSINewTableCallBack: table 0x%x(%d) ext=0x%x(%d)",
+ i_table_id, i_table_id, i_extension, i_extension );
+
+ dvbpsi_AttachEIT( h, i_table_id, i_extension,
+ (dvbpsi_eit_callback)EITCallBack, p_demux );
+ }
+}
+#endif
+
static void PMTCallBack( demux_t *p_demux, dvbpsi_pmt_t *p_pmt )
{
demux_sys_t *p_sys = p_demux->p_sys;
if( !old_pid && p_sys->pid[p_es->i_pid].b_valid )
{
- msg_Warn( p_demux, "pmt error: pid=%d already defined",
- p_es->i_pid );
- continue;
+ ts_pid_t *pid = &p_sys->pid[p_es->i_pid];
+ if( ( pid->i_pid == 0x11 /* SDT */ ||
+ pid->i_pid == 0x12 /* EDT */ ) && pid->psi )
+ {
+ /* This doesn't look like a DVB stream so don't try
+ * parsing the SDT/EDT */
+ dvbpsi_DetachDemux( pid->psi->handle );
+ free( pid->psi );
+ pid->psi = 0;
+ }
+ else
+ {
+ msg_Warn( p_demux, "pmt error: pid=%d already defined",
+ p_es->i_pid );
+ continue;
+ }
}
PIDInit( pid, VLC_FALSE, pmt->psi );
case 0x20: /* mpeg4 */
pid->es->fmt.i_codec = VLC_FOURCC('m','p','4','v');
break;
+ case 0x21: /* h264 */
+ pid->es->fmt.i_codec = VLC_FOURCC('h','2','6','4');
+ break;
case 0x60:
case 0x61:
case 0x62:
else if( p_dr->i_tag == 0x73 )
{
/* DTS audio descriptor (ETSI TS 101 154 Annex F) */
- msg_Dbg( p_demux, " * DTS audio descriptor not decoded" );
+ msg_Dbg( p_demux, " * DTS audio descriptor not decoded" );
pid->es->fmt.i_cat = AUDIO_ES;
pid->es->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
}
else if( p_dr->i_tag == 0x45 )
{
- msg_Dbg( p_demux, " * VBI Data descriptor" );
- pid->es->fmt.i_cat = SPU_ES;
- pid->es->fmt.i_codec = VLC_FOURCC( 'v', 'b', 'i', 'd' );
- pid->es->fmt.psz_description = strdup( "VBI Data" );
- pid->es->fmt.i_extra = p_dr->i_length;
- pid->es->fmt.p_extra = malloc( p_dr->i_length );
- memcpy( pid->es->fmt.p_extra, p_dr->p_data,
- p_dr->i_length );
+ msg_Dbg( p_demux, " * VBI Data descriptor" );
+ /* FIXME : store the information somewhere */
}
else if( p_dr->i_tag == 0x46 )
{
- msg_Dbg( p_demux, " * VBI Teletext descriptor" );
- pid->es->fmt.i_cat = SPU_ES;
- pid->es->fmt.i_codec = VLC_FOURCC( 'v', 'b', 'i', 't' );
- pid->es->fmt.psz_description = strdup( "VBI Teletext" );
- pid->es->fmt.i_extra = p_dr->i_length;
- pid->es->fmt.p_extra = malloc( p_dr->i_length );
- memcpy( pid->es->fmt.p_extra, p_dr->p_data,
- p_dr->i_length );
+ msg_Dbg( p_demux, " * VBI Teletext descriptor" );
+ /* FIXME : store the information somewhere */
+ }
+#ifdef _DVBPSI_DR_52_H_
+ else if( p_dr->i_tag == 0x52 )
+ {
+ dvbpsi_stream_identifier_dr_t *si;
+ si = dvbpsi_DecodeStreamIdentifierDr( p_dr );
+
+ msg_Dbg( p_demux, " * Stream Component Identifier: %d", si->i_component_tag );
}
+#endif
else if( p_dr->i_tag == 0x56 )
{
- msg_Dbg( p_demux, " * EBU Teletext descriptor" );
+ msg_Dbg( p_demux, " * EBU Teletext descriptor" );
pid->es->fmt.i_cat = SPU_ES;
pid->es->fmt.i_codec = VLC_FOURCC( 't', 'e', 'l', 'x' );
pid->es->fmt.psz_description = strdup( "Teletext" );
/* Delete PMT pid */
for( i = 0; i < i_pmt_rm; i++ )
{
+ int i_prg;
if( p_sys->b_dvb_control )
{
if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS,
p_sys->b_dvb_control = VLC_FALSE;
}
+ for( i_prg = 0; i_prg < pmt_rm[i]->psi->i_prg; i_prg++ )
+ {
+ const int i_number = pmt_rm[i]->psi->prg[i_prg]->i_number;
+ if( i_number != 0 )
+ es_out_Control( p_demux->out, ES_OUT_DEL_GROUP, i_number );
+ }
+
PIDClean( p_demux->out, &p_sys->pid[pmt_rm[i]->i_pid] );
TAB_REMOVE( p_sys->i_pmt, p_sys->pmt, pmt_rm[i] );
}
if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_SET_PRIVATE_ID_STATE, p_program->i_pid, VLC_TRUE ) )
p_sys->b_dvb_control = VLC_FALSE;
}
- else
- {
- if( stream_Control( p_demux->s, STREAM_CONTROL_ACCESS, ACCESS_SET_PRIVATE_ID_STATE, p_program->i_pid, VLC_FALSE ) )
- p_sys->b_dvb_control = VLC_FALSE;
- }
}
}
}