#include "libavutil/dict.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/avassert.h"
#include "libavcodec/bytestream.h"
+#include "libavcodec/get_bits.h"
#include "avformat.h"
#include "mpegts.h"
#include "internal.h"
#define MAX_PES_PAYLOAD 200*1024
+#define MAX_MP4_DESCR_COUNT 16
+
enum MpegTSFilterType {
MPEGTS_PES,
MPEGTS_SECTION,
struct MpegTSFilter {
int pid;
+ int es_id;
int last_cc; /* last cc code (-1 if first packet) */
enum MpegTSFilterType type;
union {
};
static const AVOption options[] = {
- {"compute_pcr", "Compute exact PCR for each transport stream packet.", offsetof(MpegTSContext, mpeg2ts_compute_pcr), FF_OPT_TYPE_INT,
+ {"compute_pcr", "Compute exact PCR for each transport stream packet.", offsetof(MpegTSContext, mpeg2ts_compute_pcr), AV_OPT_TYPE_INT,
{.dbl = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
{ NULL },
};
int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */
uint8_t header[MAX_PES_HEADER_SIZE];
uint8_t *buffer;
+ SLConfigDescr sl;
} PESContext;
extern AVInputFormat ff_mpegts_demuxer;
ts->pids[pid] = filter;
filter->type = MPEGTS_SECTION;
filter->pid = pid;
+ filter->es_id = -1;
filter->last_cc = -1;
sec = &filter->u.section_filter;
sec->section_cb = section_cb;
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;
return c;
}
-/* read and allocate a DVB string preceeded by its length */
+/* read and allocate a DVB string preceded by its length */
static char *getstr8(const uint8_t **pp, const uint8_t *p_end)
{
int len;
{ 0x84, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 },
{ 0x85, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS HD */
{ 0x86, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS HD MASTER*/
+ { 0xa1, AVMEDIA_TYPE_AUDIO, CODEC_ID_EAC3 }, /* E-AC3 Secondary Audio */
+ { 0xa2, AVMEDIA_TYPE_AUDIO, CODEC_ID_DTS }, /* DTS Express Secondary Audio */
{ 0x90, AVMEDIA_TYPE_SUBTITLE, CODEC_ID_HDMV_PGS_SUBTITLE },
{ 0 },
};
static int mpegts_set_stream_info(AVStream *st, PESContext *pes,
uint32_t stream_type, uint32_t prog_reg_desc)
{
+ int old_codec_type= st->codec->codec_type;
+ int old_codec_id = st->codec->codec_id;
av_set_pts_info(st, 33, 1, 90000);
st->priv_data = pes;
st->codec->codec_type = AVMEDIA_TYPE_DATA;
return AVERROR(ENOMEM);
memcpy(sub_pes, pes, sizeof(*sub_pes));
- sub_st = av_new_stream(pes->stream, pes->pid);
+ sub_st = avformat_new_stream(pes->stream, NULL);
if (!sub_st) {
av_free(sub_pes);
return AVERROR(ENOMEM);
}
+ sub_st->id = pes->pid;
av_set_pts_info(sub_st, 33, 1, 90000);
sub_st->priv_data = sub_pes;
sub_st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
}
if (st->codec->codec_id == CODEC_ID_NONE)
mpegts_find_stream_type(st, pes->stream_type, MISC_types);
+ if (st->codec->codec_id == CODEC_ID_NONE){
+ st->codec->codec_id = old_codec_id;
+ st->codec->codec_type= old_codec_type;
+ }
return 0;
}
pes->flags = 0;
}
+static uint64_t get_bits64(GetBitContext *gb, int bits)
+{
+ uint64_t ret = 0;
+ while (bits > 17) {
+ ret <<= 17;
+ ret |= get_bits(gb, 17);
+ bits -= 17;
+ }
+ ret <<= bits;
+ ret |= get_bits(gb, bits);
+ return ret;
+}
+
+static int read_sl_header(PESContext *pes, SLConfigDescr *sl, const uint8_t *buf, int buf_size)
+{
+ 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;
+ init_get_bits(&gb, buf, buf_size*8);
+
+ 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)
+ dts = get_bits64(&gb, sl->timestamp_len);
+ if (cts_flag == 1)
+ cts = get_bits64(&gb, sl->timestamp_len);
+ 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;
+
+ av_set_pts_info(pes->st, sl->timestamp_len, 1, sl->timestamp_res);
+
+ return (get_bits_count(&gb) + 7) >> 3;
+}
+
/* 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,
/* stream not present in PMT */
if (!pes->st) {
- pes->st = av_new_stream(ts->stream, pes->pid);
+ pes->st = avformat_new_stream(ts->stream, NULL);
if (!pes->st)
return AVERROR(ENOMEM);
+ pes->st->id = pes->pid;
mpegts_set_stream_info(pes->st, pes, 0, 0);
}
/* we got the full header. We parse it and get the payload */
pes->state = MPEGTS_PAYLOAD;
pes->data_index = 0;
+ if (pes->stream_type == 0x12) {
+ int sl_header_bytes = read_sl_header(pes, &pes->sl, p, buf_size);
+ pes->pes_header_size += sl_header_bytes;
+ p += sl_header_bytes;
+ buf_size -= sl_header_bytes;
+ }
}
break;
case MPEGTS_PAYLOAD:
return pes;
}
+#define MAX_LEVEL 4
+typedef struct {
+ AVFormatContext *s;
+ AVIOContext pb;
+ Mp4Descr *descr;
+ Mp4Descr *active_descr;
+ int descr_count;
+ int max_descr_count;
+ int level;
+} MP4DescrParseContext;
+
+static int init_MP4DescrParseContext(
+ MP4DescrParseContext *d, AVFormatContext *s, const uint8_t *buf,
+ unsigned size, Mp4Descr *descr, int max_descr_count)
+{
+ int ret;
+ if (size > (1<<30))
+ return AVERROR_INVALIDDATA;
+
+ if ((ret = ffio_init_context(&d->pb, (unsigned char*)buf, size, 0,
+ NULL, NULL, NULL, NULL)) < 0)
+ return ret;
+
+ d->s = s;
+ d->level = 0;
+ d->descr_count = 0;
+ d->descr = descr;
+ d->active_descr = NULL;
+ d->max_descr_count = max_descr_count;
+
+ return 0;
+}
+
+static void update_offsets(AVIOContext *pb, int64_t *off, int *len) {
+ int64_t new_off = avio_tell(pb);
+ (*len) -= new_off - *off;
+ *off = new_off;
+}
+
+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) {
+ if (parse_mp4_descr(d, off, len, 0) < 0)
+ return -1;
+ 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);
+}
+
+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);
+ if (!(id_flags & 0x0020)) { //URL_Flag
+ update_offsets(&d->pb, &off, &len);
+ return parse_mp4_descr_arr(d, off, len); //ES_Descriptor[]
+ } else {
+ return 0;
+ }
+}
+
+static int parse_MP4ESDescrTag(MP4DescrParseContext *d, int64_t off, int len)
+{
+ int es_id = 0;
+ if (d->descr_count >= d->max_descr_count)
+ return -1;
+ 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);
+ update_offsets(&d->pb, &off, &len);
+ if (len > 0)
+ parse_mp4_descr(d, off, len, MP4SLDescrTag);
+ d->active_descr = NULL;
+ return 0;
+}
+
+static int parse_MP4DecConfigDescrTag(MP4DescrParseContext *d, int64_t off, int len)
+{
+ Mp4Descr *descr = d->active_descr;
+ if (!descr)
+ return -1;
+ 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;
+}
+
+static int parse_MP4SLDescrTag(MP4DescrParseContext *d, int64_t off, int len)
+{
+ Mp4Descr *descr = d->active_descr;
+ int predefined;
+ if (!descr)
+ return -1;
+
+ predefined = avio_r8(&d->pb);
+ if (!predefined) {
+ int lengths;
+ int flags = avio_r8(&d->pb);
+ 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);
+ descr->sl.timestamp_len = avio_r8(&d->pb);
+ 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;
+ } else {
+ av_log_missing_feature(d->s, "Predefined SLConfigDescriptor\n", 0);
+ }
+ return 0;
+}
+
+static int parse_mp4_descr(MP4DescrParseContext *d, int64_t off, int len,
+ int target_tag) {
+ int tag;
+ int len1 = ff_mp4_read_descr(d->s, &d->pb, &tag);
+ update_offsets(&d->pb, &off, &len);
+ if (len < 0 || len1 > len || len1 <= 0) {
+ av_log(d->s, AV_LOG_ERROR, "Tag %x length violation new length %d bytes remaining %d\n", tag, len1, len);
+ return -1;
+ }
+
+ 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) {
+ av_log(d->s, AV_LOG_ERROR, "Found tag %x expected %x\n", tag, target_tag);
+ goto done;
+ }
+
+ switch (tag) {
+ case MP4IODescrTag:
+ parse_MP4IODescrTag(d, off, len1);
+ break;
+ case MP4ODescrTag:
+ parse_MP4ODescrTag(d, off, len1);
+ break;
+ case MP4ESDescrTag:
+ parse_MP4ESDescrTag(d, off, len1);
+ break;
+ case MP4DecConfigDescrTag:
+ parse_MP4DecConfigDescrTag(d, off, len1);
+ break;
+ case MP4SLDescrTag:
+ parse_MP4SLDescrTag(d, off, len1);
+ break;
+ }
+
+done:
+ d->level--;
+ avio_seek(&d->pb, off + len1, SEEK_SET);
+ return 0;
+}
+
static int mp4_read_iods(AVFormatContext *s, const uint8_t *buf, unsigned size,
- int *es_id, uint8_t **dec_config_descr,
- int *dec_config_descr_size)
+ Mp4Descr *descr, int *descr_count, int max_descr_count)
+{
+ MP4DescrParseContext d;
+ if (init_MP4DescrParseContext(&d, s, buf, size, descr, max_descr_count) < 0)
+ return -1;
+
+ parse_mp4_descr(&d, avio_tell(&d.pb), size, MP4IODescrTag);
+
+ *descr_count = d.descr_count;
+ return 0;
+}
+
+static int mp4_read_od(AVFormatContext *s, const uint8_t *buf, unsigned size,
+ Mp4Descr *descr, int *descr_count, int max_descr_count)
+{
+ MP4DescrParseContext d;
+ if (init_MP4DescrParseContext(&d, s, buf, size, descr, max_descr_count) < 0)
+ return -1;
+
+ parse_mp4_descr_arr(&d, avio_tell(&d.pb), size);
+
+ *descr_count = d.descr_count;
+ return 0;
+}
+
+static void m4sl_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
{
+ MpegTSContext *ts = filter->u.section_filter.opaque;
+ SectionHeader h;
+ const uint8_t *p, *p_end;
AVIOContext pb;
- int tag;
- unsigned len;
-
- ffio_init_context(&pb, buf, size, 0, NULL, NULL, NULL, NULL);
-
- len = ff_mp4_read_descr(s, &pb, &tag);
- if (tag == MP4IODescrTag) {
- avio_rb16(&pb); // ID
- avio_r8(&pb);
- avio_r8(&pb);
- avio_r8(&pb);
- avio_r8(&pb);
- avio_r8(&pb);
- len = ff_mp4_read_descr(s, &pb, &tag);
- if (tag == MP4ESDescrTag) {
- ff_mp4_parse_es_descr(&pb, es_id);
- av_dlog(s, "ES_ID %#x\n", *es_id);
- len = ff_mp4_read_descr(s, &pb, &tag);
- if (tag == MP4DecConfigDescrTag) {
- *dec_config_descr = av_malloc(len);
- if (!*dec_config_descr)
- return AVERROR(ENOMEM);
- *dec_config_descr_size = len;
- avio_read(&pb, *dec_config_descr, len);
+ Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = {{ 0 }};
+ int mp4_descr_count = 0;
+ int i, pid;
+ 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;
+
+ mp4_read_od(s, p, (unsigned)(p_end - p), mp4_descr, &mp4_descr_count, MAX_MP4_DESCR_COUNT);
+
+ for (pid = 0; pid < NB_PID_MAX; pid++) {
+ if (!ts->pids[pid])
+ continue;
+ for (i = 0; i < mp4_descr_count; i++) {
+ PESContext *pes;
+ AVStream *st;
+ if (ts->pids[pid]->es_id != mp4_descr[i].es_id)
+ continue;
+ if (!(ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES)) {
+ av_log(s, AV_LOG_ERROR, "pid %x is not PES\n", pid);
+ continue;
+ }
+ pes = ts->pids[pid]->u.pes_filter.opaque;
+ st = pes->st;
+ if (!st) {
+ continue;
+ }
+
+ pes->sl = mp4_descr[i].sl;
+
+ 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(s, st, &pb);
+ if (st->codec->codec_id == CODEC_ID_AAC &&
+ st->codec->extradata_size > 0)
+ st->need_parsing = 0;
+ if (st->codec->codec_id == CODEC_ID_H264 &&
+ st->codec->extradata_size > 0)
+ st->need_parsing = 0;
+
+ if (st->codec->codec_id <= CODEC_ID_NONE) {
+ } else if (st->codec->codec_id < CODEC_ID_FIRST_AUDIO) {
+ st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
+ } else if (st->codec->codec_id < CODEC_ID_FIRST_SUBTITLE) {
+ st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
+ } else if (st->codec->codec_id < CODEC_ID_FIRST_UNKNOWN) {
+ st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
}
}
}
- return 0;
+ for (i = 0; i < mp4_descr_count; i++)
+ av_free(mp4_descr[i].dec_config_descr);
}
int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type,
const uint8_t **pp, const uint8_t *desc_list_end,
- int mp4_dec_config_descr_len, int mp4_es_id, int pid,
- uint8_t *mp4_dec_config_descr)
+ Mp4Descr *mp4_descr, int mp4_descr_count, int pid,
+ MpegTSContext *ts)
{
const uint8_t *desc_end;
- int desc_len, desc_tag;
+ int desc_len, desc_tag, desc_es_id;
char language[252];
int i;
mpegts_find_stream_type(st, desc_tag, DESC_types);
switch(desc_tag) {
- case 0x1F: /* FMC descriptor */
- get16(pp, desc_end);
- if (st->codec->codec_id == CODEC_ID_AAC_LATM &&
- mp4_dec_config_descr_len && mp4_es_id == pid) {
+ case 0x1E: /* SL descriptor */
+ desc_es_id = get16(pp, desc_end);
+ if (ts && ts->pids[pid])
+ ts->pids[pid]->es_id = desc_es_id;
+ for (i = 0; i < mp4_descr_count; i++)
+ if (mp4_descr[i].dec_config_descr_len &&
+ mp4_descr[i].es_id == desc_es_id) {
AVIOContext pb;
- ffio_init_context(&pb, mp4_dec_config_descr,
- mp4_dec_config_descr_len, 0, NULL, NULL, NULL, NULL);
+ 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 == CODEC_ID_AAC &&
st->codec->extradata_size > 0)
st->need_parsing = 0;
+ if (st->codec->codec_id == CODEC_ID_MPEG4SYSTEMS)
+ mpegts_open_section_filter(ts, pid, m4sl_cb, ts, 1);
+ }
+ break;
+ case 0x1F: /* FMC descriptor */
+ get16(pp, desc_end);
+ if (mp4_descr_count > 0 && (st->codec->codec_id == CODEC_ID_AAC_LATM || st->request_probe>0) &&
+ mp4_descr->dec_config_descr_len && mp4_descr->es_id == pid) {
+ AVIOContext pb;
+ ffio_init_context(&pb, mp4_descr->dec_config_descr,
+ mp4_descr->dec_config_descr_len, 0, NULL, NULL, NULL, NULL);
+ ff_mp4_read_dec_config_descr(fc, st, &pb);
+ if (st->codec->codec_id == CODEC_ID_AAC &&
+ st->codec->extradata_size > 0){
+ st->request_probe= st->need_parsing = 0;
+ st->codec->codec_type= AVMEDIA_TYPE_AUDIO;
+ }
}
break;
case 0x56: /* DVB teletext descriptor */
int program_info_length, pcr_pid, pid, stream_type;
int desc_list_len;
uint32_t prog_reg_desc = 0; /* registration descriptor */
- uint8_t *mp4_dec_config_descr = NULL;
- int mp4_dec_config_descr_len = 0;
- int mp4_es_id = 0;
+
+ Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = {{ 0 }};
+ int mp4_descr_count = 0;
+ int i;
av_dlog(ts->stream, "PMT: len %i\n", section_len);
hex_dump_debug(ts->stream, (uint8_t *)section, section_len);
get8(&p, p_end); // scope
get8(&p, p_end); // label
len -= 2;
- mp4_read_iods(ts->stream, p, len, &mp4_es_id,
- &mp4_dec_config_descr, &mp4_dec_config_descr_len);
+ mp4_read_iods(ts->stream, p, len, mp4_descr + mp4_descr_count,
+ &mp4_descr_count, MAX_MP4_DESCR_COUNT);
} else if (tag == 0x05 && len >= 4) { // registration descriptor
prog_reg_desc = bytestream_get_le32(&p);
len -= 4;
// stop parsing after pmt, we found header
if (!ts->stream->nb_streams)
- ts->stop_parse = 1;
+ ts->stop_parse = 2;
for(;;) {
st = 0;
+ pes = NULL;
stream_type = get8(&p, p_end);
if (stream_type < 0)
break;
/* now create ffmpeg stream */
if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) {
pes = ts->pids[pid]->u.pes_filter.opaque;
- if (!pes->st)
- pes->st = av_new_stream(pes->stream, pes->pid);
+ if (!pes->st) {
+ pes->st = avformat_new_stream(pes->stream, NULL);
+ pes->st->id = pes->pid;
+ }
st = pes->st;
- } else {
+ } else if (stream_type != 0x13) {
if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); //wrongly added sdt filter probably
pes = add_pes_stream(ts, pid, pcr_pid);
- if (pes)
- st = av_new_stream(pes->stream, pes->pid);
+ if (pes) {
+ st = avformat_new_stream(pes->stream, NULL);
+ st->id = pes->pid;
+ }
+ } else {
+ int idx = ff_find_stream_index(ts->stream, pid);
+ if (idx >= 0) {
+ st = ts->stream->streams[idx];
+ } else {
+ st = avformat_new_stream(pes->stream, NULL);
+ st->id = pid;
+ st->codec->codec_type = AVMEDIA_TYPE_DATA;
+ }
}
if (!st)
goto out;
- if (!pes->stream_type)
+ if (pes && !pes->stream_type)
mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc);
add_pid_to_pmt(ts, h->id, pid);
break;
for(;;) {
if (ff_parse_mpeg2_descriptor(ts->stream, st, stream_type, &p, desc_list_end,
- mp4_dec_config_descr_len, mp4_es_id, pid, mp4_dec_config_descr) < 0)
+ mp4_descr, mp4_descr_count, pid, ts) < 0)
break;
- if (prog_reg_desc == AV_RL32("HDMV") && stream_type == 0x83 && pes->sub_st) {
+ 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);
pes->sub_st->codec->codec_tag = st->codec->codec_tag;
}
}
out:
- av_free(mp4_dec_config_descr);
+ for (i = 0; i < mp4_descr_count; i++)
+ av_free(mp4_descr[i].dec_config_descr);
}
static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
tss->last_cc = cc;
if (!cc_ok) {
- av_log(ts->stream, AV_LOG_WARNING, "Continuity Check Failed\n");
+ av_log(ts->stream, AV_LOG_DEBUG,
+ "Continuity check failed for pid %d expected %d got %d\n",
+ pid, expected_cc, cc);
if(tss->type == MPEGTS_PES) {
PESContext *pc = tss->u.pes_filter.opaque;
pc->flags |= AV_PKT_FLAG_CORRUPT;
return 0;
p = packet + 4;
if (has_adaptation) {
- /* skip adapation field */
+ /* skip adaptation field */
p += p[0] + 1;
}
/* if past the end of packet, ignore */
len = avio_read(pb, buf, TS_PACKET_SIZE);
if (len != TS_PACKET_SIZE)
return len < 0 ? len : AVERROR_EOF;
- /* check paquet sync byte */
+ /* check packet sync byte */
if (buf[0] != 0x47) {
/* find a new packet start */
avio_seek(pb, -TS_PACKET_SIZE, SEEK_CUR);
if (avio_tell(s->pb) != ts->last_pos) {
int i;
-// av_dlog("Skipping after seek\n");
+ av_dlog(ts->stream, "Skipping after seek\n");
/* seek detected, flush pes buffer */
for (i = 0; i < NB_PID_MAX; i++) {
- if (ts->pids[i] && ts->pids[i]->type == MPEGTS_PES) {
- PESContext *pes = ts->pids[i]->u.pes_filter.opaque;
- av_freep(&pes->buffer);
+ if (ts->pids[i]) {
+ if (ts->pids[i]->type == MPEGTS_PES) {
+ PESContext *pes = ts->pids[i]->u.pes_filter.opaque;
+ av_freep(&pes->buffer);
+ pes->data_index = 0;
+ pes->state = MPEGTS_SKIP; /* skip until pes header */
+ }
ts->pids[i]->last_cc = -1;
- pes->data_index = 0;
- pes->state = MPEGTS_SKIP; /* skip until pes header */
}
}
}
ts->stop_parse = 0;
packet_num = 0;
for(;;) {
- if (ts->stop_parse>0)
- break;
packet_num++;
- if (nb_packets != 0 && packet_num >= nb_packets)
+ if (nb_packets != 0 && packet_num >= nb_packets ||
+ ts->stop_parse > 1) {
+ ret = AVERROR(EAGAIN);
+ break;
+ }
+ if (ts->stop_parse > 0)
break;
+
ret = read_packet(s, packet, ts->raw_packet_size);
if (ret != 0)
break;
int len;
int64_t pos;
- /* read the first 1024 bytes to get packet size */
+ /* read the first 8192 bytes to get packet size */
pos = avio_tell(pb);
len = avio_read(pb, buf, sizeof(buf));
if (len != sizeof(buf))
if (s->iformat == &ff_mpegts_demuxer) {
/* normal demux */
- /* first do a scaning to get all the services */
- if (pb->seekable && avio_seek(pb, pos, SEEK_SET) < 0)
- av_log(s, AV_LOG_ERROR, "Unable to seek back to the start\n");
+ /* first do a scanning to get all the services */
+ /* 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");
mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
/* only read packets */
- st = av_new_stream(s, 0);
+ st = avformat_new_stream(s, NULL);
if (!st)
goto fail;
av_set_pts_info(st, 60, 1, 27000000);
int64_t pos, timestamp;
uint8_t buf[TS_PACKET_SIZE];
int pcr_l, pcr_pid = ((PESContext*)s->streams[stream_index]->priv_data)->pcr_pid;
- const int find_next= 1;
pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
- if (find_next) {
- for(;;) {
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
+ 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;
+ if (buf[0] != 0x47) {
+ if (mpegts_resync(s) < 0)
return AV_NOPTS_VALUE;
- if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
- parse_pcr(×tamp, &pcr_l, buf) == 0) {
- break;
- }
- pos += ts->raw_packet_size;
+ pos = url_ftell(s->pb);
+ continue;
}
- } else {
- for(;;) {
- pos -= ts->raw_packet_size;
- if (pos < 0)
- return AV_NOPTS_VALUE;
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
- return AV_NOPTS_VALUE;
- if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
- parse_pcr(×tamp, &pcr_l, buf) == 0) {
- break;
+ if ((pcr_pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pcr_pid) &&
+ parse_pcr(×tamp, &pcr_l, buf) == 0) {
+ *ppos = pos;
+ return timestamp;
+ }
+ pos += ts->raw_packet_size;
+ }
+
+ return AV_NOPTS_VALUE;
+}
+
+static int64_t mpegts_get_dts(AVFormatContext *s, int stream_index,
+ int64_t *ppos, int64_t pos_limit)
+{
+ MpegTSContext *ts = s->priv_data;
+ int64_t pos, timestamp;
+ pos = ((*ppos + ts->raw_packet_size - 1 - ts->pos47) / ts->raw_packet_size) * ts->raw_packet_size + ts->pos47;
+ 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);
+ ret= av_read_frame(s, &pkt);
+ if(ret < 0)
+ return AV_NOPTS_VALUE;
+ av_free_packet(&pkt);
+ if(pkt.dts != AV_NOPTS_VALUE && pkt.pos >= 0){
+ 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? */);
+ if(pkt.stream_index == stream_index){
+ *ppos= pkt.pos;
+ return pkt.dts;
}
}
+ pos = pkt.pos;
}
- *ppos = pos;
- return timestamp;
+ return AV_NOPTS_VALUE;
}
#ifdef USE_SYNCPOINT_SEARCH
ts_adj = target_ts;
stream_index_gen_search = stream_index;
}
- pos = av_gen_search(s, stream_index_gen_search, ts_adj,
+ pos = ff_gen_search(s, stream_index_gen_search, ts_adj,
0, INT64_MAX, -1,
AV_NOPTS_VALUE,
AV_NOPTS_VALUE,
return ret;
}
-#else
-
-static int read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
- MpegTSContext *ts = s->priv_data;
- uint8_t buf[TS_PACKET_SIZE];
- int64_t pos;
-
- if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
- return -1;
-
- pos= avio_tell(s->pb);
-
- for(;;) {
- avio_seek(s->pb, pos, SEEK_SET);
- if (avio_read(s->pb, buf, TS_PACKET_SIZE) != TS_PACKET_SIZE)
- return -1;
-// pid = AV_RB16(buf + 1) & 0x1fff;
- if(buf[1] & 0x40) break;
- pos += ts->raw_packet_size;
- }
- avio_seek(s->pb, pos, SEEK_SET);
-
- return 0;
-}
-
#endif
/**************************************************************/
ts->raw_packet_size = TS_PACKET_SIZE;
ts->stream = s;
ts->auto_guess = 1;
+ mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1);
+ mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1);
+
return ts;
}
len1 = len;
ts->pkt = pkt;
- ts->stop_parse = 0;
for(;;) {
- if (ts->stop_parse>0)
- break;
+ ts->stop_parse = 0;
if (len < TS_PACKET_SIZE)
return -1;
if (buf[0] != 0x47) {
handle_packet(ts, buf);
buf += TS_PACKET_SIZE;
len -= TS_PACKET_SIZE;
+ if (ts->stop_parse == 1)
+ break;
}
}
return len1 - len;
.read_header = mpegts_read_header,
.read_packet = mpegts_read_packet,
.read_close = mpegts_read_close,
- .read_seek = read_seek,
- .read_timestamp = mpegts_get_pcr,
+ .read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
#ifdef USE_SYNCPOINT_SEARCH
.read_seek2 = read_seek2,
.read_header = mpegts_read_header,
.read_packet = mpegts_raw_read_packet,
.read_close = mpegts_read_close,
- .read_seek = read_seek,
- .read_timestamp = mpegts_get_pcr,
+ .read_timestamp = mpegts_get_dts,
.flags = AVFMT_SHOW_IDS|AVFMT_TS_DISCONT,
#ifdef USE_SYNCPOINT_SEARCH
.read_seek2 = read_seek2,