enum MpegTSState {
MPEGTS_HEADER = 0,
+ MPEGTS_PESHEADER,
MPEGTS_PESHEADER_FILL,
MPEGTS_PAYLOAD,
MPEGTS_SKIP,
};
/* enough for PES header + length */
-#define PES_START_SIZE 9
+#define PES_START_SIZE 6
+#define PES_HEADER_SIZE 9
#define MAX_PES_HEADER_SIZE (9 + 255)
struct PESContext {
static const StreamType MISC_types[] = {
{ 0x81, CODEC_TYPE_AUDIO, CODEC_ID_AC3 },
{ 0x8a, CODEC_TYPE_AUDIO, CODEC_ID_DTS },
- {0x100, CODEC_TYPE_SUBTITLE, CODEC_ID_DVB_SUBTITLE }, // demuxer internal
{ 0 },
};
{ 0 },
};
+/* descriptor present */
+static const StreamType DESC_types[] = {
+ { 0x6a, CODEC_TYPE_AUDIO, CODEC_ID_AC3 }, /* AC-3 descriptor */
+ { 0x7a, CODEC_TYPE_AUDIO, CODEC_ID_EAC3 }, /* E-AC-3 descriptor */
+ { 0x7b, CODEC_TYPE_AUDIO, CODEC_ID_DTS },
+ { 0x59, CODEC_TYPE_SUBTITLE, CODEC_ID_DVB_SUBTITLE }, /* subtitling descriptor */
+ { 0 },
+};
+
static void mpegts_find_stream_type(AVStream *st,
uint32_t stream_type, const StreamType *types)
{
}
}
-static AVStream *new_pes_av_stream(PESContext *pes, uint32_t code,
- uint32_t prog_reg_desc, uint32_t reg_desc)
+static AVStream *new_pes_av_stream(PESContext *pes, uint32_t prog_reg_desc, uint32_t code)
{
AVStream *st = av_new_stream(pes->stream, pes->pid);
av_set_pts_info(st, 33, 1, 90000);
st->priv_data = pes;
st->codec->codec_type = CODEC_TYPE_DATA;
- st->codec->codec_id = CODEC_ID_PROBE;
+ st->codec->codec_id = CODEC_ID_NONE;
st->need_parsing = AVSTREAM_PARSE_FULL;
pes->st = st;
- dprintf(pes->stream, "stream_type=%x prog_reg_desc=%.4s reg_desc=%.4s\n",
- pes->stream_type, (char*)&prog_reg_desc, (char*)®_desc);
-
- if (pes->stream_type == 0x06) { // private data carrying pes data
- mpegts_find_stream_type(st, reg_desc, REGD_types);
- } else {
- mpegts_find_stream_type(st, pes->stream_type, ISO_types);
- if (prog_reg_desc == AV_RL32("HDMV") &&
- st->codec->codec_id == CODEC_ID_PROBE)
- mpegts_find_stream_type(st, pes->stream_type, HDMV_types);
- if (st->codec->codec_id == CODEC_ID_PROBE)
- mpegts_find_stream_type(st, pes->stream_type, MISC_types);
+ dprintf(pes->stream, "stream_type=%x pid=%x prog_reg_desc=%.4s\n",
+ pes->stream_type, pes->pid, (char*)&prog_reg_desc);
+
+ st->codec->codec_tag = pes->stream_type;
+
+ mpegts_find_stream_type(st, pes->stream_type, ISO_types);
+ if (prog_reg_desc == AV_RL32("HDMV") &&
+ st->codec->codec_id == CODEC_ID_NONE)
+ mpegts_find_stream_type(st, pes->stream_type, HDMV_types);
+ if (st->codec->codec_id == CODEC_ID_NONE)
+ mpegts_find_stream_type(st, pes->stream_type, MISC_types);
+
+ /* stream was not present in PMT, guess based on PES start code */
+ if (st->codec->codec_id == CODEC_ID_NONE) {
+ if (code >= 0x1c0 && code <= 0x1df) {
+ st->codec->codec_type = CODEC_TYPE_AUDIO;
+ st->codec->codec_id = CODEC_ID_MP2;
+ } else if (code == 0x1bd) {
+ st->codec->codec_type = CODEC_TYPE_AUDIO;
+ st->codec->codec_id = CODEC_ID_AC3;
+ }
}
return st;
const uint8_t *p, *p_end, *desc_list_end, *desc_end;
int program_info_length, pcr_pid, pid, stream_type;
int desc_list_len, desc_len, desc_tag;
- int comp_page = 0, anc_page = 0; /* initialize to kill warnings */
- char language[4] = {0}; /* initialize to kill warnings */
+ int comp_page, anc_page;
+ char language[4];
uint32_t prog_reg_desc = 0; /* registration descriptor */
- uint32_t reg_desc = 0; /* registration descriptor */
#ifdef DEBUG
dprintf(ts->stream, "PMT: len %i\n", section_len);
if (p >= p_end)
return;
for(;;) {
- reg_desc = 0;
- language[0] = 0;
st = 0;
stream_type = get8(&p, p_end);
if (stream_type < 0)
pid = get16(&p, p_end) & 0x1fff;
if (pid < 0)
break;
+
+ /* now create ffmpeg stream */
+ if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) {
+ pes = ts->pids[pid]->u.pes_filter.opaque;
+ st = pes->st;
+ } else {
+ if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); //wrongly added sdt filter probably
+ pes = add_pes_stream(ts, pid, pcr_pid, stream_type);
+ if (pes)
+ st = new_pes_av_stream(pes, prog_reg_desc, 0);
+ }
+
+ if (!st)
+ return;
+
+ add_pid_to_pmt(ts, h->id, pid);
+
+ av_program_add_stream_index(ts->stream, h->id, st->index);
+
desc_list_len = get16(&p, p_end) & 0xfff;
if (desc_list_len < 0)
break;
desc_tag = get8(&p, desc_list_end);
if (desc_tag < 0)
break;
- if (stream_type == STREAM_TYPE_PRIVATE_DATA) {
- if((desc_tag == 0x6A) || (desc_tag == 0x7A)) {
- /*assume DVB AC-3 Audio*/
- stream_type = STREAM_TYPE_AUDIO_AC3;
- } else if(desc_tag == 0x7B) {
- /* DVB DTS audio */
- stream_type = STREAM_TYPE_AUDIO_DTS;
- }
- }
desc_len = get8(&p, desc_list_end);
if (desc_len < 0)
break;
dprintf(ts->stream, "tag: 0x%02x len=%d\n",
desc_tag, desc_len);
+ if (st->codec->codec_id == CODEC_ID_NONE &&
+ stream_type == STREAM_TYPE_PRIVATE_DATA)
+ mpegts_find_stream_type(st, desc_tag, DESC_types);
+
switch(desc_tag) {
case 0x59: /* subtitling descriptor */
- if (stream_type == STREAM_TYPE_PRIVATE_DATA)
- stream_type = 0x100; // demuxer internal
-
language[0] = get8(&p, desc_end);
language[1] = get8(&p, desc_end);
language[2] = get8(&p, desc_end);
get8(&p, desc_end);
comp_page = get16(&p, desc_end);
anc_page = get16(&p, desc_end);
-
+ st->codec->sub_id = (anc_page << 16) | comp_page;
+ av_metadata_set(&st->metadata, "language", language);
break;
case 0x0a: /* ISO 639 language descriptor */
language[0] = get8(&p, desc_end);
language[1] = get8(&p, desc_end);
language[2] = get8(&p, desc_end);
language[3] = 0;
+ av_metadata_set(&st->metadata, "language", language);
break;
case 0x05: /* registration descriptor */
- reg_desc = bytestream_get_le32(&p);
+ st->codec->codec_tag = bytestream_get_le32(&p);
+ dprintf(ts->stream, "reg_desc=%.4s\n", (char*)&st->codec->codec_tag);
+ if (st->codec->codec_id == CODEC_ID_NONE &&
+ stream_type == STREAM_TYPE_PRIVATE_DATA)
+ mpegts_find_stream_type(st, st->codec->codec_tag, REGD_types);
break;
default:
break;
p = desc_end;
}
p = desc_list_end;
-
- dprintf(ts->stream, "stream_type=%x pid=0x%x\n",
- stream_type, pid);
-
- /* now create ffmpeg stream */
- if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) {
- pes= ts->pids[pid]->u.pes_filter.opaque;
- st= pes->st;
- } else {
- if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); //wrongly added sdt filter probably
- pes = add_pes_stream(ts, pid, pcr_pid, stream_type);
- if (pes)
- st = new_pes_av_stream(pes, 0, prog_reg_desc, reg_desc);
- }
-
- add_pid_to_pmt(ts, h->id, pid);
-
- if(st) {
- av_program_add_stream_index(ts->stream, h->id, st->index);
-
- if (language[0] != 0)
- av_metadata_set(&st->metadata, "language", language);
-
- if (stream_type == 0x100)
- st->codec->sub_id = (anc_page << 16) | comp_page;
- }
}
/* all parameters are there */
ts->stop_parse++;
pes->header[2] == 0x01) {
/* it must be an mpeg2 PES stream */
code = pes->header[3] | 0x100;
- if (!pes->st || pes->st->discard == AVDISCARD_ALL ||
- !((code >= 0x1c0 && code <= 0x1df) ||
- (code >= 0x1e0 && code <= 0x1ef) ||
- (code == 0x1bd) || (code == 0x1fd)))
+ dprintf(pes->stream, "pid=%x pes_code=%#x\n", pes->pid, code);
+
+ if ((!pes->st && pes->stream->nb_streams == MAX_STREAMS) ||
+ (pes->st && pes->st->discard == AVDISCARD_ALL) ||
+ code == 0x1be) /* padding_stream */
goto skip;
- pes->state = MPEGTS_PESHEADER_FILL;
+
+ /* stream not present in PMT */
+ if (!pes->st)
+ pes->st = new_pes_av_stream(pes, 0, code);
+ if (!pes->st)
+ return AVERROR(ENOMEM);
+
pes->total_size = AV_RB16(pes->header + 4);
/* NOTE: a zero total size means the PES size is
unbounded */
- pes->pes_header_size = pes->header[8] + 9;
+ if (!pes->total_size)
+ pes->total_size = MAX_PES_PAYLOAD;
+
+ /* allocate pes buffer */
+ pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE);
+ 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;
+ if (pes->st->codec->codec_id == CODEC_ID_NONE) {
+ dprintf(pes->stream, "pid=%x stream_type=%x probing\n",
+ pes->pid, pes->stream_type);
+ pes->st->codec->codec_id = CODEC_ID_PROBE;
+ }
+ } else {
+ pes->state = MPEGTS_PAYLOAD;
+ pes->data_index = 0;
+ }
} else {
/* otherwise, it should be a table */
/* skip packet */
break;
/**********************************************/
/* PES packing parsing */
+ case MPEGTS_PESHEADER:
+ len = PES_HEADER_SIZE - pes->data_index;
+ if (len < 0)
+ return -1;
+ 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;
+ pes->state = MPEGTS_PESHEADER_FILL;
+ }
+ break;
case MPEGTS_PESHEADER_FILL:
len = pes->pes_header_size - pes->data_index;
if (len < 0)
r += 5;
}
- if (pes->total_size > pes->data_index - 6)
- pes->total_size -= pes->data_index - 6;
- else
- pes->total_size = MAX_PES_PAYLOAD;
- /* allocate pes buffer */
- pes->buffer = av_malloc(pes->total_size+FF_INPUT_BUFFER_PADDING_SIZE);
- if (!pes->buffer)
- return AVERROR(ENOMEM);
-
/* we got the full header. We parse it and get the payload */
pes->state = MPEGTS_PAYLOAD;
pes->data_index = 0;
pes->pid = pid;
pes->pcr_pid = pcr_pid;
pes->stream_type = stream_type;
+ pes->state = MPEGTS_SKIP;
tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);
if (!tss) {
av_free(pes);