* ts.c: Transport Stream input module for VLC.
*****************************************************************************
* Copyright (C) 2004 VideoLAN
- * $Id: ts.c,v 1.1 2004/01/16 01:47:41 fenrir Exp $
+ * $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
#include <vlc/input.h>
#include "iso_lang.h"
+#include "network.h"
+
+#include "../mux/mpeg/csa.h"
/* Include dvbpsi headers */
#ifdef HAVE_DVBPSI_DR_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 * );
+static int Open ( vlc_object_t * );
+static void Close ( vlc_object_t * );
vlc_module_begin();
set_description( _("ISO 13818-1 MPEG Transport Stream input - new" ) );
- add_category_hint( "TS demuxer", NULL, VLC_TRUE );
- add_string( "ts-extra-pmt", NULL, NULL, "extra PMT", "allow user to specify an extra pmt (pmt_pid=pid:stream_type[,...])", VLC_TRUE );
+ add_string( "ts-extra-pmt", NULL, NULL, "extra PMT", "allow user to specify an extra pmt (pmt_pid=pid:stream_type[,...])", VLC_TRUE );
+ add_bool( "ts-es-id-pid", 0, NULL, "set id of es to pid", "set id of es to pid", VLC_TRUE );
+ add_string( "ts-out", NULL, NULL, "fast udp streaming", "send TS to specific ip:port by udp (you must know what you are doing)", VLC_TRUE );
+ add_integer( "ts-out-mtu", 1500, NULL, "MTU for out mode", "MTU for out mode", VLC_TRUE );
+ add_string( "ts-csa-ck", NULL, NULL, "CSA ck", "CSA ck", VLC_TRUE );
set_capability( "demux2", 10 );
set_callbacks( Open, Close );
add_shortcut( "ts2" );
struct demux_sys_t
{
+ /* 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_udp_out;
+ int fd; /* udp socket */
+ uint8_t *buffer;
};
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 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 vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk );
-static char *LanguageNameISO639( char *p );
+
+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 IODFree( iod_descriptor_t * );
-static int ESFillFormat( es_format_t *fmt, int i_stream_type );
/*****************************************************************************
* Open
uint8_t *p_peek;
int i_peek;
+ int i_sync;
int i;
ts_pid_t *pat;
msg_Err( p_demux, "cannot peek" );
return VLC_EGENERIC;
}
- if( p_peek[0] != 0x47 || ( i_peek >= 189 && p_peek[188] != 0x47 ) )
+
+ /* Search first synch */
+ for( i_sync = 0; i_sync < i_peek; i_sync++ )
+ {
+ if( p_peek[i_sync] == 0x47 ) break;
+ }
+ if( i_sync >= i_peek )
{
- if( strcmp( p_demux->psz_demux, "ts" ) )
+ if( strcmp( p_demux->psz_demux, "ts2" ) )
{
msg_Warn( p_demux, "TS module discarded" );
return VLC_EGENERIC;
}
msg_Warn( p_demux, "this does not look like a TS stream, continuing" );
}
+ if( strcmp( p_demux->psz_demux, "ts2" ) )
+ {
+ /* Check next 3 sync points */
+ i_peek = 188*3 + 1 + i_sync;
+ 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+ 188] != 0x47 || p_peek[i_sync+2*188] != 0x47 ||
+ p_peek[i_sync+3*188] != 0x47 )
+ {
+ msg_Warn( p_demux, "TS module discarded (lost sync)" );
+ return VLC_EGENERIC;
+ }
+ }
/* Fill p_demux field */
p_demux->pf_demux = Demux;
pid->b_seen = VLC_FALSE;
pid->b_valid = VLC_FALSE;
}
+ 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];
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++ = '\0';
+ 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 / 188;
+ if( p_sys->i_ts_read <= 0 )
+ {
+ p_sys->i_ts_read = 1500 / 188;
+ }
+ p_sys->buffer = malloc( 188 * 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 );
{
ts_pid_t *pmt = &p_sys->pid[i_pid];
- msg_Dbg( p_demux, "Extra pmt specified (pid=0x%x)", i_pid );
+ msg_Dbg( p_demux, "extra pmt specified (pid=0x%x)", i_pid );
PIDInit( pmt, VLC_TRUE, NULL );
/* FIXME we should also ask for a number */
pmt->psi->handle = dvbpsi_AttachPMT( 1, (dvbpsi_pmt_callback)PMTCallBack, p_demux );
{
pmt->psi->i_pid_pcr = i_pid;
}
- ESFillFormat( &pid->es->fmt, i_stream_type);
+ 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=0x%x type=0x%x 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 );
}
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 = strtoll( 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 );
+ }
+
+
return VLC_SUCCESS;
}
}
}
+ 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 );
free( p_sys );
}
-
/*****************************************************************************
* Demux:
*****************************************************************************/
int i_pkt;
/* We read at most 100 TS packet or until a frame is completed */
- for( i_pkt = 0; i_pkt < 100; i_pkt++ )
+ for( i_pkt = 0; i_pkt < p_sys->i_ts_read; i_pkt++ )
{
vlc_bool_t b_frame = VLC_FALSE;
block_t *p_pkt;
block_Release( p_pkt );
/* Resynch */
- for( ;; )
+ while( !p_demux->b_die )
{
uint8_t *p_peek;
int i_peek = stream_Peek( p_demux->s, &p_peek, 1880 );
}
}
+ if( p_sys->b_udp_out )
+ {
+ memcpy( &p_sys->buffer[i_pkt*188], p_pkt->p_buffer, 188 );
+ }
+
/* Parse the TS packet */
p_pid = &p_sys->pid[PIDGet( p_pkt )];
dvbpsi_PushPacket( p_pid->psi->handle, p_pkt->p_buffer );
block_Release( p_pkt );
}
- else
+ else if( !p_sys->b_udp_out )
{
b_frame = GatherPES( p_demux, p_pid, p_pkt );
}
+ else
+ {
+ block_Release( p_pkt );
+ }
}
else
{
{
msg_Dbg( p_demux, "pid[0x%x] 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( p_sys->b_udp_out )
+ {
+ /* Send the complete block */
+ net_Write( p_demux, p_sys->fd, p_sys->buffer, p_sys->i_ts_read * 188 );
+ }
+
return 1;
}
*****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
- demux_sys_t *p_sys = p_demux->p_sys;
+ /* demux_sys_t *p_sys = p_demux->p_sys; */
double f, *pf;
- int64_t i64, *pi64;
+ int64_t i64;
switch( i_query )
{
*pi64 = p_sys->i_time;
return VLC_SUCCESS;
-#if 0
case DEMUX_GET_LENGTH:
pi64 = (int64_t*)va_arg( args, int64_t * );
if( p_sys->i_mux_rate > 0 )
}
*pi64 = 0;
return VLC_EGENERIC;
-
- case DEMUX_SET_TIME:
#endif
case DEMUX_GET_FPS:
- pf = (double*)va_arg( args, double * );
- *pf = (double)1000000.0 / (double)p_sys->i_pcr_inc;
- return VLC_SUCCESS;
-#endif
+ case DEMUX_SET_TIME:
default:
return VLC_EGENERIC;
}
}
}
+static void PIDClean( es_out_t *out, ts_pid_t *pid )
+{
+ if( pid->psi )
+ {
+ if( pid->psi->handle )
+ {
+ dvbpsi_DetachPMT( pid->psi->handle );
+ }
+ if( pid->psi->iod )
+ {
+ IODFree( pid->psi->iod );
+ }
+ 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 );
+ }
+ free( pid->es );
+ }
+ pid->b_valid = VLC_FALSE;
+}
+
/****************************************************************************
* gathering stuff
****************************************************************************/
if( header[0] != 0 || header[1] != 0 || header[2] != 1 )
{
- msg_Err( p_demux, "invalid header [0x%x:%x:%x:%x]", header[0], header[1],header[2],header[3] );
+ msg_Warn( p_demux, "invalid header [0x%x:%x:%x:%x]", header[0], header[1],header[2],header[3] );
block_ChainRelease( p_pes );
return;
}
{
p_pes->i_pts = i_pts * 100 / 9;
}
- es_out_Send( p_demux->out, pid->es->id, p_pes );
+
+ /* For mpeg4/mscodec we first gather the packet -> will make ffmpeg happier */
+ es_out_Send( p_demux->out, pid->es->id, block_ChainGather( p_pes ) );
}
else
{
msg_Warn( p_demux, "empty pes" );
}
-};
+}
-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 *pid, block_t *p_bk )
{
- uint8_t *p = p_bk->p_buffer;
+ demux_sys_t *p_sys = p_demux->p_sys;
+ const uint8_t *p = p_bk->p_buffer;
+
+ if( ( p[3]&0x20 ) && /* adaptation */
+ ( p[5]&0x10 ) &&
+ ( p[4] >= 7 ) )
+ {
+ int i;
+ mtime_t i_pcr; /* 33 bits */
+
+ i_pcr = ( (mtime_t)p[6] << 25 ) |
+ ( (mtime_t)p[7] << 17 ) |
+ ( (mtime_t)p[8] << 9 ) |
+ ( (mtime_t)p[9] << 1 ) |
+ ( (mtime_t)p[10] >> 7 );
- vlc_bool_t b_unit_start= p[1]&0x40;
- vlc_bool_t b_adaptation= p[3]&0x20;
- vlc_bool_t b_payload = p[3]&0x10;
- int i_cc = p[3]&0x0f; /* continuity counter */
+ /* Search program and set the PCR */
+ for( i = 0; i < p_sys->i_pmt; i++ )
+ {
+ if( pid->i_pid == p_sys->pmt[i]->psi->i_pid_pcr )
+ {
+ es_out_Control( p_demux->out, ES_OUT_SET_GROUP_PCR,
+ (int)p_sys->pmt[i]->psi->i_number,
+ (int64_t)(i_pcr * 100 / 9) );
+ }
+ }
+ }
+}
+
+static vlc_bool_t GatherPES( demux_t *p_demux, ts_pid_t *pid, block_t *p_bk )
+{
+ const uint8_t *p = p_bk->p_buffer;
+ 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 */
/* transport_scrambling_control is ignored */
int i_skip = 0;
msg_Dbg( p_demux, "transport_error_indicator set (pid=0x%x)", pid->i_pid );
}
+ if( p_demux->p_sys->csa )
+ {
+ csa_Decrypt( p_demux->p_sys->csa, p_bk->p_buffer );
+ }
+
if( !b_adaptation )
{
i_skip = 4;
{
if( pid->i_cc == 0xff )
{
- msg_Warn( p_demux, "first packet for pid=0x%x c=0x%x", pid->i_pid, i_cc );
+ msg_Warn( p_demux, "first packet for pid=0x%x cc=0x%x", pid->i_pid, i_cc );
pid->i_cc = i_cc;
}
else if( i_diff != 0 )
if( pid->es->p_pes )
{
- block_ChainRelease( pid->es->p_pes );
- pid->es->p_pes = NULL;
+ pid->es->p_pes->i_flags |= BLOCK_FLAG_DISCONTINUITY;
}
}
}
- if( b_adaptation &&
- (p[5] & 0x10) && p[4]>=7 && pid->p_owner && pid->p_owner->i_pid_pcr == pid->i_pid )
- {
- mtime_t i_pcr; /* 33 bits */
+ PCRHandle( p_demux, pid, p_bk );
- i_pcr = ( (mtime_t)p[6] << 25 ) |
- ( (mtime_t)p[7] << 17 ) |
- ( (mtime_t)p[8] << 9 ) |
- ( (mtime_t)p[9] << 1 ) |
- ( (mtime_t)p[10] >> 7 );
-
- es_out_Control( p_demux->out, ES_OUT_SET_GROUP_PCR, (int)pid->p_owner->i_number, (int64_t)(i_pcr * 100 / 9) );
- }
-
-
- if( i_skip >= 188 || pid->es->id == NULL )
+ if( i_skip >= 188 || pid->es->id == NULL || p_demux->p_sys->b_udp_out )
{
block_Release( p_bk );
}
else
{
+ const vlc_bool_t b_unit_start= p[1]&0x40;
+
/* we have to gather it */
p_bk->p_buffer += i_skip;
p_bk->i_buffer -= i_skip;
return i_ret;
}
-static char *LanguageNameISO639( char *psz_code )
+static int PIDFillFormat( ts_pid_t *pid, int i_stream_type )
{
- const iso639_lang_t *pl;
+ es_format_t *fmt = &pid->es->fmt;
- pl = GetLang_2B( psz_code );
- if( !strcmp( pl->psz_iso639_1, "??" ) )
- {
- pl = GetLang_2T( psz_code );
- }
-
- if( !strcmp( pl->psz_iso639_1, "??" ) )
- {
- return strdup( psz_code );
- }
- else
- {
- if( *pl->psz_native_name )
- {
- return strdup( pl->psz_native_name );
- }
- return strdup( pl->psz_eng_name );
- }
-}
-
-static int ESFillFormat( es_format_t *fmt, int i_stream_type )
-{
switch( i_stream_type )
{
case 0x01: /* MPEG-1 video */
break;
}
+ /* PES packets usually contain truncated frames */
+ fmt->b_packetized = VLC_FALSE;
+
return fmt->i_cat == UNKNOWN_ES ? VLC_EGENERIC : VLC_SUCCESS ;
}
/*****************************************************************************
- * MP4 specific functions
+ * MP4 specific functions (IOD parser)
*****************************************************************************/
static int IODDescriptorLength( int *pi_data, uint8_t **pp_data )
{
{
if( *pi_data > 0 )
{
- int i_b = **pp_data;
+ const int i_b = **pp_data;
(*pp_data)++;
(*pi_data)--;
return( i_b );
}
- else
- {
- return( 0 );
- }
+ return( 0 );
}
-
-static int MP4_GetWord( int *pi_data, uint8_t **pp_data )
+static int IODGetWord( int *pi_data, uint8_t **pp_data )
{
- int i1, i2;
- i1 = IODGetByte( pi_data, pp_data );
- i2 = IODGetByte( pi_data, pp_data );
+ const int i1 = IODGetByte( pi_data, pp_data );
+ const int i2 = IODGetByte( pi_data, pp_data );
return( ( i1 << 8 ) | i2 );
}
static int IODGet3Bytes( int *pi_data, uint8_t **pp_data )
{
- int i1, i2, i3;
- i1 = IODGetByte( pi_data, pp_data );
- i2 = IODGetByte( pi_data, pp_data );
- i3 = IODGetByte( pi_data, pp_data );
+ const int i1 = IODGetByte( pi_data, pp_data );
+ const int i2 = IODGetByte( pi_data, pp_data );
+ const int i3 = IODGetByte( pi_data, pp_data );
+
return( ( i1 << 16 ) | ( i2 << 8) | i3 );
}
-static uint32_t IODGetWord( int *pi_data, uint8_t **pp_data )
+static uint32_t IODGetDWord( int *pi_data, uint8_t **pp_data )
{
- uint32_t i1, i2;
- i1 = MP4_GetWord( pi_data, pp_data );
- i2 = MP4_GetWord( pi_data, pp_data );
+ const uint32_t i1 = IODGetWord( pi_data, pp_data );
+ const uint32_t i2 = IODGetWord( pi_data, pp_data );
return( ( i1 << 16 ) | i2 );
}
fprintf( stderr, "\n* - ES_Descriptor length:%d", i_length );
es_descr.b_ok = 1;
- es_descr.i_es_id = MP4_GetWord( &i_data, &p_data );
+ es_descr.i_es_id = IODGetWord( &i_data, &p_data );
i_flags = IODGetByte( &i_data, &p_data );
es_descr.b_streamDependenceFlag = ( i_flags >> 7 )&0x01;
b_url = ( i_flags >> 6 )&0x01;
if( es_descr.b_streamDependenceFlag )
{
- es_descr.i_dependOn_es_id = MP4_GetWord( &i_data, &p_data );
+ es_descr.i_dependOn_es_id = IODGetWord( &i_data, &p_data );
fprintf( stderr, "\n* * dependOn_es_id:%d", es_descr.i_dependOn_es_id );
}
if( es_descr.b_OCRStreamFlag )
{
- es_descr.i_OCR_es_id = MP4_GetWord( &i_data, &p_data );
+ es_descr.i_OCR_es_id = IODGetWord( &i_data, &p_data );
fprintf( stderr, "\n* * OCR_es_id:%d", es_descr.i_OCR_es_id );
}
dec_descr.i_streamType = i_flags >> 2;
dec_descr.b_upStream = ( i_flags >> 1 )&0x01;
dec_descr.i_bufferSizeDB = IODGet3Bytes( &i_data, &p_data );
- dec_descr.i_maxBitrate = IODGetWord( &i_data, &p_data );
- dec_descr.i_avgBitrate = IODGetWord( &i_data, &p_data );
+ dec_descr.i_maxBitrate = IODGetDWord( &i_data, &p_data );
+ dec_descr.i_avgBitrate = IODGetDWord( &i_data, &p_data );
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 );
if( pid->b_valid && pid->p_owner == pmt->psi && pid->psi == NULL )
{
- pid->b_valid = VLC_FALSE;
- if( pid->es->id )
- {
- es_out_Del( p_demux->out, pid->es->id );
- }
- if( pid->es->p_pes )
- {
- block_ChainRelease( pid->es->p_pes );
- }
+ PIDClean( p_demux->out, pid );
}
}
if( pmt->psi->iod )
pmt->psi->iod = NULL;
}
- msg_Dbg( p_demux, "New PMT program number=%d version=%d pid_pcr=0x%x", p_pmt->i_program_number, p_pmt->i_version, p_pmt->i_pcr_pid );
+ msg_Dbg( p_demux, "new PMT program number=%d version=%d pid_pcr=0x%x", p_pmt->i_program_number, p_pmt->i_version, p_pmt->i_pcr_pid );
pmt->psi->i_pid_pcr = p_pmt->i_pcr_pid;
pmt->psi->i_version = p_pmt->i_version;
if( p_dr->i_tag == 0x1d )
{
/* We have found an IOD descriptor */
- msg_Warn( p_demux, "found IOD descriptor" );
+ msg_Warn( p_demux, " * descriptor : IOD (0x1d)" );
pmt->psi->iod = IODNew( p_dr->i_length, p_dr->p_data );
}
+ else
+ {
+ msg_Dbg( p_demux, " * descriptor : unknown (0x%x)", p_dr->i_tag );
+ }
}
for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
}
PIDInit( pid, VLC_FALSE, pmt->psi );
- ESFillFormat( &pid->es->fmt, p_es->i_type );
+ PIDFillFormat( pid, p_es->i_type );
if( p_es->i_type == 0x10 || p_es->i_type == 0x11 )
{
default:
pid->es->fmt.i_cat = UNKNOWN_ES;
+ break;
}
}
else if( dcd->i_streamType == 0x05 ) /* AudioStream */
break;
default:
pid->es->fmt.i_cat = UNKNOWN_ES;
+ break;
}
}
else
for( p_dr = p_es->p_first_descriptor; p_dr != NULL; p_dr = p_dr->p_next )
{
+ msg_Dbg( p_demux, " * es pid=0x%x type=0x%x dr->i_tag=0x%x",
+ p_es->i_pid, p_es->i_type, p_dr->i_tag );
+
if( p_dr->i_tag == 0x6a )
{
pid->es->fmt.i_cat = AUDIO_ES;
if( p_dr && p_dr->i_length >= 8 )
{
+ pid->es->fmt.i_cat = VIDEO_ES;
pid->es->fmt.i_codec = VLC_FOURCC( p_dr->p_data[0], p_dr->p_data[1],
p_dr->p_data[2], p_dr->p_data[3] );
+ pid->es->fmt.video.i_width = ( p_dr->p_data[4] << 8 )|p_dr->p_data[5];
+ pid->es->fmt.video.i_height= ( p_dr->p_data[6] << 8 )|p_dr->p_data[7];
pid->es->fmt.i_extra = (p_dr->p_data[8] << 8) | p_dr->p_data[9];
if( pid->es->fmt.i_extra > 0 )
{
msg_Warn( p_demux, "private MSCODEC (vlc) without bih private descriptor" );
}
+ /* For such stream we will gather them ourself and don't launch a packetize,
+ * Yes it's ugly but it's the only way to make DIV3 working */
+ pid->es->fmt.b_packetized = VLC_TRUE;
}
if( pid->es->fmt.i_cat == AUDIO_ES || pid->es->fmt.i_cat == SPU_ES )
if( p_dr )
{
dvbpsi_iso639_dr_t *p_decoded = dvbpsi_DecodeISO639Dr( p_dr );
- pid->es->fmt.psz_language =
- LanguageNameISO639( (char*)&p_decoded->i_iso_639_code );
+
+ if( p_decoded )
+ {
+ pid->es->fmt.psz_language = malloc( 4 );
+ memcpy( pid->es->fmt.psz_language, p_decoded->i_iso_639_code, 3 );
+ pid->es->fmt.psz_language[3] = 0;
+ }
}
}
{
msg_Dbg( p_demux, " * es pid=0x%x type=0x%x *unknown*", p_es->i_pid, p_es->i_type );
}
- else
+ else if( !p_sys->b_udp_out )
{
msg_Dbg( p_demux, " * es pid=0x%x type=0x%x fcc=%4.4s", p_es->i_pid, p_es->i_type, (char*)&pid->es->fmt.i_codec );
+ if( p_sys->b_es_id_pid )
+ {
+ pid->es->fmt.i_id = p_es->i_pid;
+ }
pid->es->id = es_out_Add( p_demux->out, &pid->es->fmt );
}
}
msg_Dbg( p_demux, "PATCallBack called" );
- if( pat->psi->i_version != -1 && ( !p_pat->b_current_next || p_pat->i_version == pat->psi->i_version ) )
+ if( pat->psi->i_version != -1 &&
+ ( !p_pat->b_current_next || p_pat->i_version == pat->psi->i_version ) )
{
dvbpsi_DeletePAT( p_pat );
return;
}
- msg_Dbg( p_demux, "New PAT ts_id=0x%x version=%d current_next=%d", p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
+ msg_Dbg( p_demux, "new PAT ts_id=0x%x version=%d current_next=%d",
+ p_pat->i_ts_id, p_pat->i_version, p_pat->b_current_next );
/* Clean old */
- for( i = 2; i < 8192; i++ )
+ if( p_sys->i_pmt > 0 )
{
- ts_pid_t *pid = &p_sys->pid[i];
+ int i_pmt_rm = 0;
+ ts_pid_t **pmt_rm = NULL;
- if( pid->b_valid )
+ /* Search pmt to be deleted */
+ for( i = 0; i < p_sys->i_pmt; i++ )
{
- if( pid->psi )
+ ts_pid_t *pmt = p_sys->pmt[i];
+ vlc_bool_t b_keep = VLC_FALSE;
+
+ for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
{
- if( pid->p_owner == pat->psi )
+ if( p_program->i_pid == pmt->i_pid && p_program->i_number == pmt->psi->i_number )
{
- dvbpsi_DetachPMT( pid->psi->handle );
- if( pid->psi->iod )
- {
- IODFree( pid->psi->iod );
- pid->psi->iod = NULL;
- }
- pid->b_valid = VLC_FALSE;
- TAB_REMOVE( p_sys->i_pmt, p_sys->pmt, pid );
+ b_keep = VLC_TRUE;
+ break;
}
}
- else if( pid->p_owner && pid->p_owner->i_number != 0 && pid->es->id )
+ if( !b_keep )
{
- /* We only remove es that aren't defined by extra pmt */
- es_out_Del( p_demux->out, pid->es->id );
+ TAB_APPEND( i_pmt_rm, pmt_rm, pmt );
+ }
+ }
- pid->b_valid = VLC_FALSE;
+ /* Delete all ES attached to thoses PMT */
+ for( i = 2; i < 8192; i++ )
+ {
+ ts_pid_t *pid = &p_sys->pid[i];
+ if( pid->b_valid && !pid->psi )
+ {
+ for( i = 0; i < i_pmt_rm; i++ )
+ {
+ if( pid->p_owner->i_pid_pcr == pmt_rm[i]->i_pid && pid->es->id )
+ {
+ /* We only remove es that aren't defined by extra pmt */
+ PIDClean( p_demux->out, pid );
+ break;
+ }
+ }
}
}
+
+ /* Delete PMT pid */
+ for( i = 0; i < i_pmt_rm; i++ )
+ {
+ 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( pmt_rm )
+ {
+ free( pmt_rm );
+ }
}
/* now create programs */
- for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next )
+ for( p_program = p_pat->p_first_program; p_program != NULL;
+ p_program = p_program->p_next )
{
- msg_Dbg( p_demux, " * number=%d pid=0x%x", p_program->i_number, p_program->i_pid );
+ msg_Dbg( p_demux, " * number=%d pid=0x%x", p_program->i_number,
+ p_program->i_pid );
if( p_program->i_number != 0 )
{
ts_pid_t *pmt = &p_sys->pid[p_program->i_pid];
- PIDInit( pmt, VLC_TRUE, pat->psi );
- pmt->psi->handle = dvbpsi_AttachPMT( p_program->i_number, (dvbpsi_pmt_callback)PMTCallBack, p_demux );
- pmt->psi->i_number = p_program->i_number;
+ if( !pmt->b_valid )
+ {
+ PIDInit( pmt, VLC_TRUE, pat->psi );
+ pmt->psi->handle =
+ dvbpsi_AttachPMT( p_program->i_number,
+ (dvbpsi_pmt_callback)PMTCallBack, p_demux );
+ pmt->psi->i_number = p_program->i_number;
- TAB_APPEND( p_sys->i_pmt, p_sys->pmt, pmt );
+ TAB_APPEND( p_sys->i_pmt, p_sys->pmt, pmt );
+ }
}
}
pat->psi->i_version = p_pat->i_version;
dvbpsi_DeletePAT( p_pat );
}
-