]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/mpegts.c
Only link against alsa if enabled.
[ffmpeg] / libavformat / mpegts.c
index 395095b8157bed068ead5823b9281cb05ca6eeb8..0d38e6f92a9bb7994846c8d5725f45117f66c6fb 100644 (file)
@@ -128,13 +128,15 @@ struct MpegTSContext {
 
 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 {
@@ -511,7 +513,6 @@ static const StreamType HDMV_types[] = {
 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 },
 };
 
@@ -521,6 +522,15 @@ static const StreamType REGD_types[] = {
     { 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)
 {
@@ -533,8 +543,7 @@ static void mpegts_find_stream_type(AVStream *st,
     }
 }
 
-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);
 
@@ -544,22 +553,31 @@ static AVStream *new_pes_av_stream(PESContext *pes, uint32_t code,
     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*)&reg_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;
@@ -574,10 +592,9 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
     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);
@@ -624,8 +641,6 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int 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)
@@ -633,6 +648,25 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
         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;
@@ -643,15 +677,6 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
             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;
@@ -662,11 +687,12 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
             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);
@@ -674,16 +700,22 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
                 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;
@@ -691,32 +723,6 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
             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++;
@@ -920,16 +926,44 @@ static int mpegts_push_data(MpegTSFilter *filter,
                     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 */
@@ -941,6 +975,21 @@ static int mpegts_push_data(MpegTSFilter *filter,
             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)
@@ -969,15 +1018,6 @@ static int mpegts_push_data(MpegTSFilter *filter,
                     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;
@@ -1021,6 +1061,7 @@ static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int pcr_pid, int s
     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);