|
|
|
@@ -76,6 +76,13 @@ struct MpegTSFilter { |
|
|
|
} u; |
|
|
|
}; |
|
|
|
|
|
|
|
#define MAX_PIDS_PER_PROGRAM 64 |
|
|
|
typedef struct { |
|
|
|
unsigned int id; //program id/service id |
|
|
|
unsigned int nb_pids; |
|
|
|
unsigned int pids[MAX_PIDS_PER_PROGRAM]; |
|
|
|
} Program_t; |
|
|
|
|
|
|
|
struct MpegTSContext { |
|
|
|
/* user data */ |
|
|
|
AVFormatContext *stream; |
|
|
|
@@ -99,6 +106,9 @@ struct MpegTSContext { |
|
|
|
/******************************************/ |
|
|
|
/* private mpegts data */ |
|
|
|
/* scan context */ |
|
|
|
/** structure to keep track of Program->pids mapping */ |
|
|
|
unsigned int nb_prg; |
|
|
|
Program_t *prg; |
|
|
|
|
|
|
|
|
|
|
|
/** filters for various streams specified by PMT + for the PAT and PMT */ |
|
|
|
@@ -136,6 +146,85 @@ struct PESContext { |
|
|
|
|
|
|
|
extern AVInputFormat mpegts_demuxer; |
|
|
|
|
|
|
|
static void clear_program(MpegTSContext *ts, unsigned int programid) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
for(i=0; i<ts->nb_prg; i++) |
|
|
|
if(ts->prg[i].id == programid) |
|
|
|
ts->prg[i].nb_pids = 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void clear_programs(MpegTSContext *ts) |
|
|
|
{ |
|
|
|
av_freep(&ts->prg); |
|
|
|
ts->nb_prg=0; |
|
|
|
} |
|
|
|
|
|
|
|
static void add_pat_entry(MpegTSContext *ts, unsigned int programid) |
|
|
|
{ |
|
|
|
Program_t *p; |
|
|
|
void *tmp = av_realloc(ts->prg, (ts->nb_prg+1)*sizeof(Program_t)); |
|
|
|
if(!tmp) |
|
|
|
return; |
|
|
|
ts->prg = tmp; |
|
|
|
p = &ts->prg[ts->nb_prg]; |
|
|
|
p->id = programid; |
|
|
|
p->nb_pids = 0; |
|
|
|
ts->nb_prg++; |
|
|
|
} |
|
|
|
|
|
|
|
static void add_pid_to_pmt(MpegTSContext *ts, unsigned int programid, unsigned int pid) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
Program_t *p = NULL; |
|
|
|
for(i=0; i<ts->nb_prg; i++) { |
|
|
|
if(ts->prg[i].id == programid) { |
|
|
|
p = &ts->prg[i]; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if(!p) |
|
|
|
return; |
|
|
|
|
|
|
|
if(p->nb_pids >= MAX_PIDS_PER_PROGRAM) |
|
|
|
return; |
|
|
|
p->pids[p->nb_pids++] = pid; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* \brief discard_pid() decides if the pid is to be discarded according |
|
|
|
* to caller's programs selection |
|
|
|
* \param ts : - TS context |
|
|
|
* \param pid : - pid |
|
|
|
* \return 1 if the pid is only comprised in programs that have .discard=AVDISCARD_ALL |
|
|
|
* 0 otherwise |
|
|
|
*/ |
|
|
|
static int discard_pid(MpegTSContext *ts, unsigned int pid) |
|
|
|
{ |
|
|
|
int i, j, k; |
|
|
|
int used = 0, discarded = 0; |
|
|
|
Program_t *p; |
|
|
|
for(i=0; i<ts->nb_prg; i++) { |
|
|
|
p = &ts->prg[i]; |
|
|
|
for(j=0; j<p->nb_pids; j++) { |
|
|
|
if(p->pids[j] != pid) |
|
|
|
continue; |
|
|
|
//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) |
|
|
|
discarded++; |
|
|
|
else |
|
|
|
used++; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return (!used && discarded); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Assembles PES packets out of TS packets, and then calls the "section_cb" |
|
|
|
* function when they are complete. |
|
|
|
@@ -403,9 +492,11 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len |
|
|
|
if (h->tid != PMT_TID) |
|
|
|
return; |
|
|
|
|
|
|
|
clear_program(ts, h->id); |
|
|
|
pcr_pid = get16(&p, p_end) & 0x1fff; |
|
|
|
if (pcr_pid < 0) |
|
|
|
return; |
|
|
|
add_pid_to_pmt(ts, h->id, pcr_pid); |
|
|
|
#ifdef DEBUG_SI |
|
|
|
av_log(ts->stream, AV_LOG_DEBUG, "pcr_pid=0x%x\n", pcr_pid); |
|
|
|
#endif |
|
|
|
@@ -505,6 +596,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len |
|
|
|
if (pes) |
|
|
|
st = new_pes_av_stream(pes, 0); |
|
|
|
} |
|
|
|
add_pid_to_pmt(ts, h->id, pid); |
|
|
|
break; |
|
|
|
default: |
|
|
|
/* we ignore the other streams */ |
|
|
|
@@ -544,6 +636,7 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len |
|
|
|
if (h->tid != PAT_TID) |
|
|
|
return; |
|
|
|
|
|
|
|
clear_programs(ts); |
|
|
|
for(;;) { |
|
|
|
sid = get16(&p, p_end); |
|
|
|
if (sid < 0) |
|
|
|
@@ -560,6 +653,9 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len |
|
|
|
av_new_program(ts->stream, sid); |
|
|
|
ts->stop_parse--; |
|
|
|
mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1); |
|
|
|
add_pat_entry(ts, sid); |
|
|
|
add_pid_to_pmt(ts, sid, 0); //add pat pid to program |
|
|
|
add_pid_to_pmt(ts, sid, pmt_pid); |
|
|
|
} |
|
|
|
} |
|
|
|
/* not found */ |
|
|
|
@@ -887,6 +983,8 @@ static void handle_packet(MpegTSContext *ts, const uint8_t *packet) |
|
|
|
const uint8_t *p, *p_end; |
|
|
|
|
|
|
|
pid = AV_RB16(packet + 1) & 0x1fff; |
|
|
|
if(pid && discard_pid(ts, pid)) |
|
|
|
return; |
|
|
|
is_start = packet[1] & 0x40; |
|
|
|
tss = ts->pids[pid]; |
|
|
|
if (ts->auto_guess && tss == NULL && is_start) { |
|
|
|
|