|
|
|
@ -55,12 +55,13 @@ |
|
|
|
|
enum MpegTSFilterType { |
|
|
|
|
MPEGTS_PES, |
|
|
|
|
MPEGTS_SECTION, |
|
|
|
|
MPEGTS_PCR, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
typedef struct MpegTSFilter MpegTSFilter; |
|
|
|
|
|
|
|
|
|
typedef int PESCallback (MpegTSFilter *f, const uint8_t *buf, int len, |
|
|
|
|
int is_start, int64_t pos, int64_t cur_pcr); |
|
|
|
|
int is_start, int64_t pos); |
|
|
|
|
|
|
|
|
|
typedef struct MpegTSPESFilter { |
|
|
|
|
PESCallback *pes_cb; |
|
|
|
@ -85,6 +86,7 @@ struct MpegTSFilter { |
|
|
|
|
int pid; |
|
|
|
|
int es_id; |
|
|
|
|
int last_cc; /* last cc code (-1 if first packet) */ |
|
|
|
|
int64_t last_pcr; |
|
|
|
|
enum MpegTSFilterType type; |
|
|
|
|
union { |
|
|
|
|
MpegTSPESFilter pes_filter; |
|
|
|
@ -216,7 +218,6 @@ typedef struct PESContext { |
|
|
|
|
uint8_t header[MAX_PES_HEADER_SIZE]; |
|
|
|
|
AVBufferRef *buffer; |
|
|
|
|
SLConfigDescr sl; |
|
|
|
|
int64_t last_pcr; |
|
|
|
|
} PESContext; |
|
|
|
|
|
|
|
|
|
extern AVInputFormat ff_mpegts_demuxer; |
|
|
|
@ -405,14 +406,10 @@ static void write_section_data(AVFormatContext *s, MpegTSFilter *tss1, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, |
|
|
|
|
unsigned int pid, |
|
|
|
|
SectionCallback *section_cb, |
|
|
|
|
void *opaque, |
|
|
|
|
int check_crc) |
|
|
|
|
static MpegTSFilter *mpegts_open_filter(MpegTSContext *ts, unsigned int pid, |
|
|
|
|
enum MpegTSFilterType type) |
|
|
|
|
{ |
|
|
|
|
MpegTSFilter *filter; |
|
|
|
|
MpegTSSectionFilter *sec; |
|
|
|
|
|
|
|
|
|
av_dlog(ts->stream, "Filter: pid=0x%x\n", pid); |
|
|
|
|
|
|
|
|
@ -423,11 +420,26 @@ static MpegTSFilter *mpegts_open_section_filter(MpegTSContext *ts, |
|
|
|
|
return NULL; |
|
|
|
|
ts->pids[pid] = filter; |
|
|
|
|
|
|
|
|
|
filter->type = MPEGTS_SECTION; |
|
|
|
|
filter->type = type; |
|
|
|
|
filter->pid = pid; |
|
|
|
|
filter->es_id = -1; |
|
|
|
|
filter->last_cc = -1; |
|
|
|
|
filter->last_pcr= -1; |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
sec = &filter->u.section_filter; |
|
|
|
|
sec->section_cb = section_cb; |
|
|
|
|
sec->opaque = opaque; |
|
|
|
@ -447,24 +459,20 @@ static MpegTSFilter *mpegts_open_pes_filter(MpegTSContext *ts, unsigned int pid, |
|
|
|
|
MpegTSFilter *filter; |
|
|
|
|
MpegTSPESFilter *pes; |
|
|
|
|
|
|
|
|
|
if (pid >= NB_PID_MAX || ts->pids[pid]) |
|
|
|
|
return NULL; |
|
|
|
|
filter = av_mallocz(sizeof(MpegTSFilter)); |
|
|
|
|
if (!filter) |
|
|
|
|
if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_PES))) |
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
|
|
ts->pids[pid] = filter; |
|
|
|
|
filter->type = MPEGTS_PES; |
|
|
|
|
filter->pid = pid; |
|
|
|
|
filter->es_id = -1; |
|
|
|
|
filter->last_cc = -1; |
|
|
|
|
|
|
|
|
|
pes = &filter->u.pes_filter; |
|
|
|
|
pes->pes_cb = pes_cb; |
|
|
|
|
pes->opaque = opaque; |
|
|
|
|
return filter; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static MpegTSFilter *mpegts_open_pcr_filter(MpegTSContext *ts, unsigned int pid) |
|
|
|
|
{ |
|
|
|
|
return mpegts_open_filter(ts, pid, MPEGTS_PCR); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter) |
|
|
|
|
{ |
|
|
|
|
int pid; |
|
|
|
@ -891,7 +899,7 @@ static int read_sl_header(PESContext *pes, SLConfigDescr *sl, |
|
|
|
|
/* 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, |
|
|
|
|
int64_t pos, int64_t pcr) |
|
|
|
|
int64_t pos) |
|
|
|
|
{ |
|
|
|
|
PESContext *pes = filter->u.pes_filter.opaque; |
|
|
|
|
MpegTSContext *ts = pes->ts; |
|
|
|
@ -901,9 +909,6 @@ static int mpegts_push_data(MpegTSFilter *filter, |
|
|
|
|
if (!ts->pkt) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
if (pcr != -1) |
|
|
|
|
pes->last_pcr = pcr; |
|
|
|
|
|
|
|
|
|
if (is_start) { |
|
|
|
|
if (pes->state == MPEGTS_PAYLOAD && pes->data_index > 0) { |
|
|
|
|
new_pes_packet(pes, ts->pkt); |
|
|
|
@ -1066,16 +1071,28 @@ skip: |
|
|
|
|
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]; |
|
|
|
|
if (f && f->type == MPEGTS_PES) { |
|
|
|
|
PESContext *pcrpes = f->u.pes_filter.opaque; |
|
|
|
|
if (pcrpes && pcrpes->last_pcr != -1 && pcrpes->st && pcrpes->st->discard != AVDISCARD_ALL) { |
|
|
|
|
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) { |
|
|
|
|
// 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
|
|
|
|
|
int64_t pcr = pcrpes->last_pcr / 300; |
|
|
|
|
pes->st->pts_wrap_reference = pcrpes->st->pts_wrap_reference; |
|
|
|
|
pes->st->pts_wrap_behavior = pcrpes->st->pts_wrap_behavior; |
|
|
|
|
int64_t pcr = f->last_pcr / 300; |
|
|
|
|
pes->st->pts_wrap_reference = st->pts_wrap_reference; |
|
|
|
|
pes->st->pts_wrap_behavior = st->pts_wrap_behavior; |
|
|
|
|
if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) { |
|
|
|
|
pes->pts = pes->dts = pcr; |
|
|
|
|
} else if (pes->dts > pcr + 3654 + 9000) { |
|
|
|
@ -1146,7 +1163,6 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid) |
|
|
|
|
pes->state = MPEGTS_SKIP; |
|
|
|
|
pes->pts = AV_NOPTS_VALUE; |
|
|
|
|
pes->dts = AV_NOPTS_VALUE; |
|
|
|
|
pes->last_pcr= -1; |
|
|
|
|
tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); |
|
|
|
|
if (!tss) { |
|
|
|
|
av_free(pes); |
|
|
|
@ -1826,6 +1842,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len |
|
|
|
|
p = desc_list_end; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!ts->pids[pcr_pid]) |
|
|
|
|
mpegts_open_pcr_filter(ts, pcr_pid); |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
for (i = 0; i < mp4_descr_count; i++) |
|
|
|
|
av_free(mp4_descr[i].dec_config_descr); |
|
|
|
@ -2031,7 +2050,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!has_payload) |
|
|
|
|
if (!has_payload && tss->type != MPEGTS_PCR) |
|
|
|
|
return 0; |
|
|
|
|
p = packet + 4; |
|
|
|
|
if (has_adaptation) { |
|
|
|
@ -2040,7 +2059,7 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) |
|
|
|
|
} |
|
|
|
|
/* if past the end of packet, ignore */ |
|
|
|
|
p_end = packet + TS_PACKET_SIZE; |
|
|
|
|
if (p >= p_end) |
|
|
|
|
if (p > p_end || (p == p_end && tss->type != MPEGTS_PCR)) |
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
pos = avio_tell(ts->stream->pb); |
|
|
|
@ -2093,15 +2112,16 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) |
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
int ret; |
|
|
|
|
int64_t pcr = -1; |
|
|
|
|
int64_t pcr_h; |
|
|
|
|
int pcr_l; |
|
|
|
|
if (parse_pcr(&pcr_h, &pcr_l, packet) == 0) |
|
|
|
|
pcr = pcr_h * 300 + pcr_l; |
|
|
|
|
tss->last_pcr = pcr_h * 300 + pcr_l; |
|
|
|
|
// Note: The position here points actually behind the current packet.
|
|
|
|
|
if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start, |
|
|
|
|
pos - ts->raw_packet_size, pcr)) < 0) |
|
|
|
|
return ret; |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
@ -2217,9 +2237,9 @@ static int handle_packets(MpegTSContext *ts, int nb_packets) |
|
|
|
|
av_buffer_unref(&pes->buffer); |
|
|
|
|
pes->data_index = 0; |
|
|
|
|
pes->state = MPEGTS_SKIP; /* skip until pes header */ |
|
|
|
|
pes->last_pcr = -1; |
|
|
|
|
} |
|
|
|
|
ts->pids[i]->last_cc = -1; |
|
|
|
|
ts->pids[i]->last_pcr = -1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|