2002-05-20 18:27:23 +02:00
/*
2006-10-23 10:57:54 +02:00
* MPEG2 transport stream ( aka DVB ) demuxer
2009-01-19 16:46:40 +01:00
* Copyright ( c ) 2002 - 2003 Fabrice Bellard
2002-05-20 18:27:23 +02:00
*
2006-10-07 17:30:46 +02:00
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
2002-05-26 00:34:32 +02:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 17:30:46 +02:00
* version 2.1 of the License , or ( at your option ) any later version .
2002-05-20 18:27:23 +02:00
*
2006-10-07 17:30:46 +02:00
* FFmpeg is distributed in the hope that it will be useful ,
2002-05-20 18:27:23 +02:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2002-05-26 00:34:32 +02:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
2002-05-20 18:27:23 +02:00
*
2002-05-26 00:34:32 +02:00
* You should have received a copy of the GNU Lesser General Public
2006-10-07 17:30:46 +02:00
* License along with FFmpeg ; if not , write to the Free Software
2006-01-12 23:43:26 +01:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2002-05-20 18:27:23 +02:00
*/
2008-05-09 13:56:36 +02:00
2012-10-31 08:53:18 +01:00
# include "libavutil/buffer.h"
2008-05-09 13:56:36 +02:00
# include "libavutil/crc.h"
2009-01-11 23:19:48 +01:00
# include "libavutil/intreadwrite.h"
2011-04-30 13:42:55 +02:00
# include "libavutil/log.h"
2011-05-22 12:46:29 +02:00
# include "libavutil/dict.h"
2011-07-05 00:42:31 +02:00
# include "libavutil/mathematics.h"
2011-04-30 13:42:55 +02:00
# include "libavutil/opt.h"
2011-10-21 17:37:08 +02:00
# include "libavutil/avassert.h"
2009-04-12 04:32:02 +02:00
# include "libavcodec/bytestream.h"
2011-10-11 23:49:59 +02:00
# include "libavcodec/get_bits.h"
2002-05-20 18:27:23 +02:00
# include "avformat.h"
2003-06-13 16:28:45 +02:00
# include "mpegts.h"
2008-12-04 00:04:30 +01:00
# include "internal.h"
2011-02-20 11:04:13 +01:00
# include "avio_internal.h"
2009-08-22 18:07:50 +02:00
# include "seek.h"
2011-01-30 16:24:00 +01:00
# include "mpeg.h"
2010-11-23 01:51:12 +01:00
# include "isom.h"
2002-05-20 18:27:23 +02:00
2003-07-15 15:21:39 +02:00
/* maximum size in which we look for synchronisation if
2014-03-17 18:03:07 +01:00
* synchronisation is lost */
2009-10-18 22:08:13 +02:00
# define MAX_RESYNC_SIZE 65536
2003-06-13 16:28:45 +02:00
2014-03-17 18:03:07 +01:00
# define MAX_PES_PAYLOAD 200 * 1024
2009-05-27 02:44:00 +02:00
2011-10-05 08:43:59 +02:00
# define MAX_MP4_DESCR_COUNT 16
2014-03-17 18:03:07 +01:00
# define MOD_UNLIKELY(modulus, dividend, divisor, prev_dividend) \
do { \
2014-03-01 13:01:43 +01:00
if ( ( prev_dividend ) = = 0 | | ( dividend ) - ( prev_dividend ) ! = ( divisor ) ) \
2014-03-17 18:03:07 +01:00
( modulus ) = ( dividend ) % ( divisor ) ; \
( prev_dividend ) = ( dividend ) ; \
2014-03-01 13:01:43 +01:00
} while ( 0 )
2003-06-13 16:28:45 +02:00
enum MpegTSFilterType {
MPEGTS_PES ,
MPEGTS_SECTION ,
2014-03-02 01:47:17 +01:00
MPEGTS_PCR ,
2002-05-20 18:27:23 +02:00
} ;
2007-07-08 15:42:51 +02:00
typedef struct MpegTSFilter MpegTSFilter ;
2014-03-17 18:03:07 +01:00
typedef int PESCallback ( MpegTSFilter * f , const uint8_t * buf , int len ,
2014-03-02 14:12:50 +01:00
int is_start , int64_t pos ) ;
2002-05-20 18:27:23 +02:00
2003-06-13 16:28:45 +02:00
typedef struct MpegTSPESFilter {
PESCallback * pes_cb ;
void * opaque ;
} MpegTSPESFilter ;
2014-03-17 18:03:07 +01:00
typedef void SectionCallback ( MpegTSFilter * f , const uint8_t * buf , int len ) ;
2003-06-13 16:28:45 +02:00
2014-03-17 18:03:07 +01:00
typedef void SetServiceCallback ( void * opaque , int ret ) ;
2003-06-13 16:28:45 +02:00
typedef struct MpegTSSectionFilter {
int section_index ;
int section_h_size ;
uint8_t * section_buf ;
2014-03-17 18:03:07 +01:00
unsigned int check_crc : 1 ;
unsigned int end_of_section_reached : 1 ;
2003-06-13 16:28:45 +02:00
SectionCallback * section_cb ;
void * opaque ;
} MpegTSSectionFilter ;
2007-07-08 15:42:51 +02:00
struct MpegTSFilter {
2002-05-20 18:27:23 +02:00
int pid ;
2011-10-10 21:50:00 +02:00
int es_id ;
2002-05-20 18:27:23 +02:00
int last_cc ; /* last cc code (-1 if first packet) */
2014-03-02 14:12:50 +01:00
int64_t last_pcr ;
2003-06-13 16:28:45 +02:00
enum MpegTSFilterType type ;
union {
MpegTSPESFilter pes_filter ;
MpegTSSectionFilter section_filter ;
} u ;
2007-07-08 15:42:51 +02:00
} ;
2003-06-13 16:28:45 +02:00
2007-09-25 22:58:37 +02:00
# define MAX_PIDS_PER_PROGRAM 64
2008-12-13 01:04:34 +01:00
struct Program {
2014-03-17 18:03:07 +01:00
unsigned int id ; // program id/service id
2007-09-25 22:58:37 +02:00
unsigned int nb_pids ;
unsigned int pids [ MAX_PIDS_PER_PROGRAM ] ;
2013-12-15 15:58:31 +01:00
/** have we found pmt for this program */
int pmt_found ;
2008-12-13 01:04:34 +01:00
} ;
2007-09-25 22:58:37 +02:00
2010-02-02 00:30:30 +01:00
struct MpegTSContext {
2011-04-30 13:42:55 +02:00
const AVClass * class ;
2003-06-13 16:28:45 +02:00
/* user data */
AVFormatContext * stream ;
2014-03-17 18:03:07 +01:00
/** raw packet size, including FEC if present */
2007-01-23 22:47:32 +01:00
int raw_packet_size ;
2008-04-23 23:16:25 +02:00
2013-08-18 16:35:38 +02:00
int size_stat [ 3 ] ;
int size_stat_count ;
# define SIZE_STAT_THRESHOLD 10
2013-08-06 19:56:20 +02:00
int64_t pos47_full ;
2008-04-23 23:16:25 +02:00
2014-03-17 18:03:07 +01:00
/** if true, all pids are analyzed to find streams */
2007-01-23 22:47:32 +01:00
int auto_guess ;
2003-06-13 16:28:45 +02:00
2014-03-17 18:03:07 +01:00
/** compute exact PCR for each transport stream packet */
2007-01-23 22:47:32 +01:00
int mpeg2ts_compute_pcr ;
2003-10-29 15:16:31 +01:00
2013-08-04 04:17:22 +02:00
/** fix dvb teletext pts */
int fix_teletext_pts ;
2014-03-17 18:03:07 +01:00
int64_t cur_pcr ; /**< used to estimate the exact PCR */
int pcr_incr ; /**< used to estimate the exact PCR */
2005-12-17 19:14:38 +01:00
2003-06-13 16:28:45 +02:00
/* data needed to handle file based ts */
2014-03-17 18:03:07 +01:00
/** stop parsing loop */
2007-01-23 22:47:32 +01:00
int stop_parse ;
2014-03-17 18:03:07 +01:00
/** packet containing Audio/Video data */
2007-01-23 22:47:32 +01:00
AVPacket * pkt ;
2014-03-17 18:03:07 +01:00
/** to detect seek */
2009-05-27 02:44:00 +02:00
int64_t last_pos ;
2003-06-13 16:28:45 +02:00
2014-07-11 16:42:52 +02:00
int skip_changes ;
2014-07-12 21:49:15 +02:00
int skip_clear ;
2014-07-11 16:42:52 +02:00
2014-08-25 12:11:32 +02:00
int resync_size ;
2003-06-13 16:28:45 +02:00
/******************************************/
/* private mpegts data */
/* scan context */
2014-03-17 18:03:07 +01:00
/** structure to keep track of Program->pids mapping */
2007-09-25 22:58:37 +02:00
unsigned int nb_prg ;
2008-12-13 01:04:34 +01:00
struct Program * prg ;
2005-12-17 19:14:38 +01:00
2012-10-08 05:25:27 +02:00
int8_t crc_validity [ NB_PID_MAX ] ;
2007-01-23 22:47:32 +01:00
/** filters for various streams specified by PMT + for the PAT and PMT */
2003-06-13 16:28:45 +02:00
MpegTSFilter * pids [ NB_PID_MAX ] ;
2012-11-13 15:21:41 +01:00
int current_pid ;
2010-02-02 00:30:30 +01:00
} ;
2002-05-20 18:27:23 +02:00
2014-08-25 12:11:32 +02:00
# define MPEGTS_OPTIONS \
2014-09-06 12:06:39 +02:00
{ " resync_size " , " Size limit for looking up a new synchronization. " , offsetof ( MpegTSContext , resync_size ) , AV_OPT_TYPE_INT , { . i64 = MAX_RESYNC_SIZE } , 0 , INT_MAX , AV_OPT_FLAG_DECODING_PARAM }
2014-08-25 12:11:32 +02:00
2014-09-03 12:44:14 +02:00
static const AVOption options [ ] = {
MPEGTS_OPTIONS ,
2013-08-04 04:17:22 +02:00
{ " fix_teletext_pts " , " Try to fix pts values of dvb teletext streams. " , offsetof ( MpegTSContext , fix_teletext_pts ) , AV_OPT_TYPE_INT ,
{ . i64 = 1 } , 0 , 1 , AV_OPT_FLAG_DECODING_PARAM } ,
2013-12-19 17:39:51 +01:00
{ " ts_packetsize " , " Output option carrying the raw packet size. " , offsetof ( MpegTSContext , raw_packet_size ) , AV_OPT_TYPE_INT ,
2014-02-20 02:10:05 +01:00
{ . i64 = 0 } , 0 , 0 , AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY } ,
2014-07-11 16:42:52 +02:00
{ " skip_changes " , " Skip changing / adding streams / programs. " , offsetof ( MpegTSContext , skip_changes ) , AV_OPT_TYPE_INT ,
{ . i64 = 0 } , 0 , 1 , 0 } ,
2014-07-12 21:49:15 +02:00
{ " skip_clear " , " Skip clearing programs. " , offsetof ( MpegTSContext , skip_clear ) , AV_OPT_TYPE_INT ,
{ . i64 = 0 } , 0 , 1 , 0 } ,
2013-08-04 04:17:22 +02:00
{ NULL } ,
} ;
static const AVClass mpegts_class = {
. class_name = " mpegts demuxer " ,
. item_name = av_default_item_name ,
2014-09-03 12:44:14 +02:00
. option = options ,
2011-04-30 13:42:55 +02:00
. version = LIBAVUTIL_VERSION_INT ,
} ;
2014-09-03 12:52:34 +02:00
static const AVOption raw_options [ ] = {
MPEGTS_OPTIONS ,
{ " compute_pcr " , " Compute exact PCR for each transport stream packet. " ,
offsetof ( MpegTSContext , mpeg2ts_compute_pcr ) , AV_OPT_TYPE_INT ,
{ . i64 = 0 } , 0 , 1 , AV_OPT_FLAG_DECODING_PARAM } ,
{ " ts_packetsize " , " Output option carrying the raw packet size. " ,
offsetof ( MpegTSContext , raw_packet_size ) , AV_OPT_TYPE_INT ,
{ . i64 = 0 } , 0 , 0 ,
AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY } ,
{ NULL } ,
} ;
static const AVClass mpegtsraw_class = {
. class_name = " mpegtsraw demuxer " ,
. item_name = av_default_item_name ,
. option = raw_options ,
. version = LIBAVUTIL_VERSION_INT ,
} ;
2007-06-04 16:11:54 +02:00
/* TS stream handling */
enum MpegTSState {
MPEGTS_HEADER = 0 ,
2009-06-02 09:53:44 +02:00
MPEGTS_PESHEADER ,
2007-06-04 16:11:54 +02:00
MPEGTS_PESHEADER_FILL ,
MPEGTS_PAYLOAD ,
MPEGTS_SKIP ,
} ;
/* enough for PES header + length */
2009-06-02 09:53:44 +02:00
# define PES_START_SIZE 6
# define PES_HEADER_SIZE 9
2007-06-04 16:11:54 +02:00
# define MAX_PES_HEADER_SIZE (9 + 255)
2010-01-13 23:52:22 +01:00
typedef struct PESContext {
2007-06-04 16:11:54 +02:00
int pid ;
2007-06-08 19:21:29 +02:00
int pcr_pid ; /**< if -1 then all packets containing PCR are considered */
2007-06-04 16:11:54 +02:00
int stream_type ;
MpegTSContext * ts ;
AVFormatContext * stream ;
AVStream * st ;
2009-10-05 10:38:39 +02:00
AVStream * sub_st ; /**< stream for the embedded AC3 stream in HDMV TrueHD */
2007-06-04 16:11:54 +02:00
enum MpegTSState state ;
/* used to get the format */
int data_index ;
2011-07-24 10:13:50 +02:00
int flags ; /**< copied to the AVPacket flags */
2007-06-04 16:11:54 +02:00
int total_size ;
int pes_header_size ;
2009-10-05 10:38:39 +02:00
int extended_stream_id ;
2007-06-04 16:11:54 +02:00
int64_t pts , dts ;
2009-02-28 19:35:53 +01:00
int64_t ts_packet_pos ; /**< position of first TS packet of this PES packet */
2007-06-04 16:11:54 +02:00
uint8_t header [ MAX_PES_HEADER_SIZE ] ;
2012-10-31 08:53:18 +01:00
AVBufferRef * buffer ;
2011-10-11 23:49:59 +02:00
SLConfigDescr sl ;
2010-01-13 23:52:22 +01:00
} PESContext ;
2007-06-04 16:11:54 +02:00
2011-01-25 23:03:28 +01:00
extern AVInputFormat ff_mpegts_demuxer ;
2007-09-17 01:00:44 +02:00
2013-12-15 15:58:31 +01:00
static struct Program * get_program ( MpegTSContext * ts , unsigned int programid )
{
int i ;
2014-03-18 13:16:56 +01:00
for ( i = 0 ; i < ts - > nb_prg ; i + + ) {
if ( ts - > prg [ i ] . id = = programid ) {
2013-12-15 15:58:31 +01:00
return & ts - > prg [ i ] ;
}
}
return NULL ;
}
2012-12-16 09:53:18 +01:00
static void clear_avprogram ( MpegTSContext * ts , unsigned int programid )
{
AVProgram * prg = NULL ;
int i ;
2014-07-11 16:42:52 +02:00
2014-03-18 13:16:56 +01:00
for ( i = 0 ; i < ts - > stream - > nb_programs ; i + + )
if ( ts - > stream - > programs [ i ] - > id = = programid ) {
2012-12-16 09:53:18 +01:00
prg = ts - > stream - > programs [ i ] ;
break ;
}
if ( ! prg )
return ;
prg - > nb_stream_indexes = 0 ;
}
2007-09-25 22:58:37 +02:00
static void clear_program ( MpegTSContext * ts , unsigned int programid )
{
int i ;
2012-12-16 09:53:18 +01:00
clear_avprogram ( ts , programid ) ;
2014-03-17 18:03:07 +01:00
for ( i = 0 ; i < ts - > nb_prg ; i + + )
2014-03-18 13:16:56 +01:00
if ( ts - > prg [ i ] . id = = programid ) {
2007-09-25 22:58:37 +02:00
ts - > prg [ i ] . nb_pids = 0 ;
2013-12-15 15:58:31 +01:00
ts - > prg [ i ] . pmt_found = 0 ;
}
2007-09-25 22:58:37 +02:00
}
static void clear_programs ( MpegTSContext * ts )
{
av_freep ( & ts - > prg ) ;
2014-03-17 18:03:07 +01:00
ts - > nb_prg = 0 ;
2007-09-25 22:58:37 +02:00
}
static void add_pat_entry ( MpegTSContext * ts , unsigned int programid )
{
2008-12-13 01:04:34 +01:00
struct Program * p ;
2013-09-10 11:57:35 +02:00
if ( av_reallocp_array ( & ts - > prg , ts - > nb_prg + 1 , sizeof ( * ts - > prg ) ) < 0 ) {
ts - > nb_prg = 0 ;
2007-09-25 22:58:37 +02:00
return ;
2013-09-10 11:57:35 +02:00
}
2007-09-25 22:58:37 +02:00
p = & ts - > prg [ ts - > nb_prg ] ;
p - > id = programid ;
p - > nb_pids = 0 ;
2013-12-15 15:58:31 +01:00
p - > pmt_found = 0 ;
2007-09-25 22:58:37 +02:00
ts - > nb_prg + + ;
}
2014-03-17 18:03:07 +01:00
static void add_pid_to_pmt ( MpegTSContext * ts , unsigned int programid ,
unsigned int pid )
2007-09-25 22:58:37 +02:00
{
2013-12-15 15:58:31 +01:00
struct Program * p = get_program ( ts , programid ) ;
2014-03-17 18:03:07 +01:00
if ( ! p )
2007-09-25 22:58:37 +02:00
return ;
2014-03-17 18:03:07 +01:00
if ( p - > nb_pids > = MAX_PIDS_PER_PROGRAM )
2007-09-25 22:58:37 +02:00
return ;
p - > pids [ p - > nb_pids + + ] = pid ;
}
2013-12-15 15:58:31 +01:00
static void set_pmt_found ( MpegTSContext * ts , unsigned int programid )
{
struct Program * p = get_program ( ts , programid ) ;
2014-03-18 13:16:56 +01:00
if ( ! p )
2013-12-15 15:58:31 +01:00
return ;
p - > pmt_found = 1 ;
}
2011-03-11 13:39:55 +01:00
static void set_pcr_pid ( AVFormatContext * s , unsigned int programid , unsigned int pid )
{
int i ;
2014-03-18 13:16:56 +01:00
for ( i = 0 ; i < s - > nb_programs ; i + + ) {
if ( s - > programs [ i ] - > id = = programid ) {
2011-03-11 13:39:55 +01:00
s - > programs [ i ] - > pcr_pid = pid ;
break ;
}
}
}
2007-09-25 22:58:37 +02:00
/**
2011-06-23 22:41:54 +02:00
* @ brief discard_pid ( ) decides if the pid is to be discarded according
2007-09-25 22:58:37 +02:00
* to caller ' s programs selection
2011-06-23 22:41:54 +02:00
* @ param ts : - TS context
* @ param pid : - pid
* @ return 1 if the pid is only comprised in programs that have . discard = AVDISCARD_ALL
2007-09-25 22:58:37 +02:00
* 0 otherwise
*/
static int discard_pid ( MpegTSContext * ts , unsigned int pid )
{
int i , j , k ;
int used = 0 , discarded = 0 ;
2008-12-13 01:04:34 +01:00
struct Program * p ;
2013-08-05 14:12:51 +02:00
/* If none of the programs have .discard=AVDISCARD_ALL then there's
2014-03-17 18:03:07 +01:00
* no way we have to discard this packet */
for ( k = 0 ; k < ts - > stream - > nb_programs ; k + + )
2013-08-05 14:12:51 +02:00
if ( ts - > stream - > programs [ k ] - > discard = = AVDISCARD_ALL )
break ;
if ( k = = ts - > stream - > nb_programs )
return 0 ;
2014-03-17 18:03:07 +01:00
for ( i = 0 ; i < ts - > nb_prg ; i + + ) {
2007-09-25 22:58:37 +02:00
p = & ts - > prg [ i ] ;
2014-03-17 18:03:07 +01:00
for ( j = 0 ; j < p - > nb_pids ; j + + ) {
if ( p - > pids [ j ] ! = pid )
2007-09-25 22:58:37 +02:00
continue ;
2014-03-17 18:03:07 +01:00
// is program with id p->id set to be discarded?
for ( k = 0 ; k < ts - > stream - > nb_programs ; k + + ) {
if ( ts - > stream - > programs [ k ] - > id = = p - > id ) {
if ( ts - > stream - > programs [ k ] - > discard = = AVDISCARD_ALL )
2007-09-25 22:58:37 +02:00
discarded + + ;
else
used + + ;
}
}
}
}
2008-05-06 11:16:36 +02:00
return ! used & & discarded ;
2007-09-25 22:58:37 +02:00
}
2007-01-23 22:47:32 +01:00
/**
2010-06-30 17:38:06 +02:00
* Assemble PES packets out of TS packets , and then call the " section_cb "
2007-01-23 22:47:32 +01:00
* function when they are complete .
*/
2014-07-08 09:54:15 +02:00
static void write_section_data ( MpegTSContext * ts , MpegTSFilter * tss1 ,
2003-06-13 16:28:45 +02:00
const uint8_t * buf , int buf_size , int is_start )
{
MpegTSSectionFilter * tss = & tss1 - > u . section_filter ;
int len ;
2005-12-17 19:14:38 +01:00
2003-06-13 16:28:45 +02:00
if ( is_start ) {
memcpy ( tss - > section_buf , buf , buf_size ) ;
tss - > section_index = buf_size ;
tss - > section_h_size = - 1 ;
tss - > end_of_section_reached = 0 ;
} else {
if ( tss - > end_of_section_reached )
return ;
len = 4096 - tss - > section_index ;
if ( buf_size < len )
len = buf_size ;
memcpy ( tss - > section_buf + tss - > section_index , buf , len ) ;
tss - > section_index + = len ;
}
/* compute section length if possible */
if ( tss - > section_h_size = = - 1 & & tss - > section_index > = 3 ) {
2007-07-06 11:32:34 +02:00
len = ( AV_RB16 ( tss - > section_buf + 1 ) & 0xfff ) + 3 ;
2003-06-13 16:28:45 +02:00
if ( len > 4096 )
return ;
tss - > section_h_size = len ;
}
2014-03-17 18:03:07 +01:00
if ( tss - > section_h_size ! = - 1 & &
tss - > section_index > = tss - > section_h_size ) {
2012-10-08 05:25:27 +02:00
int crc_valid = 1 ;
2003-06-13 16:28:45 +02:00
tss - > end_of_section_reached = 1 ;
2012-10-08 05:25:27 +02:00
2014-03-18 13:16:56 +01:00
if ( tss - > check_crc ) {
2012-10-08 05:25:27 +02:00
crc_valid = ! av_crc ( av_crc_get_table ( AV_CRC_32_IEEE ) , - 1 , tss - > section_buf , tss - > section_h_size ) ;
2014-03-18 13:16:56 +01:00
if ( crc_valid ) {
2012-10-08 05:25:27 +02:00
ts - > crc_validity [ tss1 - > pid ] = 100 ;
2014-03-18 13:16:56 +01:00
} else if ( ts - > crc_validity [ tss1 - > pid ] > - 10 ) {
2012-10-08 05:25:27 +02:00
ts - > crc_validity [ tss1 - > pid ] - - ;
} else
crc_valid = 2 ;
}
if ( crc_valid )
2007-06-04 15:57:00 +02:00
tss - > section_cb ( tss1 , tss - > section_buf , tss - > section_h_size ) ;
2003-06-13 16:28:45 +02:00
}
}
2014-03-02 14:28:06 +01:00
static MpegTSFilter * mpegts_open_filter ( MpegTSContext * ts , unsigned int pid ,
enum MpegTSFilterType type )
2003-06-13 16:28:45 +02:00
{
MpegTSFilter * filter ;
2005-12-17 19:14:38 +01:00
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " Filter: pid=0x%x \n " , pid ) ;
2009-04-12 05:08:46 +02:00
2003-06-13 16:28:45 +02:00
if ( pid > = NB_PID_MAX | | ts - > pids [ pid ] )
return NULL ;
filter = av_mallocz ( sizeof ( MpegTSFilter ) ) ;
2005-12-17 19:14:38 +01:00
if ( ! filter )
2003-06-13 16:28:45 +02:00
return NULL ;
ts - > pids [ pid ] = filter ;
2014-03-17 18:03:07 +01:00
2014-03-02 14:28:06 +01:00
filter - > type = type ;
2014-03-17 18:03:07 +01:00
filter - > pid = pid ;
filter - > es_id = - 1 ;
2003-06-13 16:28:45 +02:00
filter - > last_cc = - 1 ;
2014-03-02 14:12:50 +01:00
filter - > last_pcr = - 1 ;
2014-03-17 18:03:07 +01:00
2014-03-02 14:28:06 +01:00
return filter ;
}
static MpegTSFilter * mpegts_open_section_filter ( MpegTSContext * ts ,
unsigned int pid ,
SectionCallback * section_cb ,
void * opaque ,
int check_crc )
{
MpegTSFilter * filter ;
MpegTSSectionFilter * sec ;
if ( ! ( filter = mpegts_open_filter ( ts , pid , MPEGTS_SECTION ) ) )
return NULL ;
2003-06-13 16:28:45 +02:00
sec = & filter - > u . section_filter ;
2014-03-17 18:03:07 +01:00
sec - > section_cb = section_cb ;
sec - > opaque = opaque ;
2003-06-13 16:28:45 +02:00
sec - > section_buf = av_malloc ( MAX_SECTION_SIZE ) ;
2014-03-17 18:03:07 +01:00
sec - > check_crc = check_crc ;
2003-06-13 16:28:45 +02:00
if ( ! sec - > section_buf ) {
av_free ( filter ) ;
return NULL ;
}
return filter ;
}
2006-06-18 13:33:14 +02:00
static MpegTSFilter * mpegts_open_pes_filter ( MpegTSContext * ts , unsigned int pid ,
2014-03-17 18:03:07 +01:00
PESCallback * pes_cb ,
void * opaque )
2003-06-13 16:28:45 +02:00
{
MpegTSFilter * filter ;
MpegTSPESFilter * pes ;
2014-03-02 14:28:06 +01:00
if ( ! ( filter = mpegts_open_filter ( ts , pid , MPEGTS_PES ) ) )
2003-06-13 16:28:45 +02:00
return NULL ;
2014-03-17 18:03:07 +01:00
2003-06-13 16:28:45 +02:00
pes = & filter - > u . pes_filter ;
pes - > pes_cb = pes_cb ;
pes - > opaque = opaque ;
return filter ;
}
2014-03-02 01:47:17 +01:00
static MpegTSFilter * mpegts_open_pcr_filter ( MpegTSContext * ts , unsigned int pid )
{
return mpegts_open_filter ( ts , pid , MPEGTS_PCR ) ;
}
2006-06-18 13:33:14 +02:00
static void mpegts_close_filter ( MpegTSContext * ts , MpegTSFilter * filter )
2003-06-13 16:28:45 +02:00
{
int pid ;
pid = filter - > pid ;
if ( filter - > type = = MPEGTS_SECTION )
av_freep ( & filter - > u . section_filter . section_buf ) ;
2009-02-06 21:30:18 +01:00
else if ( filter - > type = = MPEGTS_PES ) {
2009-05-27 02:44:00 +02:00
PESContext * pes = filter - > u . pes_filter . opaque ;
2012-10-31 08:53:18 +01:00
av_buffer_unref ( & pes - > buffer ) ;
2009-02-06 21:30:18 +01:00
/* referenced private data will be freed later in
2011-12-11 10:38:28 +01:00
* avformat_close_input */
2009-02-06 21:30:18 +01:00
if ( ! ( ( PESContext * ) filter - > u . pes_filter . opaque ) - > st ) {
av_freep ( & filter - > u . pes_filter . opaque ) ;
}
}
2004-01-08 20:01:16 +01:00
2003-06-13 16:28:45 +02:00
av_free ( filter ) ;
ts - > pids [ pid ] = NULL ;
}
2014-03-17 18:03:07 +01:00
static int analyze ( const uint8_t * buf , int size , int packet_size , int * index )
{
2009-08-24 23:42:25 +02:00
int stat [ TS_MAX_PACKET_SIZE ] ;
2014-09-13 22:08:21 +02:00
int stat_all = 0 ;
2003-12-09 01:17:43 +01:00
int i ;
2014-03-17 18:03:07 +01:00
int best_score = 0 ;
2003-12-09 01:17:43 +01:00
2014-03-18 13:16:56 +01:00
memset ( stat , 0 , packet_size * sizeof ( * stat ) ) ;
2003-12-09 01:17:43 +01:00
2014-03-18 13:16:56 +01:00
for ( i = 0 ; i < size - 3 ; i + + ) {
if ( buf [ i ] = = 0x47 & & ! ( buf [ i + 1 ] & 0x80 ) & & buf [ i + 3 ] ! = 0x47 ) {
2013-11-09 16:09:26 +01:00
int x = i % packet_size ;
2003-12-09 01:17:43 +01:00
stat [ x ] + + ;
2014-09-13 22:08:21 +02:00
stat_all + + ;
2014-03-17 18:03:07 +01:00
if ( stat [ x ] > best_score ) {
best_score = stat [ x ] ;
if ( index )
* index = x ;
2003-12-09 01:17:43 +01:00
}
}
}
2014-09-13 22:08:21 +02:00
return best_score - FFMAX ( stat_all - 10 * best_score , 0 ) / 10 ;
2003-12-09 01:17:43 +01:00
}
2002-05-20 18:27:23 +02:00
/* autodetect fec presence. Must have at least 1024 bytes */
2003-06-13 16:28:45 +02:00
static int get_packet_size ( const uint8_t * buf , int size )
2002-05-20 18:27:23 +02:00
{
2006-01-02 21:13:24 +01:00
int score , fec_score , dvhs_score ;
2002-05-20 18:27:23 +02:00
if ( size < ( TS_FEC_PACKET_SIZE * 5 + 1 ) )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2005-12-17 19:14:38 +01:00
2014-03-17 18:03:07 +01:00
score = analyze ( buf , size , TS_PACKET_SIZE , NULL ) ;
dvhs_score = analyze ( buf , size , TS_DVHS_PACKET_SIZE , NULL ) ;
fec_score = analyze ( buf , size , TS_FEC_PACKET_SIZE , NULL ) ;
2012-08-21 12:40:41 +02:00
av_dlog ( NULL , " score: %d, dvhs_score: %d, fec_score: %d \n " ,
score , dvhs_score , fec_score ) ;
2005-12-17 19:14:38 +01:00
2014-03-17 18:03:07 +01:00
if ( score > fec_score & & score > dvhs_score )
return TS_PACKET_SIZE ;
else if ( dvhs_score > score & & dvhs_score > fec_score )
return TS_DVHS_PACKET_SIZE ;
else if ( score < fec_score & & dvhs_score < fec_score )
return TS_FEC_PACKET_SIZE ;
else
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2002-05-20 18:27:23 +02:00
}
2003-06-13 16:28:45 +02:00
typedef struct SectionHeader {
uint8_t tid ;
uint16_t id ;
uint8_t version ;
uint8_t sec_num ;
uint8_t last_sec_num ;
} SectionHeader ;
static inline int get8 ( const uint8_t * * pp , const uint8_t * p_end )
2002-05-20 18:27:23 +02:00
{
2003-06-13 16:28:45 +02:00
const uint8_t * p ;
int c ;
p = * pp ;
if ( p > = p_end )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2014-03-17 18:03:07 +01:00
c = * p + + ;
2003-06-13 16:28:45 +02:00
* pp = p ;
return c ;
2002-05-20 18:27:23 +02:00
}
2003-06-13 16:28:45 +02:00
static inline int get16 ( const uint8_t * * pp , const uint8_t * p_end )
{
const uint8_t * p ;
int c ;
p = * pp ;
if ( ( p + 1 ) > = p_end )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2014-03-17 18:03:07 +01:00
c = AV_RB16 ( p ) ;
p + = 2 ;
2003-06-13 16:28:45 +02:00
* pp = p ;
return c ;
}
2011-10-29 14:50:34 +02:00
/* read and allocate a DVB string preceded by its length */
2003-06-13 16:28:45 +02:00
static char * getstr8 ( const uint8_t * * pp , const uint8_t * p_end )
2002-05-20 18:27:23 +02:00
{
int len ;
2003-06-13 16:28:45 +02:00
const uint8_t * p ;
char * str ;
2002-05-20 18:27:23 +02:00
2014-03-17 18:03:07 +01:00
p = * pp ;
2003-06-13 16:28:45 +02:00
len = get8 ( & p , p_end ) ;
if ( len < 0 )
return NULL ;
if ( ( p + len ) > p_end )
return NULL ;
str = av_malloc ( len + 1 ) ;
if ( ! str )
return NULL ;
memcpy ( str , p , len ) ;
str [ len ] = ' \0 ' ;
2014-03-17 18:03:07 +01:00
p + = len ;
2003-06-13 16:28:45 +02:00
* pp = p ;
return str ;
}
2005-12-17 19:14:38 +01:00
static int parse_section_header ( SectionHeader * h ,
2003-06-13 16:28:45 +02:00
const uint8_t * * pp , const uint8_t * p_end )
{
int val ;
val = get8 ( pp , p_end ) ;
if ( val < 0 )
2014-03-17 18:03:08 +01:00
return val ;
2003-06-13 16:28:45 +02:00
h - > tid = val ;
* pp + = 2 ;
2014-03-17 18:03:07 +01:00
val = get16 ( pp , p_end ) ;
2003-06-13 16:28:45 +02:00
if ( val < 0 )
2014-03-17 18:03:08 +01:00
return val ;
2003-06-13 16:28:45 +02:00
h - > id = val ;
val = get8 ( pp , p_end ) ;
if ( val < 0 )
2014-03-17 18:03:08 +01:00
return val ;
2003-06-13 16:28:45 +02:00
h - > version = ( val > > 1 ) & 0x1f ;
val = get8 ( pp , p_end ) ;
if ( val < 0 )
2014-03-17 18:03:08 +01:00
return val ;
2003-06-13 16:28:45 +02:00
h - > sec_num = val ;
val = get8 ( pp , p_end ) ;
if ( val < 0 )
2014-03-17 18:03:08 +01:00
return val ;
2003-06-13 16:28:45 +02:00
h - > last_sec_num = val ;
2002-05-20 18:27:23 +02:00
return 0 ;
2003-06-13 16:28:45 +02:00
}
2009-05-31 05:12:25 +02:00
typedef struct {
uint32_t stream_type ;
2010-03-31 01:30:55 +02:00
enum AVMediaType codec_type ;
2012-08-05 11:11:04 +02:00
enum AVCodecID codec_id ;
2009-05-31 05:12:25 +02:00
} StreamType ;
static const StreamType ISO_types [ ] = {
2012-08-05 11:11:04 +02:00
{ 0x01 , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_MPEG2VIDEO } ,
{ 0x02 , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_MPEG2VIDEO } ,
2014-03-17 18:03:07 +01:00
{ 0x03 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_MP3 } ,
{ 0x04 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_MP3 } ,
{ 0x0f , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_AAC } ,
{ 0x10 , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_MPEG4 } ,
2011-08-30 10:35:29 +02:00
/* Makito encoder sets stream type 0x11 for AAC,
* so auto - detect LOAS / LATM instead of hardcoding it . */
2013-01-24 00:47:36 +01:00
# if !CONFIG_LOAS_DEMUXER
2014-03-17 18:03:07 +01:00
{ 0x11 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_AAC_LATM } , /* LATM syntax */
2013-01-24 00:47:36 +01:00
# endif
2014-03-17 18:03:07 +01:00
{ 0x1b , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_H264 } ,
{ 0x24 , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_HEVC } ,
{ 0x42 , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_CAVS } ,
{ 0xd1 , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_DIRAC } ,
{ 0xea , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_VC1 } ,
2009-05-31 05:12:25 +02:00
{ 0 } ,
} ;
static const StreamType HDMV_types [ ] = {
2014-03-17 18:03:07 +01:00
{ 0x80 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_PCM_BLURAY } ,
{ 0x81 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_AC3 } ,
{ 0x82 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } ,
{ 0x83 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_TRUEHD } ,
{ 0x84 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_EAC3 } ,
{ 0x85 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } , /* DTS HD */
{ 0x86 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } , /* DTS HD MASTER*/
2014-03-18 13:16:56 +01:00
{ 0xa1 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_EAC3 } , /* E-AC3 Secondary Audio */
{ 0xa2 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } , /* DTS Express Secondary Audio */
2012-08-05 11:11:04 +02:00
{ 0x90 , AVMEDIA_TYPE_SUBTITLE , AV_CODEC_ID_HDMV_PGS_SUBTITLE } ,
2009-05-31 05:12:25 +02:00
{ 0 } ,
} ;
/* ATSC ? */
static const StreamType MISC_types [ ] = {
2014-03-17 18:03:07 +01:00
{ 0x81 , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_AC3 } ,
{ 0x8a , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } ,
2009-05-31 05:12:25 +02:00
{ 0 } ,
} ;
static const StreamType REGD_types [ ] = {
2014-03-17 18:03:07 +01:00
{ MKTAG ( ' d ' , ' r ' , ' a ' , ' c ' ) , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_DIRAC } ,
{ MKTAG ( ' A ' , ' C ' , ' - ' , ' 3 ' ) , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_AC3 } ,
{ MKTAG ( ' B ' , ' S ' , ' S ' , ' D ' ) , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_S302M } ,
{ MKTAG ( ' D ' , ' T ' , ' S ' , ' 1 ' ) , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } ,
{ MKTAG ( ' D ' , ' T ' , ' S ' , ' 2 ' ) , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } ,
{ MKTAG ( ' D ' , ' T ' , ' S ' , ' 3 ' ) , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } ,
{ MKTAG ( ' H ' , ' E ' , ' V ' , ' C ' ) , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_HEVC } ,
2014-03-18 13:16:56 +01:00
{ MKTAG ( ' K ' , ' L ' , ' V ' , ' A ' ) , AVMEDIA_TYPE_DATA , AV_CODEC_ID_SMPTE_KLV } ,
2014-03-17 18:03:07 +01:00
{ MKTAG ( ' V ' , ' C ' , ' - ' , ' 1 ' ) , AVMEDIA_TYPE_VIDEO , AV_CODEC_ID_VC1 } ,
2009-05-31 05:12:25 +02:00
{ 0 } ,
} ;
2013-02-05 12:01:11 +01:00
static const StreamType METADATA_types [ ] = {
{ MKTAG ( ' K ' , ' L ' , ' V ' , ' A ' ) , AVMEDIA_TYPE_DATA , AV_CODEC_ID_SMPTE_KLV } ,
2013-12-30 08:50:46 +01:00
{ MKTAG ( ' I ' , ' D ' , ' 3 ' , ' ' ) , AVMEDIA_TYPE_DATA , AV_CODEC_ID_TIMED_ID3 } ,
2013-02-05 12:01:11 +01:00
{ 0 } ,
} ;
2009-05-31 05:40:36 +02:00
/* descriptor present */
static const StreamType DESC_types [ ] = {
2014-03-17 18:03:07 +01:00
{ 0x6a , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_AC3 } , /* AC-3 descriptor */
{ 0x7a , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_EAC3 } , /* E-AC-3 descriptor */
{ 0x7b , AVMEDIA_TYPE_AUDIO , AV_CODEC_ID_DTS } ,
2012-08-05 11:11:04 +02:00
{ 0x56 , AVMEDIA_TYPE_SUBTITLE , AV_CODEC_ID_DVB_TELETEXT } ,
{ 0x59 , AVMEDIA_TYPE_SUBTITLE , AV_CODEC_ID_DVB_SUBTITLE } , /* subtitling descriptor */
2009-06-20 08:09:30 +02:00
{ 0 } ,
2009-05-31 05:40:36 +02:00
} ;
2009-05-31 05:12:25 +02:00
static void mpegts_find_stream_type ( AVStream * st ,
2014-03-17 18:03:07 +01:00
uint32_t stream_type ,
const StreamType * types )
2009-05-31 05:12:25 +02:00
{
2012-12-03 17:34:38 +01:00
if ( avcodec_is_open ( st - > codec ) ) {
av_log ( NULL , AV_LOG_DEBUG , " cannot set stream info, codec is open \n " ) ;
return ;
}
2014-03-17 18:03:07 +01:00
for ( ; types - > stream_type ; types + + )
2009-05-31 05:12:25 +02:00
if ( stream_type = = types - > stream_type ) {
st - > codec - > codec_type = types - > codec_type ;
st - > codec - > codec_id = types - > codec_id ;
2011-04-05 18:27:15 +02:00
st - > request_probe = 0 ;
2009-05-31 05:12:25 +02:00
return ;
}
}
2009-11-08 04:17:08 +01:00
static int mpegts_set_stream_info ( AVStream * st , PESContext * pes ,
uint32_t stream_type , uint32_t prog_reg_desc )
2009-05-31 05:12:25 +02:00
{
2014-03-18 13:16:56 +01:00
int old_codec_type = st - > codec - > codec_type ;
2011-09-15 23:01:04 +02:00
int old_codec_id = st - > codec - > codec_id ;
2012-11-13 15:43:01 +01:00
2012-12-03 17:29:56 +01:00
if ( avcodec_is_open ( st - > codec ) ) {
2012-11-13 15:43:01 +01:00
av_log ( pes - > stream , AV_LOG_DEBUG , " cannot set stream info, codec is open \n " ) ;
return 0 ;
}
2011-11-29 19:28:15 +01:00
avpriv_set_pts_info ( st , 33 , 1 , 90000 ) ;
2014-03-17 18:03:07 +01:00
st - > priv_data = pes ;
2010-03-31 01:30:55 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_DATA ;
2012-08-05 11:11:04 +02:00
st - > codec - > codec_id = AV_CODEC_ID_NONE ;
2014-03-17 18:03:07 +01:00
st - > need_parsing = AVSTREAM_PARSE_FULL ;
pes - > st = st ;
2009-11-08 04:17:08 +01:00
pes - > stream_type = stream_type ;
2009-05-31 05:12:25 +02:00
2009-11-08 04:17:08 +01:00
av_log ( pes - > stream , AV_LOG_DEBUG ,
" stream=%d stream_type=%x pid=%x prog_reg_desc=%.4s \n " ,
2014-03-17 18:03:07 +01:00
st - > index , pes - > stream_type , pes - > pid , ( char * ) & prog_reg_desc ) ;
2009-05-31 05:12:25 +02:00
2009-05-31 06:10:15 +02:00
st - > codec - > codec_tag = pes - > stream_type ;
2009-05-31 05:45:45 +02:00
mpegts_find_stream_type ( st , pes - > stream_type , ISO_types ) ;
2011-11-08 10:30:37 +01:00
if ( ( prog_reg_desc = = AV_RL32 ( " HDMV " ) | |
prog_reg_desc = = AV_RL32 ( " HDPR " ) ) & &
2012-08-05 11:11:04 +02:00
st - > codec - > codec_id = = AV_CODEC_ID_NONE ) {
2009-05-31 05:45:45 +02:00
mpegts_find_stream_type ( st , pes - > stream_type , HDMV_types ) ;
2009-10-05 10:38:39 +02:00
if ( pes - > stream_type = = 0x83 ) {
// HDMV TrueHD streams also contain an AC3 coded version of the
// audio track - add a second stream for this
AVStream * sub_st ;
// priv_data cannot be shared between streams
PESContext * sub_pes = av_malloc ( sizeof ( * sub_pes ) ) ;
if ( ! sub_pes )
2009-11-08 04:17:08 +01:00
return AVERROR ( ENOMEM ) ;
2009-10-05 10:38:39 +02:00
memcpy ( sub_pes , pes , sizeof ( * sub_pes ) ) ;
2011-06-18 11:43:24 +02:00
sub_st = avformat_new_stream ( pes - > stream , NULL ) ;
2009-10-05 10:38:39 +02:00
if ( ! sub_st ) {
av_free ( sub_pes ) ;
2009-11-08 04:17:08 +01:00
return AVERROR ( ENOMEM ) ;
2009-10-05 10:38:39 +02:00
}
2011-06-18 11:43:24 +02:00
sub_st - > id = pes - > pid ;
2011-11-29 19:28:15 +01:00
avpriv_set_pts_info ( sub_st , 33 , 1 , 90000 ) ;
2014-03-17 18:03:07 +01:00
sub_st - > priv_data = sub_pes ;
2010-03-31 01:30:55 +02:00
sub_st - > codec - > codec_type = AVMEDIA_TYPE_AUDIO ;
2012-08-05 11:11:04 +02:00
sub_st - > codec - > codec_id = AV_CODEC_ID_AC3 ;
2014-03-17 18:03:07 +01:00
sub_st - > need_parsing = AVSTREAM_PARSE_FULL ;
sub_pes - > sub_st = pes - > sub_st = sub_st ;
2009-10-05 10:38:39 +02:00
}
}
2012-08-05 11:11:04 +02:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_NONE )
2009-05-31 05:45:45 +02:00
mpegts_find_stream_type ( st , pes - > stream_type , MISC_types ) ;
2014-03-18 13:16:56 +01:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_NONE ) {
2011-09-15 23:01:04 +02:00
st - > codec - > codec_id = old_codec_id ;
2014-03-18 13:16:56 +01:00
st - > codec - > codec_type = old_codec_type ;
2011-09-15 23:01:04 +02:00
}
2009-05-31 05:12:25 +02:00
2009-11-08 04:17:08 +01:00
return 0 ;
2009-05-31 05:12:25 +02:00
}
2003-06-13 16:28:45 +02:00
2014-05-02 16:51:58 +02:00
static void reset_pes_packet_state ( PESContext * pes )
{
pes - > pts = AV_NOPTS_VALUE ;
pes - > dts = AV_NOPTS_VALUE ;
pes - > data_index = 0 ;
pes - > flags = 0 ;
2014-05-02 17:13:27 +02:00
av_buffer_unref ( & pes - > buffer ) ;
2014-05-02 16:51:58 +02:00
}
2009-11-08 04:27:58 +01:00
static void new_pes_packet ( PESContext * pes , AVPacket * pkt )
{
av_init_packet ( pkt ) ;
2012-10-31 08:53:18 +01:00
pkt - > buf = pes - > buffer ;
pkt - > data = pes - > buffer - > data ;
2009-11-08 04:27:58 +01:00
pkt - > size = pes - > data_index ;
2011-07-24 10:13:51 +02:00
2014-03-17 18:03:07 +01:00
if ( pes - > total_size ! = MAX_PES_PAYLOAD & &
pes - > pes_header_size + pes - > data_index ! = pes - > total_size +
PES_START_SIZE ) {
2011-08-09 19:14:12 +02:00
av_log ( pes - > stream , AV_LOG_WARNING , " PES packet size mismatch \n " ) ;
2011-07-24 10:13:51 +02:00
pes - > flags | = AV_PKT_FLAG_CORRUPT ;
}
2014-03-17 18:03:07 +01:00
memset ( pkt - > data + pkt - > size , 0 , FF_INPUT_BUFFER_PADDING_SIZE ) ;
2009-11-08 04:27:58 +01:00
// Separate out the AC3 substream from an HDMV combined TrueHD/AC3 PID
if ( pes - > sub_st & & pes - > stream_type = = 0x83 & & pes - > extended_stream_id = = 0x76 )
pkt - > stream_index = pes - > sub_st - > index ;
else
pkt - > stream_index = pes - > st - > index ;
pkt - > pts = pes - > pts ;
pkt - > dts = pes - > dts ;
/* store position of first TS packet of this PES packet */
2014-03-17 18:03:07 +01:00
pkt - > pos = pes - > ts_packet_pos ;
2011-07-24 10:13:50 +02:00
pkt - > flags = pes - > flags ;
2009-11-08 04:27:58 +01:00
2014-05-02 17:13:27 +02:00
pes - > buffer = NULL ;
2014-05-02 16:51:58 +02:00
reset_pes_packet_state ( pes ) ;
2009-11-08 04:27:58 +01:00
}
2012-12-08 14:35:27 +01:00
static uint64_t get_ts64 ( GetBitContext * gb , int bits )
2011-10-11 23:49:59 +02:00
{
2012-03-03 21:02:17 +01:00
if ( get_bits_left ( gb ) < bits )
return AV_NOPTS_VALUE ;
2012-12-08 14:58:56 +01:00
return get_bits64 ( gb , bits ) ;
2011-10-11 23:49:59 +02:00
}
2014-03-17 18:03:07 +01:00
static int read_sl_header ( PESContext * pes , SLConfigDescr * sl ,
const uint8_t * buf , int buf_size )
2011-10-11 23:49:59 +02:00
{
GetBitContext gb ;
int au_start_flag = 0 , au_end_flag = 0 , ocr_flag = 0 , idle_flag = 0 ;
int padding_flag = 0 , padding_bits = 0 , inst_bitrate_flag = 0 ;
int dts_flag = - 1 , cts_flag = - 1 ;
int64_t dts = AV_NOPTS_VALUE , cts = AV_NOPTS_VALUE ;
2014-10-04 05:14:08 +02:00
uint8_t buf_padded [ 128 + FF_INPUT_BUFFER_PADDING_SIZE ] ;
int buf_padded_size = FFMIN ( buf_size , sizeof ( buf_padded ) - FF_INPUT_BUFFER_PADDING_SIZE ) ;
2012-03-03 07:43:32 +01:00
2014-10-04 05:14:08 +02:00
memcpy ( buf_padded , buf , buf_padded_size ) ;
init_get_bits ( & gb , buf_padded , buf_padded_size * 8 ) ;
2011-10-11 23:49:59 +02:00
if ( sl - > use_au_start )
au_start_flag = get_bits1 ( & gb ) ;
if ( sl - > use_au_end )
au_end_flag = get_bits1 ( & gb ) ;
if ( ! sl - > use_au_start & & ! sl - > use_au_end )
au_start_flag = au_end_flag = 1 ;
if ( sl - > ocr_len > 0 )
ocr_flag = get_bits1 ( & gb ) ;
if ( sl - > use_idle )
idle_flag = get_bits1 ( & gb ) ;
if ( sl - > use_padding )
padding_flag = get_bits1 ( & gb ) ;
if ( padding_flag )
padding_bits = get_bits ( & gb , 3 ) ;
if ( ! idle_flag & & ( ! padding_flag | | padding_bits ! = 0 ) ) {
if ( sl - > packet_seq_num_len )
skip_bits_long ( & gb , sl - > packet_seq_num_len ) ;
if ( sl - > degr_prior_len )
if ( get_bits1 ( & gb ) )
skip_bits ( & gb , sl - > degr_prior_len ) ;
if ( ocr_flag )
skip_bits_long ( & gb , sl - > ocr_len ) ;
if ( au_start_flag ) {
if ( sl - > use_rand_acc_pt )
get_bits1 ( & gb ) ;
if ( sl - > au_seq_num_len > 0 )
skip_bits_long ( & gb , sl - > au_seq_num_len ) ;
if ( sl - > use_timestamps ) {
dts_flag = get_bits1 ( & gb ) ;
cts_flag = get_bits1 ( & gb ) ;
}
}
if ( sl - > inst_bitrate_len )
inst_bitrate_flag = get_bits1 ( & gb ) ;
if ( dts_flag = = 1 )
2012-12-08 14:35:27 +01:00
dts = get_ts64 ( & gb , sl - > timestamp_len ) ;
2011-10-11 23:49:59 +02:00
if ( cts_flag = = 1 )
2012-12-08 14:35:27 +01:00
cts = get_ts64 ( & gb , sl - > timestamp_len ) ;
2011-10-11 23:49:59 +02:00
if ( sl - > au_len > 0 )
skip_bits_long ( & gb , sl - > au_len ) ;
if ( inst_bitrate_flag )
skip_bits_long ( & gb , sl - > inst_bitrate_len ) ;
}
if ( dts ! = AV_NOPTS_VALUE )
pes - > dts = dts ;
if ( cts ! = AV_NOPTS_VALUE )
pes - > pts = cts ;
2011-12-19 19:48:57 +01:00
if ( sl - > timestamp_len & & sl - > timestamp_res )
avpriv_set_pts_info ( pes - > st , sl - > timestamp_len , 1 , sl - > timestamp_res ) ;
2011-10-11 23:49:59 +02:00
return ( get_bits_count ( & gb ) + 7 ) > > 3 ;
}
2009-11-08 04:27:58 +01:00
/* return non zero if a packet could be constructed */
static int mpegts_push_data ( MpegTSFilter * filter ,
const uint8_t * buf , int buf_size , int is_start ,
2014-03-02 14:12:50 +01:00
int64_t pos )
2009-11-08 04:27:58 +01:00
{
2014-03-17 18:03:07 +01:00
PESContext * pes = filter - > u . pes_filter . opaque ;
2009-11-08 04:27:58 +01:00
MpegTSContext * ts = pes - > ts ;
const uint8_t * p ;
int len , code ;
2014-03-17 18:03:07 +01:00
if ( ! ts - > pkt )
2009-11-08 04:27:58 +01:00
return 0 ;
if ( is_start ) {
if ( pes - > state = = MPEGTS_PAYLOAD & & pes - > data_index > 0 ) {
new_pes_packet ( pes , ts - > pkt ) ;
ts - > stop_parse = 1 ;
2014-05-02 17:17:01 +02:00
} else {
reset_pes_packet_state ( pes ) ;
2009-11-08 04:27:58 +01:00
}
2014-03-17 18:03:07 +01:00
pes - > state = MPEGTS_HEADER ;
2009-11-08 04:27:58 +01:00
pes - > ts_packet_pos = pos ;
}
p = buf ;
while ( buf_size > 0 ) {
2014-03-17 18:03:07 +01:00
switch ( pes - > state ) {
2009-11-08 04:27:58 +01:00
case MPEGTS_HEADER :
len = PES_START_SIZE - pes - > data_index ;
if ( len > buf_size )
len = buf_size ;
memcpy ( pes - > header + pes - > data_index , p , len ) ;
pes - > data_index + = len ;
p + = len ;
buf_size - = len ;
if ( pes - > data_index = = PES_START_SIZE ) {
/* we got all the PES or section header. We can now
2014-03-17 18:03:07 +01:00
* decide */
2009-11-08 04:27:58 +01:00
if ( pes - > header [ 0 ] = = 0x00 & & pes - > header [ 1 ] = = 0x00 & &
pes - > header [ 2 ] = = 0x01 ) {
/* it must be an mpeg2 PES stream */
code = pes - > header [ 3 ] | 0x100 ;
2014-03-17 18:03:07 +01:00
av_dlog ( pes - > stream , " pid=%x pes_code=%#x \n " , pes - > pid ,
code ) ;
2009-11-08 04:27:58 +01:00
2012-09-06 16:43:24 +02:00
if ( ( pes - > st & & pes - > st - > discard = = AVDISCARD_ALL & &
2014-03-17 18:03:07 +01:00
( ! pes - > sub_st | |
pes - > sub_st - > discard = = AVDISCARD_ALL ) ) | |
2009-11-08 04:27:58 +01:00
code = = 0x1be ) /* padding_stream */
goto skip ;
/* stream not present in PMT */
if ( ! pes - > st ) {
2014-07-11 16:42:52 +02:00
if ( ts - > skip_changes )
goto skip ;
2011-06-18 11:43:24 +02:00
pes - > st = avformat_new_stream ( ts - > stream , NULL ) ;
2009-11-08 04:27:58 +01:00
if ( ! pes - > st )
return AVERROR ( ENOMEM ) ;
2011-06-18 11:43:24 +02:00
pes - > st - > id = pes - > pid ;
2009-11-08 04:27:58 +01:00
mpegts_set_stream_info ( pes - > st , pes , 0 , 0 ) ;
}
pes - > total_size = AV_RB16 ( pes - > header + 4 ) ;
/* NOTE: a zero total size means the PES size is
2014-03-17 18:03:07 +01:00
* unbounded */
2009-11-08 04:27:58 +01:00
if ( ! pes - > total_size )
pes - > total_size = MAX_PES_PAYLOAD ;
/* allocate pes buffer */
2012-10-31 08:53:18 +01:00
pes - > buffer = av_buffer_alloc ( pes - > total_size +
FF_INPUT_BUFFER_PADDING_SIZE ) ;
2009-11-08 04:27:58 +01:00
if ( ! pes - > buffer )
return AVERROR ( ENOMEM ) ;
if ( code ! = 0x1bc & & code ! = 0x1bf & & /* program_stream_map, private_stream_2 */
code ! = 0x1f0 & & code ! = 0x1f1 & & /* ECM, EMM */
code ! = 0x1ff & & code ! = 0x1f2 & & /* program_stream_directory, DSMCC_stream */
code ! = 0x1f8 ) { /* ITU-T Rec. H.222.1 type E stream */
pes - > state = MPEGTS_PESHEADER ;
2012-08-07 22:45:46 +02:00
if ( pes - > st - > codec - > codec_id = = AV_CODEC_ID_NONE & & ! pes - > st - > request_probe ) {
2014-03-17 18:03:07 +01:00
av_dlog ( pes - > stream ,
" pid=%x stream_type=%x probing \n " ,
pes - > pid ,
pes - > stream_type ) ;
2014-03-18 13:16:56 +01:00
pes - > st - > request_probe = 1 ;
2009-11-08 04:27:58 +01:00
}
} else {
2014-03-17 18:03:07 +01:00
pes - > state = MPEGTS_PAYLOAD ;
2009-11-08 04:27:58 +01:00
pes - > data_index = 0 ;
}
} else {
/* otherwise, it should be a table */
/* skip packet */
2014-03-17 18:03:07 +01:00
skip :
2009-11-08 04:27:58 +01:00
pes - > state = MPEGTS_SKIP ;
continue ;
}
}
break ;
2014-03-17 18:03:07 +01:00
/**********************************************/
/* PES packing parsing */
2009-11-08 04:27:58 +01:00
case MPEGTS_PESHEADER :
len = PES_HEADER_SIZE - pes - > data_index ;
if ( len < 0 )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2009-11-08 04:27:58 +01:00
if ( len > buf_size )
len = buf_size ;
memcpy ( pes - > header + pes - > data_index , p , len ) ;
pes - > data_index + = len ;
p + = len ;
buf_size - = len ;
if ( pes - > data_index = = PES_HEADER_SIZE ) {
pes - > pes_header_size = pes - > header [ 8 ] + 9 ;
2014-03-17 18:03:07 +01:00
pes - > state = MPEGTS_PESHEADER_FILL ;
2009-11-08 04:27:58 +01:00
}
break ;
case MPEGTS_PESHEADER_FILL :
len = pes - > pes_header_size - pes - > data_index ;
if ( len < 0 )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2009-11-08 04:27:58 +01:00
if ( len > buf_size )
len = buf_size ;
memcpy ( pes - > header + pes - > data_index , p , len ) ;
pes - > data_index + = len ;
p + = len ;
buf_size - = len ;
if ( pes - > data_index = = pes - > pes_header_size ) {
const uint8_t * r ;
unsigned int flags , pes_ext , skip ;
flags = pes - > header [ 7 ] ;
r = pes - > header + 9 ;
pes - > pts = AV_NOPTS_VALUE ;
pes - > dts = AV_NOPTS_VALUE ;
if ( ( flags & 0xc0 ) = = 0x80 ) {
2014-03-02 12:41:10 +01:00
pes - > dts = pes - > pts = ff_parse_pes_pts ( r ) ;
2009-11-08 04:27:58 +01:00
r + = 5 ;
} else if ( ( flags & 0xc0 ) = = 0xc0 ) {
2011-01-30 16:24:00 +01:00
pes - > pts = ff_parse_pes_pts ( r ) ;
2009-11-08 04:27:58 +01:00
r + = 5 ;
2011-01-30 16:24:00 +01:00
pes - > dts = ff_parse_pes_pts ( r ) ;
2009-11-08 04:27:58 +01:00
r + = 5 ;
}
pes - > extended_stream_id = - 1 ;
if ( flags & 0x01 ) { /* PES extension */
pes_ext = * r + + ;
/* Skip PES private data, program packet sequence counter and P-STD buffer */
2014-03-17 18:03:07 +01:00
skip = ( pes_ext > > 4 ) & 0xb ;
2009-11-08 04:27:58 +01:00
skip + = skip & 0x9 ;
2014-03-17 18:03:07 +01:00
r + = skip ;
2009-11-08 04:27:58 +01:00
if ( ( pes_ext & 0x41 ) = = 0x01 & &
( r + 2 ) < = ( pes - > header + pes - > pes_header_size ) ) {
/* PES extension 2 */
if ( ( r [ 0 ] & 0x7f ) > 0 & & ( r [ 1 ] & 0x80 ) = = 0 )
pes - > extended_stream_id = r [ 1 ] ;
}
}
/* we got the full header. We parse it and get the payload */
pes - > state = MPEGTS_PAYLOAD ;
pes - > data_index = 0 ;
2012-03-02 19:12:11 +01:00
if ( pes - > stream_type = = 0x12 & & buf_size > 0 ) {
2014-03-17 18:03:07 +01:00
int sl_header_bytes = read_sl_header ( pes , & pes - > sl , p ,
buf_size ) ;
2011-10-11 23:49:59 +02:00
pes - > pes_header_size + = sl_header_bytes ;
p + = sl_header_bytes ;
buf_size - = sl_header_bytes ;
}
2013-02-05 12:01:11 +01:00
if ( pes - > stream_type = = 0x15 & & buf_size > = 5 ) {
/* skip metadata access unit header */
pes - > pes_header_size + = 5 ;
p + = 5 ;
buf_size - = 5 ;
}
2013-08-04 04:17:22 +02:00
if ( pes - > ts - > fix_teletext_pts & & pes - > st - > codec - > codec_id = = AV_CODEC_ID_DVB_TELETEXT ) {
AVProgram * p = NULL ;
while ( ( p = av_find_program_from_stream ( pes - > stream , p , pes - > st - > index ) ) ) {
if ( p - > pcr_pid ! = - 1 & & p - > discard ! = AVDISCARD_ALL ) {
MpegTSFilter * f = pes - > ts - > pids [ p - > pcr_pid ] ;
2014-03-02 15:20:43 +01:00
if ( f ) {
AVStream * st = NULL ;
if ( f - > type = = MPEGTS_PES ) {
PESContext * pcrpes = f - > u . pes_filter . opaque ;
if ( pcrpes )
st = pcrpes - > st ;
} else if ( f - > type = = MPEGTS_PCR ) {
int i ;
for ( i = 0 ; i < p - > nb_stream_indexes ; i + + ) {
AVStream * pst = pes - > stream - > streams [ p - > stream_index [ i ] ] ;
if ( pst - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO )
st = pst ;
}
}
if ( f - > last_pcr ! = - 1 & & st & & st - > discard ! = AVDISCARD_ALL ) {
2013-08-04 04:17:22 +02:00
// teletext packets do not always have correct timestamps,
// the standard says they should be handled after 40.6 ms at most,
// and the pcr error to this packet should be no more than 100 ms.
// TODO: we should interpolate the PCR, not just use the last one
2014-03-02 14:12:50 +01:00
int64_t pcr = f - > last_pcr / 300 ;
2014-03-02 15:20:43 +01:00
pes - > st - > pts_wrap_reference = st - > pts_wrap_reference ;
pes - > st - > pts_wrap_behavior = st - > pts_wrap_behavior ;
2013-08-04 04:17:22 +02:00
if ( pes - > dts = = AV_NOPTS_VALUE | | pes - > dts < pcr ) {
pes - > pts = pes - > dts = pcr ;
} else if ( pes - > dts > pcr + 3654 + 9000 ) {
pes - > pts = pes - > dts = pcr + 3654 + 9000 ;
}
break ;
}
}
}
}
}
2009-11-08 04:27:58 +01:00
}
break ;
case MPEGTS_PAYLOAD :
2014-05-02 01:35:28 +02:00
if ( pes - > buffer ) {
2014-03-17 18:03:07 +01:00
if ( pes - > data_index > 0 & &
pes - > data_index + buf_size > pes - > total_size ) {
2009-11-08 04:27:58 +01:00
new_pes_packet ( pes , ts - > pkt ) ;
pes - > total_size = MAX_PES_PAYLOAD ;
2014-03-17 18:03:07 +01:00
pes - > buffer = av_buffer_alloc ( pes - > total_size +
FF_INPUT_BUFFER_PADDING_SIZE ) ;
2009-11-08 04:27:58 +01:00
if ( ! pes - > buffer )
return AVERROR ( ENOMEM ) ;
ts - > stop_parse = 1 ;
2014-03-17 18:03:07 +01:00
} else if ( pes - > data_index = = 0 & &
buf_size > pes - > total_size ) {
2010-11-29 04:43:56 +01:00
// pes packet size is < ts size packet and pes data is padded with 0xff
// not sure if this is legal in ts but see issue #2392
buf_size = pes - > total_size ;
2009-11-08 04:27:58 +01:00
}
2012-10-31 08:53:18 +01:00
memcpy ( pes - > buffer - > data + pes - > data_index , p , buf_size ) ;
2009-11-08 04:27:58 +01:00
pes - > data_index + = buf_size ;
2014-05-02 01:44:58 +02:00
/* emit complete packets with known packet size
* decreases demuxer delay for infrequent packets like subtitles from
* a couple of seconds to milliseconds for properly muxed files .
* total_size is the number of bytes following pes_packet_length
* in the pes header , i . e . not counting the first PES_START_SIZE bytes */
if ( ! ts - > stop_parse & & pes - > total_size < MAX_PES_PAYLOAD & &
pes - > pes_header_size + pes - > data_index = = pes - > total_size + PES_START_SIZE ) {
ts - > stop_parse = 1 ;
new_pes_packet ( pes , ts - > pkt ) ;
}
2014-05-02 01:44:19 +02:00
}
buf_size = 0 ;
2009-11-08 04:27:58 +01:00
break ;
case MPEGTS_SKIP :
buf_size = 0 ;
break ;
}
}
return 0 ;
}
static PESContext * add_pes_stream ( MpegTSContext * ts , int pid , int pcr_pid )
{
MpegTSFilter * tss ;
PESContext * pes ;
/* if no pid found, then add a pid context */
pes = av_mallocz ( sizeof ( PESContext ) ) ;
if ( ! pes )
return 0 ;
2014-03-17 18:03:07 +01:00
pes - > ts = ts ;
pes - > stream = ts - > stream ;
pes - > pid = pid ;
2009-11-08 04:27:58 +01:00
pes - > pcr_pid = pcr_pid ;
2014-03-17 18:03:07 +01:00
pes - > state = MPEGTS_SKIP ;
pes - > pts = AV_NOPTS_VALUE ;
pes - > dts = AV_NOPTS_VALUE ;
tss = mpegts_open_pes_filter ( ts , pid , mpegts_push_data , pes ) ;
2009-11-08 04:27:58 +01:00
if ( ! tss ) {
av_free ( pes ) ;
return 0 ;
}
return pes ;
}
2011-10-05 20:04:42 +02:00
# define MAX_LEVEL 4
typedef struct {
AVFormatContext * s ;
2011-02-20 11:04:12 +01:00
AVIOContext pb ;
2011-10-05 20:04:42 +02:00
Mp4Descr * descr ;
Mp4Descr * active_descr ;
int descr_count ;
int max_descr_count ;
int level ;
2014-06-09 23:20:14 +02:00
int predefined_SLConfigDescriptor_seen ;
2011-10-05 20:04:42 +02:00
} MP4DescrParseContext ;
2014-03-17 18:03:07 +01:00
static int init_MP4DescrParseContext ( MP4DescrParseContext * d , AVFormatContext * s ,
const uint8_t * buf , unsigned size ,
Mp4Descr * descr , int max_descr_count )
2011-10-05 20:04:42 +02:00
{
int ret ;
2014-03-17 18:03:07 +01:00
if ( size > ( 1 < < 30 ) )
2011-10-05 20:04:42 +02:00
return AVERROR_INVALIDDATA ;
2014-03-17 18:03:07 +01:00
if ( ( ret = ffio_init_context ( & d - > pb , ( unsigned char * ) buf , size , 0 ,
NULL , NULL , NULL , NULL ) ) < 0 )
2011-10-05 20:04:42 +02:00
return ret ;
2014-03-17 18:03:07 +01:00
d - > s = s ;
d - > level = 0 ;
d - > descr_count = 0 ;
d - > descr = descr ;
d - > active_descr = NULL ;
2011-10-05 20:04:42 +02:00
d - > max_descr_count = max_descr_count ;
return 0 ;
}
2014-03-17 18:03:07 +01:00
static void update_offsets ( AVIOContext * pb , int64_t * off , int * len )
{
2011-10-05 20:04:42 +02:00
int64_t new_off = avio_tell ( pb ) ;
( * len ) - = new_off - * off ;
2014-03-17 18:03:07 +01:00
* off = new_off ;
2011-10-05 20:04:42 +02:00
}
static int parse_mp4_descr ( MP4DescrParseContext * d , int64_t off , int len ,
int target_tag ) ;
static int parse_mp4_descr_arr ( MP4DescrParseContext * d , int64_t off , int len )
{
while ( len > 0 ) {
2014-03-17 18:03:08 +01:00
int ret = parse_mp4_descr ( d , off , len , 0 ) ;
if ( ret < 0 )
return ret ;
2011-10-05 20:04:42 +02:00
update_offsets ( & d - > pb , & off , & len ) ;
}
return 0 ;
}
static int parse_MP4IODescrTag ( MP4DescrParseContext * d , int64_t off , int len )
{
avio_rb16 ( & d - > pb ) ; // ID
avio_r8 ( & d - > pb ) ;
avio_r8 ( & d - > pb ) ;
avio_r8 ( & d - > pb ) ;
avio_r8 ( & d - > pb ) ;
avio_r8 ( & d - > pb ) ;
update_offsets ( & d - > pb , & off , & len ) ;
return parse_mp4_descr_arr ( d , off , len ) ;
}
2011-10-10 21:50:00 +02:00
static int parse_MP4ODescrTag ( MP4DescrParseContext * d , int64_t off , int len )
{
int id_flags ;
if ( len < 2 )
return 0 ;
id_flags = avio_rb16 ( & d - > pb ) ;
2014-03-17 18:03:07 +01:00
if ( ! ( id_flags & 0x0020 ) ) { // URL_Flag
2011-10-10 21:50:00 +02:00
update_offsets ( & d - > pb , & off , & len ) ;
2014-03-17 18:03:07 +01:00
return parse_mp4_descr_arr ( d , off , len ) ; // ES_Descriptor[]
2011-10-10 21:50:00 +02:00
} else {
return 0 ;
}
}
2011-10-05 20:04:42 +02:00
static int parse_MP4ESDescrTag ( MP4DescrParseContext * d , int64_t off , int len )
{
int es_id = 0 ;
if ( d - > descr_count > = d - > max_descr_count )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2011-10-05 20:04:42 +02:00
ff_mp4_parse_es_descr ( & d - > pb , & es_id ) ;
d - > active_descr = d - > descr + ( d - > descr_count + + ) ;
d - > active_descr - > es_id = es_id ;
update_offsets ( & d - > pb , & off , & len ) ;
parse_mp4_descr ( d , off , len , MP4DecConfigDescrTag ) ;
2011-10-11 23:49:59 +02:00
update_offsets ( & d - > pb , & off , & len ) ;
if ( len > 0 )
parse_mp4_descr ( d , off , len , MP4SLDescrTag ) ;
2011-10-05 20:04:42 +02:00
d - > active_descr = NULL ;
return 0 ;
}
2014-03-17 18:03:07 +01:00
static int parse_MP4DecConfigDescrTag ( MP4DescrParseContext * d , int64_t off ,
int len )
2011-10-05 20:04:42 +02:00
{
Mp4Descr * descr = d - > active_descr ;
if ( ! descr )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2011-10-05 20:04:42 +02:00
d - > active_descr - > dec_config_descr = av_malloc ( len ) ;
if ( ! descr - > dec_config_descr )
return AVERROR ( ENOMEM ) ;
descr - > dec_config_descr_len = len ;
avio_read ( & d - > pb , descr - > dec_config_descr , len ) ;
return 0 ;
}
2011-10-11 23:49:59 +02:00
static int parse_MP4SLDescrTag ( MP4DescrParseContext * d , int64_t off , int len )
{
Mp4Descr * descr = d - > active_descr ;
int predefined ;
if ( ! descr )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2011-10-11 23:49:59 +02:00
predefined = avio_r8 ( & d - > pb ) ;
if ( ! predefined ) {
int lengths ;
int flags = avio_r8 ( & d - > pb ) ;
2014-03-17 18:03:07 +01:00
descr - > sl . use_au_start = ! ! ( flags & 0x80 ) ;
descr - > sl . use_au_end = ! ! ( flags & 0x40 ) ;
descr - > sl . use_rand_acc_pt = ! ! ( flags & 0x20 ) ;
descr - > sl . use_padding = ! ! ( flags & 0x08 ) ;
descr - > sl . use_timestamps = ! ! ( flags & 0x04 ) ;
descr - > sl . use_idle = ! ! ( flags & 0x02 ) ;
descr - > sl . timestamp_res = avio_rb32 ( & d - > pb ) ;
avio_rb32 ( & d - > pb ) ;
2011-10-11 23:49:59 +02:00
descr - > sl . timestamp_len = avio_r8 ( & d - > pb ) ;
2013-12-27 11:45:55 +01:00
if ( descr - > sl . timestamp_len > 64 ) {
avpriv_request_sample ( NULL , " timestamp_len > 64 " ) ;
descr - > sl . timestamp_len = 64 ;
return AVERROR_PATCHWELCOME ;
}
2011-10-11 23:49:59 +02:00
descr - > sl . ocr_len = avio_r8 ( & d - > pb ) ;
descr - > sl . au_len = avio_r8 ( & d - > pb ) ;
descr - > sl . inst_bitrate_len = avio_r8 ( & d - > pb ) ;
lengths = avio_rb16 ( & d - > pb ) ;
descr - > sl . degr_prior_len = lengths > > 12 ;
descr - > sl . au_seq_num_len = ( lengths > > 7 ) & 0x1f ;
descr - > sl . packet_seq_num_len = ( lengths > > 2 ) & 0x1f ;
2014-06-09 23:20:14 +02:00
} else if ( ! d - > predefined_SLConfigDescriptor_seen ) {
2013-02-25 23:53:52 +01:00
avpriv_report_missing_feature ( d - > s , " Predefined SLConfigDescriptor " ) ;
2014-06-09 23:20:14 +02:00
d - > predefined_SLConfigDescriptor_seen = 1 ;
2011-10-11 23:49:59 +02:00
}
return 0 ;
}
2011-10-05 20:04:42 +02:00
static int parse_mp4_descr ( MP4DescrParseContext * d , int64_t off , int len ,
2014-03-17 18:03:07 +01:00
int target_tag )
{
2010-11-23 01:51:12 +01:00
int tag ;
2011-10-05 20:04:42 +02:00
int len1 = ff_mp4_read_descr ( d - > s , & d - > pb , & tag ) ;
update_offsets ( & d - > pb , & off , & len ) ;
if ( len < 0 | | len1 > len | | len1 < = 0 ) {
2014-03-17 18:03:07 +01:00
av_log ( d - > s , AV_LOG_ERROR ,
" Tag %x length violation new length %d bytes remaining %d \n " ,
tag , len1 , len ) ;
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2011-10-05 20:04:42 +02:00
}
if ( d - > level + + > = MAX_LEVEL ) {
av_log ( d - > s , AV_LOG_ERROR , " Maximum MP4 descriptor level exceeded \n " ) ;
goto done ;
}
if ( target_tag & & tag ! = target_tag ) {
2014-03-17 18:03:07 +01:00
av_log ( d - > s , AV_LOG_ERROR , " Found tag %x expected %x \n " , tag ,
target_tag ) ;
2011-10-05 20:04:42 +02:00
goto done ;
}
switch ( tag ) {
case MP4IODescrTag :
parse_MP4IODescrTag ( d , off , len1 ) ;
break ;
2011-10-10 21:50:00 +02:00
case MP4ODescrTag :
parse_MP4ODescrTag ( d , off , len1 ) ;
break ;
2011-10-05 20:04:42 +02:00
case MP4ESDescrTag :
parse_MP4ESDescrTag ( d , off , len1 ) ;
break ;
case MP4DecConfigDescrTag :
parse_MP4DecConfigDescrTag ( d , off , len1 ) ;
break ;
2011-10-11 23:49:59 +02:00
case MP4SLDescrTag :
parse_MP4SLDescrTag ( d , off , len1 ) ;
break ;
2010-11-23 01:51:12 +01:00
}
2011-10-05 20:04:42 +02:00
2014-03-17 18:03:08 +01:00
2011-10-05 20:04:42 +02:00
done :
d - > level - - ;
avio_seek ( & d - > pb , off + len1 , SEEK_SET ) ;
return 0 ;
}
2010-11-23 02:10:21 +01:00
static int mp4_read_iods ( AVFormatContext * s , const uint8_t * buf , unsigned size ,
2011-10-05 20:04:42 +02:00
Mp4Descr * descr , int * descr_count , int max_descr_count )
{
MP4DescrParseContext d ;
2014-03-17 18:03:08 +01:00
int ret ;
ret = init_MP4DescrParseContext ( & d , s , buf , size , descr , max_descr_count ) ;
if ( ret < 0 )
return ret ;
2011-10-05 20:04:42 +02:00
2014-03-17 18:03:08 +01:00
ret = parse_mp4_descr ( & d , avio_tell ( & d . pb ) , size , MP4IODescrTag ) ;
2011-10-05 20:04:42 +02:00
* descr_count = d . descr_count ;
2014-03-17 18:03:08 +01:00
return ret ;
2010-11-23 01:51:12 +01:00
}
2011-10-10 21:50:00 +02:00
static int mp4_read_od ( AVFormatContext * s , const uint8_t * buf , unsigned size ,
Mp4Descr * descr , int * descr_count , int max_descr_count )
2010-11-23 01:51:12 +01:00
{
2011-10-10 21:50:00 +02:00
MP4DescrParseContext d ;
2014-03-17 18:03:08 +01:00
int ret ;
ret = init_MP4DescrParseContext ( & d , s , buf , size , descr , max_descr_count ) ;
if ( ret < 0 )
return ret ;
2011-10-10 21:50:00 +02:00
2014-03-17 18:03:08 +01:00
ret = parse_mp4_descr_arr ( & d , avio_tell ( & d . pb ) , size ) ;
2011-10-10 21:50:00 +02:00
* descr_count = d . descr_count ;
2014-03-17 18:03:08 +01:00
return ret ;
2011-10-10 21:50:00 +02:00
}
2014-03-17 18:03:07 +01:00
static void m4sl_cb ( MpegTSFilter * filter , const uint8_t * section ,
int section_len )
2011-10-10 21:50:00 +02:00
{
2011-10-11 23:49:59 +02:00
MpegTSContext * ts = filter - > u . section_filter . opaque ;
SectionHeader h ;
const uint8_t * p , * p_end ;
2011-02-20 11:04:12 +01:00
AVIOContext pb ;
2011-10-10 21:50:00 +02:00
int mp4_descr_count = 0 ;
2014-03-17 18:03:07 +01:00
Mp4Descr mp4_descr [ MAX_MP4_DESCR_COUNT ] = { { 0 } } ;
2011-10-10 21:50:00 +02:00
int i , pid ;
2011-10-11 23:49:59 +02:00
AVFormatContext * s = ts - > stream ;
p_end = section + section_len - 4 ;
p = section ;
if ( parse_section_header ( & h , & p , p_end ) < 0 )
return ;
if ( h . tid ! = M4OD_TID )
return ;
2011-10-10 21:50:00 +02:00
2014-03-17 18:03:07 +01:00
mp4_read_od ( s , p , ( unsigned ) ( p_end - p ) , mp4_descr , & mp4_descr_count ,
MAX_MP4_DESCR_COUNT ) ;
2011-10-10 21:50:00 +02:00
for ( pid = 0 ; pid < NB_PID_MAX ; pid + + ) {
if ( ! ts - > pids [ pid ] )
2014-03-17 18:03:07 +01:00
continue ;
2011-10-10 21:50:00 +02:00
for ( i = 0 ; i < mp4_descr_count ; i + + ) {
PESContext * pes ;
AVStream * st ;
if ( ts - > pids [ pid ] - > es_id ! = mp4_descr [ i ] . es_id )
continue ;
2014-04-16 02:06:37 +02:00
if ( ts - > pids [ pid ] - > type ! = MPEGTS_PES ) {
2011-10-10 21:50:00 +02:00
av_log ( s , AV_LOG_ERROR , " pid %x is not PES \n " , pid ) ;
continue ;
}
pes = ts - > pids [ pid ] - > u . pes_filter . opaque ;
2014-03-17 18:03:07 +01:00
st = pes - > st ;
if ( ! st )
2011-10-10 21:50:00 +02:00
continue ;
2011-10-11 23:49:59 +02:00
pes - > sl = mp4_descr [ i ] . sl ;
2011-10-10 21:50:00 +02:00
ffio_init_context ( & pb , mp4_descr [ i ] . dec_config_descr ,
2014-03-17 18:03:07 +01:00
mp4_descr [ i ] . dec_config_descr_len , 0 ,
NULL , NULL , NULL , NULL ) ;
2011-10-10 21:50:00 +02:00
ff_mp4_read_dec_config_descr ( s , st , & pb ) ;
2012-08-05 11:11:04 +02:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_AAC & &
2011-10-10 21:50:00 +02:00
st - > codec - > extradata_size > 0 )
st - > need_parsing = 0 ;
2012-08-05 11:11:04 +02:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_H264 & &
2011-10-10 21:50:00 +02:00
st - > codec - > extradata_size > 0 )
st - > need_parsing = 0 ;
2012-08-05 11:11:04 +02:00
if ( st - > codec - > codec_id < = AV_CODEC_ID_NONE ) {
2014-03-17 18:03:07 +01:00
// do nothing
} else if ( st - > codec - > codec_id < AV_CODEC_ID_FIRST_AUDIO )
2011-10-10 21:50:00 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_VIDEO ;
2014-03-17 18:03:07 +01:00
else if ( st - > codec - > codec_id < AV_CODEC_ID_FIRST_SUBTITLE )
2011-10-10 21:50:00 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_AUDIO ;
2014-03-17 18:03:07 +01:00
else if ( st - > codec - > codec_id < AV_CODEC_ID_FIRST_UNKNOWN )
2011-10-10 21:50:00 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_SUBTITLE ;
2010-11-23 01:51:12 +01:00
}
}
2011-10-10 21:50:00 +02:00
for ( i = 0 ; i < mp4_descr_count ; i + + )
av_free ( mp4_descr [ i ] . dec_config_descr ) ;
2010-11-23 01:51:12 +01:00
}
2010-12-29 13:45:31 +01:00
int ff_parse_mpeg2_descriptor ( AVFormatContext * fc , AVStream * st , int stream_type ,
const uint8_t * * pp , const uint8_t * desc_list_end ,
2011-10-06 03:24:17 +02:00
Mp4Descr * mp4_descr , int mp4_descr_count , int pid ,
MpegTSContext * ts )
2010-12-29 13:45:31 +01:00
{
const uint8_t * desc_end ;
2011-10-05 03:24:22 +02:00
int desc_len , desc_tag , desc_es_id ;
2011-02-17 16:26:34 +01:00
char language [ 252 ] ;
int i ;
2010-12-29 13:45:31 +01:00
desc_tag = get8 ( pp , desc_list_end ) ;
if ( desc_tag < 0 )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2010-12-29 13:45:31 +01:00
desc_len = get8 ( pp , desc_list_end ) ;
if ( desc_len < 0 )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2010-12-29 13:45:31 +01:00
desc_end = * pp + desc_len ;
if ( desc_end > desc_list_end )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2010-12-29 13:45:31 +01:00
2011-01-29 17:46:18 +01:00
av_dlog ( fc , " tag: 0x%02x len=%d \n " , desc_tag , desc_len ) ;
2010-12-29 13:45:31 +01:00
2014-09-01 03:15:55 +02:00
if ( ( st - > codec - > codec_id = = AV_CODEC_ID_NONE | | st - > request_probe > 0 ) & &
2010-12-29 13:45:31 +01:00
stream_type = = STREAM_TYPE_PRIVATE_DATA )
mpegts_find_stream_type ( st , desc_tag , DESC_types ) ;
2014-03-17 18:03:07 +01:00
switch ( desc_tag ) {
2011-10-05 03:24:22 +02:00
case 0x1E : /* SL descriptor */
desc_es_id = get16 ( pp , desc_end ) ;
2011-10-10 21:50:00 +02:00
if ( ts & & ts - > pids [ pid ] )
ts - > pids [ pid ] - > es_id = desc_es_id ;
2011-10-05 08:43:59 +02:00
for ( i = 0 ; i < mp4_descr_count ; i + + )
2014-03-17 18:03:07 +01:00
if ( mp4_descr [ i ] . dec_config_descr_len & &
mp4_descr [ i ] . es_id = = desc_es_id ) {
AVIOContext pb ;
ffio_init_context ( & pb , mp4_descr [ i ] . dec_config_descr ,
mp4_descr [ i ] . dec_config_descr_len , 0 ,
NULL , NULL , NULL , NULL ) ;
ff_mp4_read_dec_config_descr ( fc , st , & pb ) ;
if ( st - > codec - > codec_id = = AV_CODEC_ID_AAC & &
st - > codec - > extradata_size > 0 )
st - > need_parsing = 0 ;
if ( st - > codec - > codec_id = = AV_CODEC_ID_MPEG4SYSTEMS )
mpegts_open_section_filter ( ts , pid , m4sl_cb , ts , 1 ) ;
}
2011-10-05 03:24:22 +02:00
break ;
2010-12-29 13:45:31 +01:00
case 0x1F : /* FMC descriptor */
get16 ( pp , desc_end ) ;
2014-03-17 18:03:07 +01:00
if ( mp4_descr_count > 0 & &
2014-03-18 13:16:56 +01:00
( st - > codec - > codec_id = = AV_CODEC_ID_AAC_LATM | | st - > request_probe > 0 ) & &
2011-10-05 08:43:59 +02:00
mp4_descr - > dec_config_descr_len & & mp4_descr - > es_id = = pid ) {
2011-02-20 11:04:12 +01:00
AVIOContext pb ;
2011-10-05 08:43:59 +02:00
ffio_init_context ( & pb , mp4_descr - > dec_config_descr ,
2014-03-17 18:03:07 +01:00
mp4_descr - > dec_config_descr_len , 0 ,
NULL , NULL , NULL , NULL ) ;
2010-12-29 13:45:31 +01:00
ff_mp4_read_dec_config_descr ( fc , st , & pb ) ;
2012-08-05 11:11:04 +02:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_AAC & &
2014-03-18 13:16:56 +01:00
st - > codec - > extradata_size > 0 ) {
st - > request_probe = st - > need_parsing = 0 ;
st - > codec - > codec_type = AVMEDIA_TYPE_AUDIO ;
2011-10-27 21:22:31 +02:00
}
2010-12-29 13:45:31 +01:00
}
break ;
case 0x56 : /* DVB teletext descriptor */
2014-01-24 20:12:48 +01:00
{
uint8_t * extradata = NULL ;
int language_count = desc_len / 5 ;
if ( desc_len > 0 & & desc_len % 5 ! = 0 )
return AVERROR_INVALIDDATA ;
if ( language_count > 0 ) {
/* 4 bytes per language code (3 bytes) with comma or NUL byte should fit language buffer */
if ( language_count > sizeof ( language ) / 4 ) {
language_count = sizeof ( language ) / 4 ;
}
if ( st - > codec - > extradata = = NULL ) {
if ( ff_alloc_extradata ( st - > codec , language_count * 2 ) ) {
return AVERROR ( ENOMEM ) ;
}
}
if ( st - > codec - > extradata_size < language_count * 2 )
return AVERROR_INVALIDDATA ;
extradata = st - > codec - > extradata ;
for ( i = 0 ; i < language_count ; i + + ) {
language [ i * 4 + 0 ] = get8 ( pp , desc_end ) ;
language [ i * 4 + 1 ] = get8 ( pp , desc_end ) ;
language [ i * 4 + 2 ] = get8 ( pp , desc_end ) ;
language [ i * 4 + 3 ] = ' , ' ;
memcpy ( extradata , * pp , 2 ) ;
extradata + = 2 ;
* pp + = 2 ;
}
language [ i * 4 - 1 ] = 0 ;
av_dict_set ( & st - > metadata , " language " , language , 0 ) ;
}
}
2010-12-29 13:45:31 +01:00
break ;
case 0x59 : /* subtitling descriptor */
2014-02-03 13:11:07 +01:00
{
/* 8 bytes per DVB subtitle substream data:
* ISO_639_language_code ( 3 bytes ) ,
* subtitling_type ( 1 byte ) ,
* composition_page_id ( 2 bytes ) ,
* ancillary_page_id ( 2 bytes ) */
int language_count = desc_len / 8 ;
if ( desc_len > 0 & & desc_len % 8 ! = 0 )
return AVERROR_INVALIDDATA ;
if ( language_count > 1 ) {
avpriv_request_sample ( fc , " DVB subtitles with multiple languages " ) ;
}
if ( language_count > 0 ) {
uint8_t * extradata ;
/* 4 bytes per language code (3 bytes) with comma or NUL byte should fit language buffer */
if ( language_count > sizeof ( language ) / 4 ) {
language_count = sizeof ( language ) / 4 ;
}
if ( st - > codec - > extradata = = NULL ) {
if ( ff_alloc_extradata ( st - > codec , language_count * 5 ) ) {
return AVERROR ( ENOMEM ) ;
}
}
if ( st - > codec - > extradata_size < language_count * 5 )
return AVERROR_INVALIDDATA ;
extradata = st - > codec - > extradata ;
for ( i = 0 ; i < language_count ; i + + ) {
language [ i * 4 + 0 ] = get8 ( pp , desc_end ) ;
language [ i * 4 + 1 ] = get8 ( pp , desc_end ) ;
language [ i * 4 + 2 ] = get8 ( pp , desc_end ) ;
language [ i * 4 + 3 ] = ' , ' ;
/* hearing impaired subtitles detection using subtitling_type */
2014-03-18 13:16:56 +01:00
switch ( * pp [ 0 ] ) {
2014-02-03 13:11:07 +01:00
case 0x20 : /* DVB subtitles (for the hard of hearing) with no monitor aspect ratio criticality */
case 0x21 : /* DVB subtitles (for the hard of hearing) for display on 4:3 aspect ratio monitor */
case 0x22 : /* DVB subtitles (for the hard of hearing) for display on 16:9 aspect ratio monitor */
case 0x23 : /* DVB subtitles (for the hard of hearing) for display on 2.21:1 aspect ratio monitor */
case 0x24 : /* DVB subtitles (for the hard of hearing) for display on a high definition monitor */
case 0x25 : /* DVB subtitles (for the hard of hearing) with plano-stereoscopic disparity for display on a high definition monitor */
st - > disposition | = AV_DISPOSITION_HEARING_IMPAIRED ;
break ;
}
extradata [ 4 ] = get8 ( pp , desc_end ) ; /* subtitling_type */
memcpy ( extradata , * pp , 4 ) ; /* composition_page_id and ancillary_page_id */
extradata + = 5 ;
* pp + = 4 ;
}
language [ i * 4 - 1 ] = 0 ;
av_dict_set ( & st - > metadata , " language " , language , 0 ) ;
2010-12-29 13:45:31 +01:00
}
}
break ;
case 0x0a : /* ISO 639 language descriptor */
2011-02-17 16:26:34 +01:00
for ( i = 0 ; i + 4 < = desc_len ; i + = 4 ) {
language [ i + 0 ] = get8 ( pp , desc_end ) ;
language [ i + 1 ] = get8 ( pp , desc_end ) ;
language [ i + 2 ] = get8 ( pp , desc_end ) ;
language [ i + 3 ] = ' , ' ;
2014-03-17 18:03:07 +01:00
switch ( get8 ( pp , desc_end ) ) {
case 0x01 :
st - > disposition | = AV_DISPOSITION_CLEAN_EFFECTS ;
break ;
case 0x02 :
st - > disposition | = AV_DISPOSITION_HEARING_IMPAIRED ;
break ;
case 0x03 :
st - > disposition | = AV_DISPOSITION_VISUAL_IMPAIRED ;
break ;
}
2011-02-17 16:26:34 +01:00
}
2014-07-21 21:39:02 +02:00
if ( i & & language [ 0 ] ) {
2011-02-17 16:26:34 +01:00
language [ i - 1 ] = 0 ;
2011-05-22 12:46:29 +02:00
av_dict_set ( & st - > metadata , " language " , language , 0 ) ;
2011-02-17 16:26:34 +01:00
}
2010-12-29 13:45:31 +01:00
break ;
case 0x05 : /* registration descriptor */
st - > codec - > codec_tag = bytestream_get_le32 ( pp ) ;
2014-03-17 18:03:07 +01:00
av_dlog ( fc , " reg_desc=%.4s \n " , ( char * ) & st - > codec - > codec_tag ) ;
2012-08-05 11:11:04 +02:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_NONE )
2010-12-29 13:45:31 +01:00
mpegts_find_stream_type ( st , st - > codec - > codec_tag , REGD_types ) ;
break ;
2011-03-04 16:09:32 +01:00
case 0x52 : /* stream identifier descriptor */
st - > stream_identifier = 1 + get8 ( pp , desc_end ) ;
break ;
2013-02-05 12:01:11 +01:00
case 0x26 : /* metadata descriptor */
if ( get16 ( pp , desc_end ) = = 0xFFFF )
* pp + = 4 ;
if ( get8 ( pp , desc_end ) = = 0xFF ) {
st - > codec - > codec_tag = bytestream_get_le32 ( pp ) ;
if ( st - > codec - > codec_id = = AV_CODEC_ID_NONE )
mpegts_find_stream_type ( st , st - > codec - > codec_tag , METADATA_types ) ;
}
break ;
2010-12-29 13:45:31 +01:00
default :
break ;
}
* pp = desc_end ;
return 0 ;
}
2007-06-04 15:57:00 +02:00
static void pmt_cb ( MpegTSFilter * filter , const uint8_t * section , int section_len )
2003-06-13 16:28:45 +02:00
{
2007-06-04 15:57:00 +02:00
MpegTSContext * ts = filter - > u . section_filter . opaque ;
2003-06-13 16:28:45 +02:00
SectionHeader h1 , * h = & h1 ;
2005-07-17 02:28:12 +02:00
PESContext * pes ;
AVStream * st ;
2010-12-29 13:45:31 +01:00
const uint8_t * p , * p_end , * desc_list_end ;
2005-07-17 02:28:12 +02:00
int program_info_length , pcr_pid , pid , stream_type ;
2010-12-29 13:45:31 +01:00
int desc_list_len ;
2009-05-31 04:56:15 +02:00
uint32_t prog_reg_desc = 0 ; /* registration descriptor */
2011-10-05 08:43:59 +02:00
int mp4_descr_count = 0 ;
2014-03-17 18:03:07 +01:00
Mp4Descr mp4_descr [ MAX_MP4_DESCR_COUNT ] = { { 0 } } ;
2011-10-05 08:43:59 +02:00
int i ;
2005-12-17 19:14:38 +01:00
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " PMT: len %i \n " , section_len ) ;
2012-10-01 12:47:49 +02:00
hex_dump_debug ( ts - > stream , section , section_len ) ;
2009-04-12 05:08:46 +02:00
2003-06-13 16:28:45 +02:00
p_end = section + section_len - 4 ;
p = section ;
if ( parse_section_header ( h , & p , p_end ) < 0 )
return ;
2009-04-12 05:08:46 +02:00
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " sid=0x%x sec_num=%d/%d \n " ,
2014-03-17 18:03:07 +01:00
h - > id , h - > sec_num , h - > last_sec_num ) ;
2009-04-12 05:08:46 +02:00
2007-06-04 16:17:43 +02:00
if ( h - > tid ! = PMT_TID )
2003-06-13 16:28:45 +02:00
return ;
2014-07-11 16:42:52 +02:00
if ( ts - > skip_changes )
return ;
2003-06-13 16:28:45 +02:00
2007-09-25 22:58:37 +02:00
clear_program ( ts , h - > id ) ;
2012-03-27 00:51:59 +02:00
pcr_pid = get16 ( & p , p_end ) ;
2003-06-13 16:28:45 +02:00
if ( pcr_pid < 0 )
return ;
2012-03-27 00:51:59 +02:00
pcr_pid & = 0x1fff ;
2007-09-25 22:58:37 +02:00
add_pid_to_pmt ( ts , h - > id , pcr_pid ) ;
2011-03-11 13:39:55 +01:00
set_pcr_pid ( ts - > stream , h - > id , pcr_pid ) ;
2009-04-12 05:08:46 +02:00
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " pcr_pid=0x%x \n " , pcr_pid ) ;
2009-04-12 05:08:46 +02:00
2012-03-27 00:51:59 +02:00
program_info_length = get16 ( & p , p_end ) ;
2003-06-13 16:28:45 +02:00
if ( program_info_length < 0 )
return ;
2012-03-27 00:51:59 +02:00
program_info_length & = 0xfff ;
2014-03-17 18:03:07 +01:00
while ( program_info_length > = 2 ) {
2008-02-23 11:57:38 +01:00
uint8_t tag , len ;
tag = get8 ( & p , p_end ) ;
len = get8 ( & p , p_end ) ;
2010-11-23 01:51:12 +01:00
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " program tag: 0x%02x len=%d \n " , tag , len ) ;
2010-11-23 01:51:12 +01:00
2014-03-17 18:03:07 +01:00
if ( len > program_info_length - 2 )
// something else is broken, exit the program_descriptors_loop
2008-02-23 11:57:38 +01:00
break ;
program_info_length - = len + 2 ;
2010-11-23 01:51:12 +01:00
if ( tag = = 0x1d ) { // IOD descriptor
get8 ( & p , p_end ) ; // scope
get8 ( & p , p_end ) ; // label
len - = 2 ;
2011-10-05 20:04:42 +02:00
mp4_read_iods ( ts - > stream , p , len , mp4_descr + mp4_descr_count ,
& mp4_descr_count , MAX_MP4_DESCR_COUNT ) ;
2010-11-23 01:51:12 +01:00
} else if ( tag = = 0x05 & & len > = 4 ) { // registration descriptor
2009-05-31 04:56:15 +02:00
prog_reg_desc = bytestream_get_le32 ( & p ) ;
2008-02-23 11:57:38 +01:00
len - = 4 ;
}
p + = len ;
}
2003-06-13 16:28:45 +02:00
p + = program_info_length ;
if ( p > = p_end )
2010-11-23 02:04:49 +01:00
goto out ;
2009-07-29 04:17:08 +02:00
// stop parsing after pmt, we found header
if ( ! ts - > stream - > nb_streams )
2011-10-08 23:40:40 +02:00
ts - > stop_parse = 2 ;
2009-07-29 04:17:08 +02:00
2013-12-15 15:58:31 +01:00
set_pmt_found ( ts , h - > id ) ;
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
2005-07-17 02:28:12 +02:00
st = 0 ;
2011-10-06 03:24:17 +02:00
pes = NULL ;
2003-06-13 16:28:45 +02:00
stream_type = get8 ( & p , p_end ) ;
if ( stream_type < 0 )
break ;
2012-03-27 00:51:59 +02:00
pid = get16 ( & p , p_end ) ;
2003-06-13 16:28:45 +02:00
if ( pid < 0 )
2014-03-02 18:34:48 +01:00
goto out ;
2012-03-27 00:51:59 +02:00
pid & = 0x1fff ;
2012-11-13 15:21:41 +01:00
if ( pid = = ts - > current_pid )
2014-03-02 18:34:48 +01:00
goto out ;
2009-05-31 05:35:29 +02:00
2011-10-30 17:56:57 +01:00
/* now create stream */
2009-05-31 05:35:29 +02:00
if ( ts - > pids [ pid ] & & ts - > pids [ pid ] - > type = = MPEGTS_PES ) {
pes = ts - > pids [ pid ] - > u . pes_filter . opaque ;
2011-06-18 11:43:24 +02:00
if ( ! pes - > st ) {
2014-03-17 18:03:07 +01:00
pes - > st = avformat_new_stream ( pes - > stream , NULL ) ;
2012-12-13 17:46:17 +01:00
if ( ! pes - > st )
goto out ;
2011-10-24 17:56:52 +02:00
pes - > st - > id = pes - > pid ;
2011-06-18 11:43:24 +02:00
}
2009-05-31 05:35:29 +02:00
st = pes - > st ;
2011-10-06 03:24:17 +02:00
} else if ( stream_type ! = 0x13 ) {
2014-03-17 18:03:07 +01:00
if ( ts - > pids [ pid ] )
mpegts_close_filter ( ts , ts - > pids [ pid ] ) ; // wrongly added sdt filter probably
2009-11-08 04:17:08 +01:00
pes = add_pes_stream ( ts , pid , pcr_pid ) ;
2011-06-18 11:43:24 +02:00
if ( pes ) {
st = avformat_new_stream ( pes - > stream , NULL ) ;
2012-12-13 17:46:17 +01:00
if ( ! st )
goto out ;
2011-06-18 11:43:24 +02:00
st - > id = pes - > pid ;
}
2011-10-06 03:24:17 +02:00
} else {
int idx = ff_find_stream_index ( ts - > stream , pid ) ;
if ( idx > = 0 ) {
st = ts - > stream - > streams [ idx ] ;
} else {
2011-12-19 19:41:22 +01:00
st = avformat_new_stream ( ts - > stream , NULL ) ;
2012-12-13 17:46:17 +01:00
if ( ! st )
goto out ;
2011-10-06 03:24:17 +02:00
st - > id = pid ;
2011-10-10 21:50:00 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_DATA ;
2011-10-06 03:24:17 +02:00
}
2009-05-31 05:35:29 +02:00
}
if ( ! st )
2010-11-23 02:04:49 +01:00
goto out ;
2009-05-31 05:35:29 +02:00
2011-10-06 03:24:17 +02:00
if ( pes & & ! pes - > stream_type )
2009-11-08 04:17:08 +01:00
mpegts_set_stream_info ( st , pes , stream_type , prog_reg_desc ) ;
2009-05-31 05:35:29 +02:00
add_pid_to_pmt ( ts , h - > id , pid ) ;
2010-03-16 00:14:07 +01:00
ff_program_add_stream_index ( ts - > stream , h - > id , st - > index ) ;
2009-05-31 05:35:29 +02:00
2012-03-27 00:51:59 +02:00
desc_list_len = get16 ( & p , p_end ) ;
2005-07-17 02:28:12 +02:00
if ( desc_list_len < 0 )
2014-03-02 18:34:48 +01:00
goto out ;
2012-03-27 00:51:59 +02:00
desc_list_len & = 0xfff ;
2014-03-17 18:03:07 +01:00
desc_list_end = p + desc_list_len ;
2009-04-12 04:19:40 +02:00
if ( desc_list_end > p_end )
2014-03-02 18:34:48 +01:00
goto out ;
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
if ( ff_parse_mpeg2_descriptor ( ts - > stream , st , stream_type , & p ,
desc_list_end , mp4_descr ,
mp4_descr_count , pid , ts ) < 0 )
2010-11-23 01:51:12 +01:00
break ;
2009-10-05 10:38:39 +02:00
2014-03-17 18:03:07 +01:00
if ( pes & & prog_reg_desc = = AV_RL32 ( " HDMV " ) & &
stream_type = = 0x83 & & pes - > sub_st ) {
ff_program_add_stream_index ( ts - > stream , h - > id ,
pes - > sub_st - > index ) ;
2009-10-05 10:38:39 +02:00
pes - > sub_st - > codec - > codec_tag = st - > codec - > codec_tag ;
}
2005-07-17 02:28:12 +02:00
}
p = desc_list_end ;
2003-06-13 16:28:45 +02:00
}
2010-11-23 02:04:49 +01:00
2014-03-02 01:47:17 +01:00
if ( ! ts - > pids [ pcr_pid ] )
mpegts_open_pcr_filter ( ts , pcr_pid ) ;
2014-03-17 18:03:07 +01:00
out :
2011-10-05 08:43:59 +02:00
for ( i = 0 ; i < mp4_descr_count ; i + + )
av_free ( mp4_descr [ i ] . dec_config_descr ) ;
2003-06-13 16:28:45 +02:00
}
2007-06-04 15:57:00 +02:00
static void pat_cb ( MpegTSFilter * filter , const uint8_t * section , int section_len )
2003-06-13 16:28:45 +02:00
{
2007-06-04 15:57:00 +02:00
MpegTSContext * ts = filter - > u . section_filter . opaque ;
2003-06-13 16:28:45 +02:00
SectionHeader h1 , * h = & h1 ;
const uint8_t * p , * p_end ;
int sid , pmt_pid ;
2011-03-04 20:22:09 +01:00
AVProgram * program ;
2003-06-13 16:28:45 +02:00
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " PAT: \n " ) ;
2012-10-01 12:47:49 +02:00
hex_dump_debug ( ts - > stream , section , section_len ) ;
2011-05-27 20:34:01 +02:00
2003-06-13 16:28:45 +02:00
p_end = section + section_len - 4 ;
2014-03-17 18:03:07 +01:00
p = section ;
2003-06-13 16:28:45 +02:00
if ( parse_section_header ( h , & p , p_end ) < 0 )
return ;
if ( h - > tid ! = PAT_TID )
return ;
2014-07-11 16:42:52 +02:00
if ( ts - > skip_changes )
return ;
2003-06-13 16:28:45 +02:00
2011-03-04 20:22:09 +01:00
ts - > stream - > ts_id = h - > id ;
2007-09-25 22:58:37 +02:00
clear_programs ( ts ) ;
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
2003-06-13 16:28:45 +02:00
sid = get16 ( & p , p_end ) ;
if ( sid < 0 )
break ;
2012-03-27 00:51:59 +02:00
pmt_pid = get16 ( & p , p_end ) ;
2003-06-13 16:28:45 +02:00
if ( pmt_pid < 0 )
break ;
2012-03-27 00:51:59 +02:00
pmt_pid & = 0x1fff ;
2009-04-12 05:08:46 +02:00
2012-11-13 19:48:03 +01:00
if ( pmt_pid = = ts - > current_pid )
break ;
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " sid=0x%x pid=0x%x \n " , sid , pmt_pid ) ;
2009-04-12 05:08:46 +02:00
2003-06-13 16:28:45 +02:00
if ( sid = = 0x0000 ) {
/* NIT info */
} else {
2013-07-05 03:27:07 +02:00
MpegTSFilter * fil = ts - > pids [ pmt_pid ] ;
2011-03-04 20:22:09 +01:00
program = av_new_program ( ts - > stream , sid ) ;
program - > program_num = sid ;
program - > pmt_pid = pmt_pid ;
2013-07-05 03:27:07 +02:00
if ( fil )
if ( fil - > type ! = MPEGTS_SECTION
| | fil - > pid ! = pmt_pid
| | fil - > u . section_filter . section_cb ! = pmt_cb )
mpegts_close_filter ( ts , ts - > pids [ pmt_pid ] ) ;
if ( ! ts - > pids [ pmt_pid ] )
mpegts_open_section_filter ( ts , pmt_pid , pmt_cb , ts , 1 ) ;
2007-09-25 22:58:37 +02:00
add_pat_entry ( ts , sid ) ;
2014-03-17 18:03:07 +01:00
add_pid_to_pmt ( ts , sid , 0 ) ; // add pat pid to program
2007-09-25 22:58:37 +02:00
add_pid_to_pmt ( ts , sid , pmt_pid ) ;
2013-02-04 23:41:53 +01:00
}
}
if ( sid < 0 ) {
int i , j ;
for ( j = 0 ; j < ts - > stream - > nb_programs ; j + + ) {
2014-03-18 13:16:56 +01:00
for ( i = 0 ; i < ts - > nb_prg ; i + + )
2013-02-04 23:41:53 +01:00
if ( ts - > prg [ i ] . id = = ts - > stream - > programs [ j ] - > id )
break ;
2014-07-12 21:49:15 +02:00
if ( i = = ts - > nb_prg & & ! ts - > skip_clear )
2013-02-04 23:41:53 +01:00
clear_avprogram ( ts , ts - > stream - > programs [ j ] - > id ) ;
2003-06-13 16:28:45 +02:00
}
}
}
2007-06-04 15:57:00 +02:00
static void sdt_cb ( MpegTSFilter * filter , const uint8_t * section , int section_len )
2003-06-13 16:28:45 +02:00
{
2007-06-04 15:57:00 +02:00
MpegTSContext * ts = filter - > u . section_filter . opaque ;
2003-06-13 16:28:45 +02:00
SectionHeader h1 , * h = & h1 ;
const uint8_t * p , * p_end , * desc_list_end , * desc_end ;
int onid , val , sid , desc_list_len , desc_tag , desc_len , service_type ;
char * name , * provider_name ;
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " SDT: \n " ) ;
2012-10-01 12:47:49 +02:00
hex_dump_debug ( ts - > stream , section , section_len ) ;
2003-06-13 16:28:45 +02:00
p_end = section + section_len - 4 ;
2014-03-17 18:03:07 +01:00
p = section ;
2003-06-13 16:28:45 +02:00
if ( parse_section_header ( h , & p , p_end ) < 0 )
return ;
if ( h - > tid ! = SDT_TID )
return ;
2014-07-11 16:42:52 +02:00
if ( ts - > skip_changes )
return ;
2003-06-13 16:28:45 +02:00
onid = get16 ( & p , p_end ) ;
if ( onid < 0 )
return ;
val = get8 ( & p , p_end ) ;
if ( val < 0 )
return ;
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
2003-06-13 16:28:45 +02:00
sid = get16 ( & p , p_end ) ;
if ( sid < 0 )
break ;
val = get8 ( & p , p_end ) ;
if ( val < 0 )
break ;
2012-03-27 00:51:59 +02:00
desc_list_len = get16 ( & p , p_end ) ;
2003-06-13 16:28:45 +02:00
if ( desc_list_len < 0 )
break ;
2012-03-27 00:51:59 +02:00
desc_list_len & = 0xfff ;
2014-03-17 18:03:07 +01:00
desc_list_end = p + desc_list_len ;
2003-06-13 16:28:45 +02:00
if ( desc_list_end > p_end )
break ;
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
2003-06-13 16:28:45 +02:00
desc_tag = get8 ( & p , desc_list_end ) ;
if ( desc_tag < 0 )
break ;
desc_len = get8 ( & p , desc_list_end ) ;
desc_end = p + desc_len ;
2014-10-04 04:29:40 +02:00
if ( desc_len < 0 | | desc_end > desc_list_end )
2003-06-13 16:28:45 +02:00
break ;
2009-04-12 05:08:46 +02:00
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " tag: 0x%02x len=%d \n " ,
2014-03-17 18:03:07 +01:00
desc_tag , desc_len ) ;
2009-04-12 05:08:46 +02:00
2014-03-17 18:03:07 +01:00
switch ( desc_tag ) {
2003-06-13 16:28:45 +02:00
case 0x48 :
service_type = get8 ( & p , p_end ) ;
if ( service_type < 0 )
break ;
provider_name = getstr8 ( & p , p_end ) ;
if ( ! provider_name )
break ;
name = getstr8 ( & p , p_end ) ;
2007-09-25 22:49:11 +02:00
if ( name ) {
AVProgram * program = av_new_program ( ts - > stream , sid ) ;
2014-03-17 18:03:07 +01:00
if ( program ) {
2011-05-22 12:46:29 +02:00
av_dict_set ( & program - > metadata , " service_name " , name , 0 ) ;
2014-03-17 18:03:07 +01:00
av_dict_set ( & program - > metadata , " service_provider " ,
provider_name , 0 ) ;
2009-02-10 01:25:21 +01:00
}
2007-09-25 22:49:11 +02:00
}
2008-04-25 00:16:00 +02:00
av_free ( name ) ;
av_free ( provider_name ) ;
2003-06-13 16:28:45 +02:00
break ;
default :
break ;
}
p = desc_end ;
}
p = desc_list_end ;
}
}
2013-07-27 21:14:45 +02:00
static int parse_pcr ( int64_t * ppcr_high , int * ppcr_low ,
const uint8_t * packet ) ;
2003-06-13 16:28:45 +02:00
/* handle one TS packet */
2009-05-27 02:56:31 +02:00
static int handle_packet ( MpegTSContext * ts , const uint8_t * packet )
2002-05-20 18:27:23 +02:00
{
2003-06-13 16:28:45 +02:00
MpegTSFilter * tss ;
2011-07-24 10:13:50 +02:00
int len , pid , cc , expected_cc , cc_ok , afc , is_start , is_discontinuity ,
has_adaptation , has_payload ;
2003-06-13 16:28:45 +02:00
const uint8_t * p , * p_end ;
2009-02-28 19:35:53 +01:00
int64_t pos ;
2003-06-13 16:28:45 +02:00
2007-07-06 11:32:34 +02:00
pid = AV_RB16 ( packet + 1 ) & 0x1fff ;
2014-03-17 18:03:07 +01:00
if ( pid & & discard_pid ( ts , pid ) )
2009-05-27 02:56:31 +02:00
return 0 ;
2003-06-13 16:28:45 +02:00
is_start = packet [ 1 ] & 0x40 ;
tss = ts - > pids [ pid ] ;
2014-08-14 22:31:24 +02:00
if ( ts - > auto_guess & & ! tss & & is_start ) {
2009-11-08 04:17:08 +01:00
add_pes_stream ( ts , pid , - 1 ) ;
2003-06-13 16:28:45 +02:00
tss = ts - > pids [ pid ] ;
}
if ( ! tss )
2009-05-27 02:56:31 +02:00
return 0 ;
2012-11-13 15:21:41 +01:00
ts - > current_pid = pid ;
2003-06-13 16:28:45 +02:00
2011-07-24 10:13:50 +02:00
afc = ( packet [ 3 ] > > 4 ) & 3 ;
if ( afc = = 0 ) /* reserved value */
return 0 ;
2014-03-17 18:03:07 +01:00
has_adaptation = afc & 2 ;
has_payload = afc & 1 ;
is_discontinuity = has_adaptation & &
packet [ 4 ] ! = 0 & & /* with length > 0 */
( packet [ 5 ] & 0x80 ) ; /* and discontinuity indicated */
2011-07-24 10:13:50 +02:00
2003-06-13 16:28:45 +02:00
/* continuity check (currently not used) */
cc = ( packet [ 3 ] & 0xf ) ;
2011-07-24 10:13:50 +02:00
expected_cc = has_payload ? ( tss - > last_cc + 1 ) & 0x0f : tss - > last_cc ;
2014-03-17 18:03:07 +01:00
cc_ok = pid = = 0x1FFF | | // null packet PID
is_discontinuity | |
tss - > last_cc < 0 | |
expected_cc = = cc ;
2011-07-24 10:13:50 +02:00
2003-06-13 16:28:45 +02:00
tss - > last_cc = cc ;
2011-07-24 10:13:50 +02:00
if ( ! cc_ok ) {
2011-10-09 22:47:35 +02:00
av_log ( ts - > stream , AV_LOG_DEBUG ,
2011-09-08 19:38:48 +02:00
" Continuity check failed for pid %d expected %d got %d \n " ,
pid , expected_cc , cc ) ;
2014-03-17 18:03:07 +01:00
if ( tss - > type = = MPEGTS_PES ) {
2011-07-24 10:13:50 +02:00
PESContext * pc = tss - > u . pes_filter . opaque ;
pc - > flags | = AV_PKT_FLAG_CORRUPT ;
}
}
2005-12-17 19:14:38 +01:00
2011-07-24 10:13:50 +02:00
p = packet + 4 ;
if ( has_adaptation ) {
2014-08-09 22:47:34 +02:00
int64_t pcr_h ;
int pcr_l ;
if ( parse_pcr ( & pcr_h , & pcr_l , packet ) = = 0 )
tss - > last_pcr = pcr_h * 300 + pcr_l ;
2011-10-29 14:50:34 +02:00
/* skip adaptation field */
2003-06-13 16:28:45 +02:00
p + = p [ 0 ] + 1 ;
}
/* if past the end of packet, ignore */
p_end = packet + TS_PACKET_SIZE ;
2014-08-09 22:47:34 +02:00
if ( p > = p_end | | ! has_payload )
2009-05-27 02:56:31 +02:00
return 0 ;
2005-12-17 19:14:38 +01:00
2011-03-03 20:11:45 +01:00
pos = avio_tell ( ts - > stream - > pb ) ;
2013-09-26 16:43:55 +02:00
if ( pos > = 0 ) {
av_assert0 ( pos > = TS_PACKET_SIZE ) ;
ts - > pos47_full = pos - TS_PACKET_SIZE ;
}
2008-04-23 23:16:25 +02:00
2003-06-13 16:28:45 +02:00
if ( tss - > type = = MPEGTS_SECTION ) {
if ( is_start ) {
/* pointer field present */
len = * p + + ;
if ( p + len > p_end )
2009-05-27 02:56:31 +02:00
return 0 ;
2003-06-13 16:28:45 +02:00
if ( len & & cc_ok ) {
2005-02-17 00:04:11 +01:00
/* write remaining section bytes */
2014-07-08 09:54:15 +02:00
write_section_data ( ts , tss ,
2003-06-13 16:28:45 +02:00
p , len , 0 ) ;
2005-02-17 00:04:11 +01:00
/* check whether filter has been closed */
if ( ! ts - > pids [ pid ] )
2009-05-27 02:56:31 +02:00
return 0 ;
2003-06-13 16:28:45 +02:00
}
p + = len ;
if ( p < p_end ) {
2014-07-08 09:54:15 +02:00
write_section_data ( ts , tss ,
2003-06-13 16:28:45 +02:00
p , p_end - p , 1 ) ;
}
} else {
if ( cc_ok ) {
2014-07-08 09:54:15 +02:00
write_section_data ( ts , tss ,
2003-06-13 16:28:45 +02:00
p , p_end - p , 0 ) ;
2003-07-15 15:21:39 +02:00
}
2003-06-13 16:28:45 +02:00
}
2013-12-15 15:58:31 +01:00
// stop find_stream_info from waiting for more streams
// when all programs have received a PMT
2014-03-18 13:16:56 +01:00
if ( ts - > stream - > ctx_flags & AVFMTCTX_NOHEADER ) {
2013-12-15 15:58:31 +01:00
int i ;
2014-03-18 13:16:56 +01:00
for ( i = 0 ; i < ts - > nb_prg ; i + + ) {
2013-12-15 15:58:31 +01:00
if ( ! ts - > prg [ i ] . pmt_found )
break ;
}
if ( i = = ts - > nb_prg & & ts - > nb_prg > 0 ) {
2014-01-29 05:44:03 +01:00
if ( ts - > stream - > nb_streams > 1 | | pos > 100000 ) {
av_log ( ts - > stream , AV_LOG_DEBUG , " All programs have pmt, headers found \n " ) ;
ts - > stream - > ctx_flags & = ~ AVFMTCTX_NOHEADER ;
}
2013-12-15 15:58:31 +01:00
}
}
2003-06-13 16:28:45 +02:00
} else {
2009-05-27 02:56:31 +02:00
int ret ;
2009-02-28 19:35:53 +01:00
// Note: The position here points actually behind the current packet.
2014-03-02 01:47:17 +01:00
if ( tss - > type = = MPEGTS_PES ) {
if ( ( ret = tss - > u . pes_filter . pes_cb ( tss , p , p_end - p , is_start ,
pos - ts - > raw_packet_size ) ) < 0 )
return ret ;
}
2003-06-13 16:28:45 +02:00
}
2009-05-27 02:56:31 +02:00
return 0 ;
2003-06-13 16:28:45 +02:00
}
2013-08-18 16:35:38 +02:00
static void reanalyze ( MpegTSContext * ts ) {
AVIOContext * pb = ts - > stream - > pb ;
int64_t pos = avio_tell ( pb ) ;
2014-03-18 13:16:56 +01:00
if ( pos < 0 )
2013-08-18 16:35:38 +02:00
return ;
2013-08-18 22:10:41 +02:00
pos - = ts - > pos47_full ;
2013-08-18 16:35:38 +02:00
if ( pos = = TS_PACKET_SIZE ) {
ts - > size_stat [ 0 ] + + ;
} else if ( pos = = TS_DVHS_PACKET_SIZE ) {
ts - > size_stat [ 1 ] + + ;
} else if ( pos = = TS_FEC_PACKET_SIZE ) {
ts - > size_stat [ 2 ] + + ;
}
ts - > size_stat_count + + ;
2014-03-18 13:16:56 +01:00
if ( ts - > size_stat_count > SIZE_STAT_THRESHOLD ) {
2013-08-18 16:35:38 +02:00
int newsize = 0 ;
if ( ts - > size_stat [ 0 ] > SIZE_STAT_THRESHOLD ) {
newsize = TS_PACKET_SIZE ;
} else if ( ts - > size_stat [ 1 ] > SIZE_STAT_THRESHOLD ) {
newsize = TS_DVHS_PACKET_SIZE ;
} else if ( ts - > size_stat [ 2 ] > SIZE_STAT_THRESHOLD ) {
newsize = TS_FEC_PACKET_SIZE ;
}
2013-08-18 21:30:19 +02:00
if ( newsize & & newsize ! = ts - > raw_packet_size ) {
2013-08-18 16:35:38 +02:00
av_log ( ts - > stream , AV_LOG_WARNING , " changing packet size to %d \n " , newsize ) ;
ts - > raw_packet_size = newsize ;
}
ts - > size_stat_count = 0 ;
memset ( ts - > size_stat , 0 , sizeof ( ts - > size_stat ) ) ;
}
}
2003-07-15 15:21:39 +02:00
/* XXX: try to find a better synchro over several packets (use
2014-03-17 18:03:07 +01:00
* get_packet_size ( ) ? ) */
2009-10-18 22:08:13 +02:00
static int mpegts_resync ( AVFormatContext * s )
2003-07-15 15:21:39 +02:00
{
2014-08-25 12:11:32 +02:00
MpegTSContext * ts = s - > priv_data ;
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s - > pb ;
2003-07-15 15:21:39 +02:00
int c , i ;
2014-08-25 12:11:32 +02:00
for ( i = 0 ; i < ts - > resync_size ; i + + ) {
2011-03-06 19:59:29 +01:00
c = avio_r8 ( pb ) ;
2014-08-07 22:12:41 +02:00
if ( avio_feof ( pb ) )
2014-03-17 18:03:08 +01:00
return AVERROR_EOF ;
2003-07-15 15:21:39 +02:00
if ( c = = 0x47 ) {
2011-02-28 14:57:54 +01:00
avio_seek ( pb , - 1 , SEEK_CUR ) ;
2013-08-18 16:35:38 +02:00
reanalyze ( s - > priv_data ) ;
2003-07-15 15:21:39 +02:00
return 0 ;
}
}
2014-03-17 18:03:07 +01:00
av_log ( s , AV_LOG_ERROR ,
" max resync size reached, could not find sync byte \n " ) ;
2003-07-15 15:21:39 +02:00
/* no sync found */
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2003-07-15 15:21:39 +02:00
}
2014-03-17 18:03:08 +01:00
/* return AVERROR_something if error or EOF. Return 0 if OK. */
2014-03-17 18:03:07 +01:00
static int read_packet ( AVFormatContext * s , uint8_t * buf , int raw_packet_size ,
const uint8_t * * data )
2003-06-13 16:28:45 +02:00
{
2011-02-20 11:04:12 +01:00
AVIOContext * pb = s - > pb ;
2013-08-01 00:46:08 +02:00
int len ;
2003-10-29 15:16:31 +01:00
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
2013-08-01 00:46:08 +02:00
len = ffio_read_indirect ( pb , buf , TS_PACKET_SIZE , data ) ;
2003-10-29 15:16:31 +01:00
if ( len ! = TS_PACKET_SIZE )
2011-03-31 16:58:50 +02:00
return len < 0 ? len : AVERROR_EOF ;
2011-10-29 14:50:34 +02:00
/* check packet sync byte */
2013-08-01 00:46:08 +02:00
if ( ( * data ) [ 0 ] ! = 0x47 ) {
2003-10-29 15:16:31 +01:00
/* find a new packet start */
2013-11-18 16:38:12 +01:00
uint64_t pos = avio_tell ( pb ) ;
avio_seek ( pb , - FFMIN ( raw_packet_size , pos ) , SEEK_CUR ) ;
2009-10-18 22:08:13 +02:00
if ( mpegts_resync ( s ) < 0 )
return AVERROR ( EAGAIN ) ;
2003-10-29 15:16:31 +01:00
else
continue ;
} else {
break ;
}
}
return 0 ;
}
2013-08-01 00:46:08 +02:00
static void finished_reading_packet ( AVFormatContext * s , int raw_packet_size )
{
AVIOContext * pb = s - > pb ;
int skip = raw_packet_size - TS_PACKET_SIZE ;
if ( skip > 0 )
avio_skip ( pb , skip ) ;
}
2014-07-30 11:09:25 +02:00
static int handle_packets ( MpegTSContext * ts , int64_t nb_packets )
2003-10-29 15:16:31 +01:00
{
AVFormatContext * s = ts - > stream ;
2012-03-03 21:03:11 +01:00
uint8_t packet [ TS_PACKET_SIZE + FF_INPUT_BUFFER_PADDING_SIZE ] ;
2013-08-08 00:22:38 +02:00
const uint8_t * data ;
2014-07-30 11:09:25 +02:00
int64_t packet_num ;
int ret = 0 ;
2011-07-24 10:13:50 +02:00
if ( avio_tell ( s - > pb ) ! = ts - > last_pos ) {
int i ;
2011-09-13 17:00:16 +02:00
av_dlog ( ts - > stream , " Skipping after seek \n " ) ;
2011-07-24 10:13:50 +02:00
/* seek detected, flush pes buffer */
for ( i = 0 ; i < NB_PID_MAX ; i + + ) {
2011-09-08 15:18:48 +02:00
if ( ts - > pids [ i ] ) {
if ( ts - > pids [ i ] - > type = = MPEGTS_PES ) {
2014-03-17 18:03:07 +01:00
PESContext * pes = ts - > pids [ i ] - > u . pes_filter . opaque ;
av_buffer_unref ( & pes - > buffer ) ;
pes - > data_index = 0 ;
pes - > state = MPEGTS_SKIP ; /* skip until pes header */
2011-09-08 15:18:48 +02:00
}
2011-07-24 10:13:50 +02:00
ts - > pids [ i ] - > last_cc = - 1 ;
2014-03-02 14:12:50 +01:00
ts - > pids [ i ] - > last_pcr = - 1 ;
2011-07-24 10:13:50 +02:00
}
}
}
2003-06-13 16:28:45 +02:00
ts - > stop_parse = 0 ;
packet_num = 0 ;
2012-03-02 19:13:07 +01:00
memset ( packet + TS_PACKET_SIZE , 0 , FF_INPUT_BUFFER_PADDING_SIZE ) ;
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
2003-06-13 16:28:45 +02:00
packet_num + + ;
2011-10-08 23:40:40 +02:00
if ( nb_packets ! = 0 & & packet_num > = nb_packets | |
ts - > stop_parse > 1 ) {
ret = AVERROR ( EAGAIN ) ;
break ;
}
if ( ts - > stop_parse > 0 )
2003-06-13 16:28:45 +02:00
break ;
2011-10-08 23:40:40 +02:00
2013-08-01 00:46:08 +02:00
ret = read_packet ( s , packet , ts - > raw_packet_size , & data ) ;
2003-10-29 15:16:31 +01:00
if ( ret ! = 0 )
2011-07-24 10:13:50 +02:00
break ;
2013-08-01 00:46:08 +02:00
ret = handle_packet ( ts , data ) ;
finished_reading_packet ( s , ts - > raw_packet_size ) ;
2009-05-27 02:56:31 +02:00
if ( ret ! = 0 )
2011-07-24 10:13:50 +02:00
break ;
2003-06-13 16:28:45 +02:00
}
2011-07-24 10:13:50 +02:00
ts - > last_pos = avio_tell ( s - > pb ) ;
return ret ;
2003-06-13 16:28:45 +02:00
}
2002-05-20 18:27:23 +02:00
2003-06-13 16:28:45 +02:00
static int mpegts_probe ( AVProbeData * p )
{
2014-03-17 18:03:07 +01:00
const int size = p - > buf_size ;
2014-03-18 13:16:56 +01:00
int maxscore = 0 ;
int sumscore = 0 ;
2012-11-01 17:22:04 +01:00
int i ;
2014-03-17 18:03:07 +01:00
int check_count = size / TS_FEC_PACKET_SIZE ;
2003-12-09 01:17:43 +01:00
# define CHECK_COUNT 10
2012-11-01 17:22:04 +01:00
# define CHECK_BLOCK 100
2005-12-17 19:14:38 +01:00
2009-02-03 12:01:57 +01:00
if ( check_count < CHECK_COUNT )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2005-12-17 19:14:38 +01:00
2014-03-18 13:16:56 +01:00
for ( i = 0 ; i < check_count ; i + = CHECK_BLOCK ) {
2012-11-01 17:22:04 +01:00
int left = FFMIN ( check_count - i , CHECK_BLOCK ) ;
2014-03-18 13:16:56 +01:00
int score = analyze ( p - > buf + TS_PACKET_SIZE * i , TS_PACKET_SIZE * left , TS_PACKET_SIZE , NULL ) ;
int dvhs_score = analyze ( p - > buf + TS_DVHS_PACKET_SIZE * i , TS_DVHS_PACKET_SIZE * left , TS_DVHS_PACKET_SIZE , NULL ) ;
int fec_score = analyze ( p - > buf + TS_FEC_PACKET_SIZE * i , TS_FEC_PACKET_SIZE * left , TS_FEC_PACKET_SIZE , NULL ) ;
2012-11-01 17:22:04 +01:00
score = FFMAX3 ( score , dvhs_score , fec_score ) ;
sumscore + = score ;
maxscore = FFMAX ( maxscore , score ) ;
}
2014-03-18 13:16:56 +01:00
sumscore = sumscore * CHECK_COUNT / check_count ;
maxscore = maxscore * CHECK_COUNT / CHECK_BLOCK ;
2012-11-01 17:22:04 +01:00
av_dlog ( 0 , " TS score: %d %d \n " , sumscore , maxscore ) ;
2005-12-17 19:14:38 +01:00
2014-03-18 13:16:56 +01:00
if ( sumscore > 6 ) return AVPROBE_SCORE_MAX + sumscore - CHECK_COUNT ;
else if ( maxscore > 6 ) return AVPROBE_SCORE_MAX / 2 + sumscore - CHECK_COUNT ;
2014-03-17 18:03:07 +01:00
else
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2003-06-13 16:28:45 +02:00
}
2008-10-02 18:28:58 +02:00
/* return the 90kHz PCR and the extension for the 27MHz PCR. return
2014-03-17 18:03:07 +01:00
* ( - 1 ) if not available */
static int parse_pcr ( int64_t * ppcr_high , int * ppcr_low , const uint8_t * packet )
2003-10-29 15:16:31 +01:00
{
int afc , len , flags ;
const uint8_t * p ;
unsigned int v ;
afc = ( packet [ 3 ] > > 4 ) & 3 ;
if ( afc < = 1 )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2014-03-17 18:03:07 +01:00
p = packet + 4 ;
2003-10-29 15:16:31 +01:00
len = p [ 0 ] ;
p + + ;
if ( len = = 0 )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2003-10-29 15:16:31 +01:00
flags = * p + + ;
len - - ;
if ( ! ( flags & 0x10 ) )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2003-10-29 15:16:31 +01:00
if ( len < 6 )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2014-03-17 18:03:07 +01:00
v = AV_RB32 ( p ) ;
* ppcr_high = ( ( int64_t ) v < < 1 ) | ( p [ 4 ] > > 7 ) ;
* ppcr_low = ( ( p [ 4 ] & 1 ) < < 8 ) | p [ 5 ] ;
2003-10-29 15:16:31 +01:00
return 0 ;
}
2013-06-30 15:45:23 +02:00
static void seek_back ( AVFormatContext * s , AVIOContext * pb , int64_t pos ) {
/* NOTE: We attempt to seek on non-seekable files as well, as the
* probe buffer usually is big enough . Only warn if the seek failed
* on files where the seek should work . */
if ( avio_seek ( pb , pos , SEEK_SET ) < 0 )
av_log ( s , pb - > seekable ? AV_LOG_ERROR : AV_LOG_INFO , " Unable to seek back to the start \n " ) ;
}
2012-01-12 13:20:36 +01:00
static int mpegts_read_header ( AVFormatContext * s )
2003-06-13 16:28:45 +02:00
{
MpegTSContext * ts = s - > priv_data ;
2014-03-17 18:03:07 +01:00
AVIOContext * pb = s - > pb ;
2014-03-18 13:16:56 +01:00
uint8_t buf [ 8 * 1024 ] = { 0 } ;
2007-06-04 16:20:07 +02:00
int len ;
2014-07-30 11:09:25 +02:00
int64_t pos , probesize = s - > probesize ? s - > probesize : s - > probesize2 ;
2004-05-31 18:57:00 +02:00
2014-07-30 11:09:25 +02:00
ffio_ensure_seekback ( pb , probesize ) ;
2013-06-30 18:18:48 +02:00
2011-09-11 00:55:16 +02:00
/* read the first 8192 bytes to get packet size */
2011-03-03 20:11:45 +01:00
pos = avio_tell ( pb ) ;
2011-02-21 16:43:01 +01:00
len = avio_read ( pb , buf , sizeof ( buf ) ) ;
2012-05-14 02:38:13 +02:00
ts - > raw_packet_size = get_packet_size ( buf , len ) ;
2011-04-24 17:33:48 +02:00
if ( ts - > raw_packet_size < = 0 ) {
av_log ( s , AV_LOG_WARNING , " Could not detect TS packet size, defaulting to non-FEC/DVHS \n " ) ;
ts - > raw_packet_size = TS_PACKET_SIZE ;
}
2014-03-17 18:03:07 +01:00
ts - > stream = s ;
2003-06-13 16:28:45 +02:00
ts - > auto_guess = 0 ;
2011-01-25 23:03:28 +01:00
if ( s - > iformat = = & ff_mpegts_demuxer ) {
2003-10-29 15:16:31 +01:00
/* normal demux */
2003-07-15 15:21:39 +02:00
2011-10-05 14:12:42 +02:00
/* first do a scan to get all the services */
2013-06-30 15:45:23 +02:00
seek_back ( s , pb , pos ) ;
2009-04-12 11:04:12 +02:00
mpegts_open_section_filter ( ts , SDT_PID , sdt_cb , ts , 1 ) ;
2005-12-17 19:14:38 +01:00
2009-04-12 10:52:16 +02:00
mpegts_open_section_filter ( ts , PAT_PID , pat_cb , ts , 1 ) ;
2005-12-17 19:14:38 +01:00
2014-07-30 11:09:25 +02:00
handle_packets ( ts , probesize / ts - > raw_packet_size ) ;
2007-06-04 10:53:08 +02:00
/* if could not find service, enable auto_guess */
2005-12-17 19:14:38 +01:00
2007-06-04 10:53:08 +02:00
ts - > auto_guess = 1 ;
2005-12-17 19:14:38 +01:00
2011-01-29 17:46:18 +01:00
av_dlog ( ts - > stream , " tuning done \n " ) ;
2009-04-12 05:08:46 +02:00
2003-10-29 15:16:31 +01:00
s - > ctx_flags | = AVFMTCTX_NOHEADER ;
} else {
AVStream * st ;
int pcr_pid , pid , nb_packets , nb_pcrs , ret , pcr_l ;
int64_t pcrs [ 2 ] , pcr_h ;
int packet_count [ 2 ] ;
uint8_t packet [ TS_PACKET_SIZE ] ;
2013-08-08 00:22:38 +02:00
const uint8_t * data ;
2005-12-17 19:14:38 +01:00
2003-10-29 15:16:31 +01:00
/* only read packets */
2005-12-17 19:14:38 +01:00
2011-06-18 11:43:24 +02:00
st = avformat_new_stream ( s , NULL ) ;
2003-10-29 15:16:31 +01:00
if ( ! st )
2014-03-17 18:03:08 +01:00
return AVERROR ( ENOMEM ) ;
2011-11-29 19:28:15 +01:00
avpriv_set_pts_info ( st , 60 , 1 , 27000000 ) ;
2010-03-31 01:30:55 +02:00
st - > codec - > codec_type = AVMEDIA_TYPE_DATA ;
2014-03-17 18:03:07 +01:00
st - > codec - > codec_id = AV_CODEC_ID_MPEG2TS ;
2005-12-17 19:14:38 +01:00
2003-10-29 15:16:31 +01:00
/* we iterate until we find two PCRs to estimate the bitrate */
2014-03-17 18:03:07 +01:00
pcr_pid = - 1 ;
nb_pcrs = 0 ;
2003-10-29 15:16:31 +01:00
nb_packets = 0 ;
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
2013-08-01 00:46:08 +02:00
ret = read_packet ( s , packet , ts - > raw_packet_size , & data ) ;
2003-10-29 15:16:31 +01:00
if ( ret < 0 )
2014-03-17 18:03:08 +01:00
return ret ;
2013-08-01 00:46:08 +02:00
pid = AV_RB16 ( data + 1 ) & 0x1fff ;
2003-10-29 15:16:31 +01:00
if ( ( pcr_pid = = - 1 | | pcr_pid = = pid ) & &
2013-08-01 00:46:08 +02:00
parse_pcr ( & pcr_h , & pcr_l , data ) = = 0 ) {
finished_reading_packet ( s , ts - > raw_packet_size ) ;
2003-10-29 15:16:31 +01:00
pcr_pid = pid ;
packet_count [ nb_pcrs ] = nb_packets ;
pcrs [ nb_pcrs ] = pcr_h * 300 + pcr_l ;
nb_pcrs + + ;
if ( nb_pcrs > = 2 )
break ;
2013-08-01 00:46:08 +02:00
} else {
finished_reading_packet ( s , ts - > raw_packet_size ) ;
2003-10-29 15:16:31 +01:00
}
nb_packets + + ;
}
2003-06-13 16:28:45 +02:00
2003-10-29 15:16:31 +01:00
/* NOTE1: the bitrate is computed without the FEC */
/* NOTE2: it is only the bitrate of the start of the stream */
ts - > pcr_incr = ( pcrs [ 1 ] - pcrs [ 0 ] ) / ( packet_count [ 1 ] - packet_count [ 0 ] ) ;
2014-03-17 18:03:07 +01:00
ts - > cur_pcr = pcrs [ 0 ] - ts - > pcr_incr * packet_count [ 0 ] ;
s - > bit_rate = TS_PACKET_SIZE * 8 * 27e6 / ts - > pcr_incr ;
2005-07-18 00:24:36 +02:00
st - > codec - > bit_rate = s - > bit_rate ;
2014-03-17 18:03:07 +01:00
st - > start_time = ts - > cur_pcr ;
2011-06-02 20:40:09 +02:00
av_dlog ( ts - > stream , " start=%0.3f pcr=%0.3f incr=%d \n " ,
2011-04-29 17:27:01 +02:00
st - > start_time / 1000000.0 , pcrs [ 0 ] / 27e6 , ts - > pcr_incr ) ;
2002-05-20 18:27:23 +02:00
}
2003-06-13 16:28:45 +02:00
2013-06-30 15:46:04 +02:00
seek_back ( s , pb , pos ) ;
2002-05-20 18:27:23 +02:00
return 0 ;
2003-06-13 16:28:45 +02:00
}
2003-10-29 15:16:31 +01:00
# define MAX_PACKET_READAHEAD ((128 * 1024) / 188)
2014-03-17 18:03:07 +01:00
static int mpegts_raw_read_packet ( AVFormatContext * s , AVPacket * pkt )
2003-10-29 15:16:31 +01:00
{
MpegTSContext * ts = s - > priv_data ;
int ret , i ;
int64_t pcr_h , next_pcr_h , pos ;
int pcr_l , next_pcr_l ;
uint8_t pcr_buf [ 12 ] ;
2013-08-08 00:22:38 +02:00
const uint8_t * data ;
2003-10-29 15:16:31 +01:00
if ( av_new_packet ( pkt , TS_PACKET_SIZE ) < 0 )
2007-02-13 19:26:14 +01:00
return AVERROR ( ENOMEM ) ;
2013-08-01 00:46:08 +02:00
ret = read_packet ( s , pkt - > data , ts - > raw_packet_size , & data ) ;
2014-03-17 18:03:07 +01:00
pkt - > pos = avio_tell ( s - > pb ) ;
2003-10-29 15:16:31 +01:00
if ( ret < 0 ) {
av_free_packet ( pkt ) ;
return ret ;
}
2013-08-01 00:46:08 +02:00
if ( data ! = pkt - > data )
memcpy ( pkt - > data , data , ts - > raw_packet_size ) ;
finished_reading_packet ( s , ts - > raw_packet_size ) ;
2003-10-29 15:16:31 +01:00
if ( ts - > mpeg2ts_compute_pcr ) {
/* compute exact PCR for each packet */
if ( parse_pcr ( & pcr_h , & pcr_l , pkt - > data ) = = 0 ) {
/* we read the next PCR (XXX: optimize it by using a bigger buffer */
2011-03-03 20:11:45 +01:00
pos = avio_tell ( s - > pb ) ;
2014-03-17 18:03:07 +01:00
for ( i = 0 ; i < MAX_PACKET_READAHEAD ; i + + ) {
2011-02-28 14:57:54 +01:00
avio_seek ( s - > pb , pos + i * ts - > raw_packet_size , SEEK_SET ) ;
2011-02-21 16:43:01 +01:00
avio_read ( s - > pb , pcr_buf , 12 ) ;
2003-10-29 15:16:31 +01:00
if ( parse_pcr ( & next_pcr_h , & next_pcr_l , pcr_buf ) = = 0 ) {
/* XXX: not precise enough */
2014-03-17 18:03:07 +01:00
ts - > pcr_incr =
( ( next_pcr_h - pcr_h ) * 300 + ( next_pcr_l - pcr_l ) ) /
2003-10-29 15:16:31 +01:00
( i + 1 ) ;
break ;
}
}
2011-02-28 14:57:54 +01:00
avio_seek ( s - > pb , pos , SEEK_SET ) ;
2003-10-29 15:16:31 +01:00
/* no next PCR found: we use previous increment */
ts - > cur_pcr = pcr_h * 300 + pcr_l ;
}
2014-03-17 18:03:07 +01:00
pkt - > pts = ts - > cur_pcr ;
2003-10-29 15:16:31 +01:00
pkt - > duration = ts - > pcr_incr ;
2014-03-17 18:03:07 +01:00
ts - > cur_pcr + = ts - > pcr_incr ;
2003-10-29 15:16:31 +01:00
}
pkt - > stream_index = 0 ;
return 0 ;
}
2014-03-17 18:03:07 +01:00
static int mpegts_read_packet ( AVFormatContext * s , AVPacket * pkt )
2003-06-13 16:28:45 +02:00
{
MpegTSContext * ts = s - > priv_data ;
2009-05-27 02:44:00 +02:00
int ret , i ;
2012-04-21 19:44:24 +02:00
pkt - > size = - 1 ;
2007-06-02 22:57:31 +02:00
ts - > pkt = pkt ;
2009-05-27 02:44:00 +02:00
ret = handle_packets ( ts , 0 ) ;
if ( ret < 0 ) {
2012-09-08 04:32:25 +02:00
av_free_packet ( ts - > pkt ) ;
2009-05-27 02:44:00 +02:00
/* flush pes data left */
2014-03-17 18:03:07 +01:00
for ( i = 0 ; i < NB_PID_MAX ; i + + )
2009-05-27 02:44:00 +02:00
if ( ts - > pids [ i ] & & ts - > pids [ i ] - > type = = MPEGTS_PES ) {
PESContext * pes = ts - > pids [ i ] - > u . pes_filter . opaque ;
if ( pes - > state = = MPEGTS_PAYLOAD & & pes - > data_index > 0 ) {
new_pes_packet ( pes , pkt ) ;
2009-09-13 22:06:49 +02:00
pes - > state = MPEGTS_SKIP ;
2009-05-27 02:44:00 +02:00
ret = 0 ;
break ;
}
}
}
2012-04-21 19:44:24 +02:00
if ( ! ret & & pkt - > size < 0 )
ret = AVERROR ( EINTR ) ;
2009-05-27 02:44:00 +02:00
return ret ;
2002-05-20 18:27:23 +02:00
}
2013-01-20 00:59:08 +01:00
static void mpegts_free ( MpegTSContext * ts )
2002-05-20 18:27:23 +02:00
{
int i ;
2008-04-25 00:16:00 +02:00
clear_programs ( ts ) ;
2014-03-17 18:03:07 +01:00
for ( i = 0 ; i < NB_PID_MAX ; i + + )
if ( ts - > pids [ i ] )
mpegts_close_filter ( ts , ts - > pids [ i ] ) ;
2013-01-20 00:59:08 +01:00
}
2006-04-01 20:19:00 +02:00
2013-01-20 00:59:08 +01:00
static int mpegts_read_close ( AVFormatContext * s )
{
MpegTSContext * ts = s - > priv_data ;
mpegts_free ( ts ) ;
2002-05-20 18:27:23 +02:00
return 0 ;
}
2012-04-02 21:33:42 +02:00
static av_unused int64_t mpegts_get_pcr ( AVFormatContext * s , int stream_index ,
2004-05-23 18:26:12 +02:00
int64_t * ppos , int64_t pos_limit )
2003-11-10 19:47:52 +01:00
{
MpegTSContext * ts = s - > priv_data ;
int64_t pos , timestamp ;
uint8_t buf [ TS_PACKET_SIZE ] ;
2014-03-17 18:03:07 +01:00
int pcr_l , pcr_pid =
( ( PESContext * ) s - > streams [ stream_index ] - > priv_data ) - > pcr_pid ;
2013-08-06 19:56:20 +02:00
int pos47 = ts - > pos47_full % ts - > raw_packet_size ;
2014-03-17 18:03:07 +01:00
pos =
2014-03-18 13:16:56 +01:00
( ( * ppos + ts - > raw_packet_size - 1 - pos47 ) / ts - > raw_packet_size ) *
ts - > raw_packet_size + pos47 ;
2008-08-27 20:08:20 +02:00
while ( pos < pos_limit ) {
if ( avio_seek ( s - > pb , pos , SEEK_SET ) < 0 )
return AV_NOPTS_VALUE ;
if ( avio_read ( s - > pb , buf , TS_PACKET_SIZE ) ! = TS_PACKET_SIZE )
return AV_NOPTS_VALUE ;
2008-08-27 20:44:16 +02:00
if ( buf [ 0 ] ! = 0x47 ) {
2013-08-18 22:31:19 +02:00
avio_seek ( s - > pb , - TS_PACKET_SIZE , SEEK_CUR ) ;
2011-10-21 16:10:16 +02:00
if ( mpegts_resync ( s ) < 0 )
2008-08-27 20:44:16 +02:00
return AV_NOPTS_VALUE ;
2011-11-14 01:23:00 +01:00
pos = avio_tell ( s - > pb ) ;
2008-08-27 20:44:16 +02:00
continue ;
}
2008-08-27 20:08:20 +02:00
if ( ( pcr_pid < 0 | | ( AV_RB16 ( buf + 1 ) & 0x1fff ) = = pcr_pid ) & &
parse_pcr ( & timestamp , & pcr_l , buf ) = = 0 ) {
* ppos = pos ;
return timestamp ;
2003-11-10 19:47:52 +01:00
}
2008-08-27 20:08:20 +02:00
pos + = ts - > raw_packet_size ;
}
2003-11-10 19:47:52 +01:00
2008-08-27 20:07:11 +02:00
return AV_NOPTS_VALUE ;
2003-11-10 19:47:52 +01:00
}
2011-10-21 16:11:00 +02:00
static int64_t mpegts_get_dts ( AVFormatContext * s , int stream_index ,
int64_t * ppos , int64_t pos_limit )
{
MpegTSContext * ts = s - > priv_data ;
2011-12-30 21:08:08 +01:00
int64_t pos ;
2013-08-06 19:56:20 +02:00
int pos47 = ts - > pos47_full % ts - > raw_packet_size ;
pos = ( ( * ppos + ts - > raw_packet_size - 1 - pos47 ) / ts - > raw_packet_size ) * ts - > raw_packet_size + pos47 ;
2011-10-21 16:11:00 +02:00
ff_read_frame_flush ( s ) ;
if ( avio_seek ( s - > pb , pos , SEEK_SET ) < 0 )
return AV_NOPTS_VALUE ;
while ( pos < pos_limit ) {
int ret ;
AVPacket pkt ;
av_init_packet ( & pkt ) ;
2014-03-18 13:16:56 +01:00
ret = av_read_frame ( s , & pkt ) ;
if ( ret < 0 )
2011-10-21 16:11:00 +02:00
return AV_NOPTS_VALUE ;
av_free_packet ( & pkt ) ;
2014-03-18 13:16:56 +01:00
if ( pkt . dts ! = AV_NOPTS_VALUE & & pkt . pos > = 0 ) {
2011-10-21 21:11:28 +02:00
ff_reduce_index ( s , pkt . stream_index ) ;
av_add_index_entry ( s - > streams [ pkt . stream_index ] , pkt . pos , pkt . dts , 0 , 0 , AVINDEX_KEYFRAME /* FIXME keyframe? */ ) ;
2014-03-18 13:16:56 +01:00
if ( pkt . stream_index = = stream_index & & pkt . pos > = * ppos ) {
* ppos = pkt . pos ;
2011-10-21 21:11:28 +02:00
return pkt . dts ;
}
2011-10-21 16:11:00 +02:00
}
pos = pkt . pos ;
}
return AV_NOPTS_VALUE ;
}
2003-10-29 15:16:31 +01:00
/**************************************************************/
/* parsing functions - called from other demuxers such as RTP */
2014-08-07 01:59:56 +02:00
MpegTSContext * avpriv_mpegts_parse_open ( AVFormatContext * s )
2003-10-29 15:16:31 +01:00
{
MpegTSContext * ts ;
2005-12-17 19:14:38 +01:00
2003-10-29 15:16:31 +01:00
ts = av_mallocz ( sizeof ( MpegTSContext ) ) ;
if ( ! ts )
return NULL ;
/* no stream case, currently used by RTP */
ts - > raw_packet_size = TS_PACKET_SIZE ;
ts - > stream = s ;
ts - > auto_guess = 1 ;
2011-09-11 20:10:22 +02:00
mpegts_open_section_filter ( ts , SDT_PID , sdt_cb , ts , 1 ) ;
mpegts_open_section_filter ( ts , PAT_PID , pat_cb , ts , 1 ) ;
2003-10-29 15:16:31 +01:00
return ts ;
}
/* return the consumed length if a packet was output, or -1 if no
2014-03-17 18:03:07 +01:00
* packet is output */
2014-08-07 01:59:56 +02:00
int avpriv_mpegts_parse_packet ( MpegTSContext * ts , AVPacket * pkt ,
const uint8_t * buf , int len )
2003-10-29 15:16:31 +01:00
{
int len1 ;
len1 = len ;
ts - > pkt = pkt ;
2014-03-17 18:03:07 +01:00
for ( ; ; ) {
2011-10-08 23:40:41 +02:00
ts - > stop_parse = 0 ;
2003-10-29 15:16:31 +01:00
if ( len < TS_PACKET_SIZE )
2014-03-17 18:03:08 +01:00
return AVERROR_INVALIDDATA ;
2003-10-29 15:16:31 +01:00
if ( buf [ 0 ] ! = 0x47 ) {
2004-04-13 15:33:02 +02:00
buf + + ;
2003-10-29 15:16:31 +01:00
len - - ;
} else {
handle_packet ( ts , buf ) ;
buf + = TS_PACKET_SIZE ;
len - = TS_PACKET_SIZE ;
2011-10-08 23:40:41 +02:00
if ( ts - > stop_parse = = 1 )
break ;
2003-10-29 15:16:31 +01:00
}
}
return len1 - len ;
}
2014-08-07 01:59:56 +02:00
void avpriv_mpegts_parse_close ( MpegTSContext * ts )
2003-10-29 15:16:31 +01:00
{
2013-01-20 00:59:08 +01:00
mpegts_free ( ts ) ;
2003-10-29 15:16:31 +01:00
av_free ( ts ) ;
}
2011-01-25 23:03:28 +01:00
AVInputFormat ff_mpegts_demuxer = {
2011-07-16 22:18:12 +02:00
. name = " mpegts " ,
2012-07-24 03:23:48 +02:00
. long_name = NULL_IF_CONFIG_SMALL ( " MPEG-TS (MPEG-2 Transport Stream) " ) ,
2011-07-16 22:18:12 +02:00
. priv_data_size = sizeof ( MpegTSContext ) ,
. read_probe = mpegts_probe ,
. read_header = mpegts_read_header ,
. read_packet = mpegts_read_packet ,
. read_close = mpegts_read_close ,
2011-10-21 16:11:00 +02:00
. read_timestamp = mpegts_get_dts ,
2012-04-06 16:50:48 +02:00
. flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT ,
2013-08-04 04:17:22 +02:00
. priv_class = & mpegts_class ,
2002-05-20 18:27:23 +02:00
} ;
2007-06-02 22:57:31 +02:00
2011-01-25 23:03:28 +01:00
AVInputFormat ff_mpegtsraw_demuxer = {
2011-07-16 22:18:12 +02:00
. name = " mpegtsraw " ,
2012-07-24 03:23:48 +02:00
. long_name = NULL_IF_CONFIG_SMALL ( " raw MPEG-TS (MPEG-2 Transport Stream) " ) ,
2011-07-16 22:18:12 +02:00
. priv_data_size = sizeof ( MpegTSContext ) ,
. read_header = mpegts_read_header ,
. read_packet = mpegts_raw_read_packet ,
. read_close = mpegts_read_close ,
2011-10-21 16:11:00 +02:00
. read_timestamp = mpegts_get_dts ,
2012-04-06 16:50:48 +02:00
. flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT ,
. priv_class = & mpegtsraw_class ,
2007-06-02 22:57:31 +02:00
} ;