]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/mpegtsenc.c
Make write_header() and write_headers() return an error code in case of
[ffmpeg] / libavformat / mpegtsenc.c
index 64e6fddcf00b5648b5c3bf87508e567a73a289fc..3fc6dc195f0d48ef3937b7619442aea975cbb3b1 100644 (file)
@@ -23,7 +23,9 @@
 #include "libavutil/crc.h"
 #include "libavcodec/mpegvideo.h"
 #include "avformat.h"
+#include "internal.h"
 #include "mpegts.h"
+#include "adts.h"
 
 /* write DVB SI sections */
 
@@ -177,6 +179,7 @@ typedef struct MpegTSWriteStream {
     int64_t payload_pts;
     int64_t payload_dts;
     uint8_t payload[DEFAULT_PES_PAYLOAD_SIZE];
+    ADTSContext *adts;
 } MpegTSWriteStream;
 
 static void mpegts_write_pat(AVFormatContext *s)
@@ -253,7 +256,7 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
 
         /* write optional descriptors here */
         switch(st->codec->codec_type) {
-        case CODEC_TYPE_AUDIO:
+        case AVMEDIA_TYPE_AUDIO:
             if (lang && strlen(lang->value) == 3) {
                 *q++ = 0x0a; /* ISO 639 language descriptor */
                 *q++ = 4;
@@ -263,7 +266,7 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
                 *q++ = 0; /* undefined type */
             }
             break;
-        case CODEC_TYPE_SUBTITLE:
+        case AVMEDIA_TYPE_SUBTITLE:
             {
                 const char *language;
                 language = lang && strlen(lang->value)==3 ? lang->value : "eng";
@@ -277,7 +280,7 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
                 put16(&q, 1); /* ancillary page id */
             }
             break;
-        case CODEC_TYPE_VIDEO:
+        case AVMEDIA_TYPE_VIDEO:
             if (stream_type == STREAM_TYPE_VIDEO_DIRAC) {
                 *q++ = 0x05; /*MPEG-2 registration descriptor*/
                 *q++ = 4;
@@ -422,11 +425,20 @@ static int mpegts_write_header(AVFormatContext *s)
         ts_st->first_pts_check = 1;
         ts_st->cc = 15;
         /* update PCR pid by using the first video stream */
-        if (st->codec->codec_type == CODEC_TYPE_VIDEO &&
+        if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
             service->pcr_pid == 0x1fff) {
             service->pcr_pid = ts_st->pid;
             pcr_st = st;
         }
+        if (st->codec->codec_id == CODEC_ID_AAC &&
+            st->codec->extradata_size > 0) {
+            ts_st->adts = av_mallocz(sizeof(*ts_st->adts));
+            if (!ts_st->adts)
+                return AVERROR(ENOMEM);
+            if (ff_adts_decode_extradata(s, ts_st->adts, st->codec->extradata,
+                                         st->codec->extradata_size) < 0)
+                return -1;
+        }
     }
 
     /* if no video stream, use the first stream as PCR */
@@ -439,19 +451,19 @@ static int mpegts_write_header(AVFormatContext *s)
     ts->mux_rate = s->mux_rate ? s->mux_rate : 1;
 
     if (ts->mux_rate > 1) {
-    service->pcr_packet_period = (ts->mux_rate * PCR_RETRANS_TIME) /
-        (TS_PACKET_SIZE * 8 * 1000);
-    ts->sdt_packet_period      = (ts->mux_rate * SDT_RETRANS_TIME) /
-        (TS_PACKET_SIZE * 8 * 1000);
-    ts->pat_packet_period      = (ts->mux_rate * PAT_RETRANS_TIME) /
-        (TS_PACKET_SIZE * 8 * 1000);
-
-    ts->cur_pcr = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
+        service->pcr_packet_period = (ts->mux_rate * PCR_RETRANS_TIME) /
+            (TS_PACKET_SIZE * 8 * 1000);
+        ts->sdt_packet_period      = (ts->mux_rate * SDT_RETRANS_TIME) /
+            (TS_PACKET_SIZE * 8 * 1000);
+        ts->pat_packet_period      = (ts->mux_rate * PAT_RETRANS_TIME) /
+            (TS_PACKET_SIZE * 8 * 1000);
+
+        ts->cur_pcr = av_rescale(s->max_delay, 90000, AV_TIME_BASE);
     } else {
         /* Arbitrary values, PAT/PMT could be written on key frames */
         ts->sdt_packet_period = 200;
         ts->pat_packet_period = 40;
-        if (pcr_st->codec->codec_type == CODEC_TYPE_AUDIO) {
+        if (pcr_st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
             if (!pcr_st->codec->frame_size) {
                 av_log(s, AV_LOG_WARNING, "frame size not set\n");
                 service->pcr_packet_period =
@@ -650,18 +662,18 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
             *q++ = 0x00;
             *q++ = 0x01;
             private_code = 0;
-            if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
+            if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
                 if (st->codec->codec_id == CODEC_ID_DIRAC) {
                     *q++ = 0xfd;
                 } else
                     *q++ = 0xe0;
-            } else if (st->codec->codec_type == CODEC_TYPE_AUDIO &&
+            } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
                        (st->codec->codec_id == CODEC_ID_MP2 ||
                         st->codec->codec_id == CODEC_ID_MP3)) {
                 *q++ = 0xc0;
             } else {
                 *q++ = 0xbd;
-                if (st->codec->codec_type == CODEC_TYPE_SUBTITLE) {
+                if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
                     private_code = 0x20;
                 }
             }
@@ -675,7 +687,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
                 header_len += 5;
                 flags |= 0x40;
             }
-            if (st->codec->codec_type == CODEC_TYPE_VIDEO &&
+            if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
                 st->codec->codec_id == CODEC_ID_DIRAC) {
                 /* set PES_extension_flag */
                 pes_extension = 1;
@@ -697,7 +709,7 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st,
             *q++ = len;
             val = 0x80;
             /* data alignment indicator is required for subtitle data */
-            if (st->codec->codec_type == CODEC_TYPE_SUBTITLE)
+            if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE)
                 val |= 0x04;
             *q++ = val;
             *q++ = flags;
@@ -809,9 +821,35 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt)
             buf  = data;
             size = pkt->size+6;
         }
