@ -23,7 +23,11 @@
//#define DEBUG_SI
/* 1.0 second at 24Mbit/s */
# define MAX_SCAN_PACKETS 16000
# define MAX_SCAN_PACKETS 32000
/* maximum size in which we look for synchronisation if
synchronisation is lost */
# define MAX_RESYNC_SIZE 4096
static int add_pes_stream ( AVFormatContext * s , int pid ) ;
@ -32,7 +36,6 @@ enum MpegTSFilterType {
MPEGTS_SECTION ,
} ;
/* XXX: suppress 'pkt' parameter */
typedef void PESCallback ( void * opaque , const uint8_t * buf , int len , int is_start ) ;
typedef struct MpegTSPESFilter {
@ -432,7 +435,7 @@ static void pat_cb(void *opaque, const uint8_t *section, int section_len)
if ( sid = = 0x0000 ) {
/* NIT info */
} else {
if ( ts - > req_sid = = sid | | ts - > req_sid < 0 ) {
if ( ts - > req_sid = = sid ) {
ts - > pmt_filter = mpegts_open_section_filter ( ts , pmt_pid ,
pmt_cb , ts , 1 ) ;
goto found ;
@ -447,6 +450,59 @@ static void pat_cb(void *opaque, const uint8_t *section, int section_len)
ts - > pat_filter = NULL ;
}
/* add all services found in the PAT */
static void pat_scan_cb ( void * opaque , const uint8_t * section , int section_len )
{
MpegTSContext * ts = opaque ;
SectionHeader h1 , * h = & h1 ;
const uint8_t * p , * p_end ;
int sid , pmt_pid ;
char * provider_name , * name ;
char buf [ 256 ] ;
# ifdef DEBUG_SI
printf ( " PAT: \n " ) ;
av_hex_dump ( ( uint8_t * ) section , section_len ) ;
# endif
p_end = section + section_len - 4 ;
p = section ;
if ( parse_section_header ( h , & p , p_end ) < 0 )
return ;
if ( h - > tid ! = PAT_TID )
return ;
for ( ; ; ) {
sid = get16 ( & p , p_end ) ;
if ( sid < 0 )
break ;
pmt_pid = get16 ( & p , p_end ) & 0x1fff ;
if ( pmt_pid < 0 )
break ;
# ifdef DEBUG_SI
printf ( " sid=0x%x pid=0x%x \n " , sid , pmt_pid ) ;
# endif
if ( sid = = 0x0000 ) {
/* NIT info */
} else {
/* add the service with a dummy name */
snprintf ( buf , sizeof ( buf ) , " Service %x \n " , sid ) ;
name = av_strdup ( buf ) ;
provider_name = av_strdup ( " " ) ;
if ( name & & provider_name ) {
new_service ( ts , sid , provider_name , name ) ;
} else {
av_freep ( & name ) ;
av_freep ( & provider_name ) ;
}
}
}
ts - > stop_parse = 1 ;
/* remove filter */
mpegts_close_filter ( ts , ts - > pat_filter ) ;
ts - > pat_filter = NULL ;
}
void mpegts_set_service ( MpegTSContext * ts , int sid ,
SetServiceCallback * set_service_cb , void * opaque )
{
@ -533,13 +589,20 @@ static void sdt_cb(void *opaque, const uint8_t *section, int section_len)
ts - > sdt_filter = NULL ;
}
/* scan services an a transport stream by looking at the sdt */
/* scan services in a transport stream by looking at the SDT */
void mpegts_scan_sdt ( MpegTSContext * ts )
{
ts - > sdt_filter = mpegts_open_section_filter ( ts , SDT_PID ,
sdt_cb , ts , 1 ) ;
}
/* scan services in a transport stream by looking at the PAT (better
than nothing ! ) */
void mpegts_scan_pat ( MpegTSContext * ts )
{
ts - > pat_filter = mpegts_open_section_filter ( ts , PAT_PID ,
pat_scan_cb , ts , 1 ) ;
}
/* TS stream handling */
@ -803,13 +866,32 @@ static void handle_packet(AVFormatContext *s, uint8_t *packet)
}
}
/* XXX: try to find a better synchro over several packets (use
get_packet_size ( ) ? ) */
static int mpegts_resync ( AVFormatContext * s )
{
ByteIOContext * pb = & s - > pb ;
int c , i ;
for ( i = 0 ; i < MAX_RESYNC_SIZE ; i + + ) {
c = url_fgetc ( pb ) ;
if ( c < 0 )
return - 1 ;
if ( c = = 0x47 ) {
url_fseek ( pb , - 1 , SEEK_CUR ) ;
return 0 ;
}
}
/* no sync found */
return - 1 ;
}
static int handle_packets ( AVFormatContext * s , int nb_packets )
{
MpegTSContext * ts = s - > priv_data ;
ByteIOContext * pb = & s - > pb ;
uint8_t packet [ TS_FEC_PACKET_SIZE ] ;
int packet_num , len ;
int i , found = 0 ;
int64_t pos ;
ts - > stop_parse = 0 ;
@ -825,26 +907,13 @@ static int handle_packets(AVFormatContext *s, int nb_packets)
if ( len ! = ts - > raw_packet_size )
return AVERROR_IO ;
/* check paquet sync byte */
if ( packet [ 0 ] ! = 0x47 )
{
//printf("bad packet: 0x%x\n", packet[0]);
found = 0 ;
for ( i = 0 ; i < ts - > raw_packet_size ; i + + )
{
if ( packet [ i ] = = 0x47 )
{
found = 1 ;
//printf("packet start at: %d\n", i);
break ;
}
}
if ( found )
{
url_fseek ( pb , pos + i , SEEK_SET ) ;
continue ;
}
if ( packet [ 0 ] ! = 0x47 ) {
/* find a new packet start */
url_fseek ( pb , - ts - > raw_packet_size , SEEK_CUR ) ;
if ( mpegts_resync ( s ) < 0 )
return AVERROR_INVALIDDATA ;
else
continue ;
}
handle_packet ( s , packet ) ;
}
@ -853,11 +922,19 @@ static int handle_packets(AVFormatContext *s, int nb_packets)
static int mpegts_probe ( AVProbeData * p )
{
# if 1
int size ;
size = get_packet_size ( p - > buf , p - > buf_size ) ;
if ( size < 0 )
return 0 ;
return AVPROBE_SCORE_MAX - 1 ;
# else
/* only use the extension for safer guess */
if ( match_ext ( p - > filename , " ts " ) )
return AVPROBE_SCORE_MAX ;
else
return 0 ;
# endif
}
void set_service_cb ( void * opaque , int ret )
@ -873,7 +950,7 @@ static int mpegts_read_header(AVFormatContext *s,
MpegTSContext * ts = s - > priv_data ;
ByteIOContext * pb = & s - > pb ;
uint8_t buf [ 1024 ] ;
int len ;
int len , sid ;
int64_t pos ;
MpegTSService * service ;
@ -888,7 +965,6 @@ static int mpegts_read_header(AVFormatContext *s,
ts - > auto_guess = 0 ;
if ( ! ts - > auto_guess ) {
int sid = - 1 ;
ts - > set_service_ret = - 1 ;
/* first do a scaning to get all the services */
@ -897,15 +973,24 @@ static int mpegts_read_header(AVFormatContext *s,
handle_packets ( s , MAX_SCAN_PACKETS ) ;
if ( ts - > nb_services > 0 )
{
if ( ts - > nb_services < = 0 ) {
/* no SDT found, we try to look at the PAT */
url_fseek ( pb , pos , SEEK_SET ) ;
mpegts_scan_pat ( ts ) ;
handle_packets ( s , MAX_SCAN_PACKETS ) ;
}
if ( ts - > nb_services < = 0 )
return - 1 ;
/* tune to first service found */
service = ts - > services [ 0 ] ;
sid = service - > sid ;
# ifdef DEBUG_SI
printf ( " tuning to '%s' \n " , service - > name ) ;
# endif
}
/* now find the info for the first service if we found any,
otherwise try to filter all PATs */