+    } else if (st->codec->codec_id == CODEC_ID_AAC) {
+        if (pkt->size < 2)
+            return -1;
+        if ((AV_RB16(pkt->data) & 0xfff0) != 0xfff0) {
+            ADTSContext *adts = ts_st->adts;
+            int new_size;
+            if (!adts) {
+                av_log(s, AV_LOG_ERROR, "aac bitstream not in adts format "
+                       "and extradata missing\n");
+                return -1;
+            }
+            new_size = ADTS_HEADER_SIZE+adts->pce_size+pkt->size;
+            if ((unsigned)new_size >= INT_MAX)
+                return -1;
+            data = av_malloc(new_size);
+            if (!data)
+                return AVERROR(ENOMEM);
+            ff_adts_write_frame_header(adts, data, pkt->size, adts->pce_size);
+            if (adts->pce_size) {
+                memcpy(data+ADTS_HEADER_SIZE, adts->pce_data, adts->pce_size);
+                adts->pce_size = 0;
+            }
+            memcpy(data+ADTS_HEADER_SIZE+adts->pce_size, pkt->data, pkt->size);
+            buf = data;
+            size = new_size;
+        }
     }
 
-    if (st->codec->codec_type != CODEC_TYPE_AUDIO) {
+    if (st->codec->codec_type != AVMEDIA_TYPE_AUDIO) {
         // for video and subtitle, write a single pes packet
         mpegts_write_pes(s, st, buf, size, pts, dts);
         av_free(data);
@@ -832,6 +870,8 @@ static int mpegts_write_packet(AVFormatContext *s, AVPacket *pkt)
     memcpy(ts_st->payload + ts_st->payload_index, buf, size);
     ts_st->payload_index += size;
 
+    av_free(data);
+
     return 0;
 }
 
@@ -851,6 +891,7 @@ static int mpegts_write_end(AVFormatContext *s)
             mpegts_write_pes(s, st, ts_st->payload, ts_st->payload_index,
                              ts_st->payload_pts, ts_st->payload_dts);
         }
+        av_freep(&ts_st->adts);
     }
     put_flush_packet(s->pb);