summaryrefslogtreecommitdiff
path: root/libavformat
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2012-06-03 02:56:52 +0200
committerMichael Niedermayer <michaelni@gmx.at>2012-06-03 02:56:52 +0200
commitf67309cabe27af33dcfcfb61fe1df39af9b5ab46 (patch)
tree31bf4f48fbbbbdb145f8163f0295266c86ca173d /libavformat
parenta128b310efa31ea0f2a3898cd58c0d954c8605be (diff)
parent2439bd86817374362ac8daa701fdb567e14cbe50 (diff)
Merge remote-tracking branch 'qatar/master'
* qatar/master: mpegtsenc: Support LATM packetization for AAC adtsenc: Don't expose the muxer internals to the rest of lavf mpegtsenc: use AVFormatContext for AAC packetization mpegtsenc: use AVERROR() for return codes Conflicts: libavformat/adts.h libavformat/mpegtsenc.c Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/Makefile2
-rw-r--r--libavformat/adts.h45
-rw-r--r--libavformat/adtsenc.c22
-rw-r--r--libavformat/mpegtsenc.c154
4 files changed, 136 insertions, 87 deletions
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 18a0e19b3f..6e3742f702 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -177,7 +177,7 @@ OBJS-$(CONFIG_MPEG1VIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_MPEG2VIDEO_MUXER) += rawenc.o
OBJS-$(CONFIG_MPEGPS_DEMUXER) += mpeg.o
OBJS-$(CONFIG_MPEGTS_DEMUXER) += mpegts.o isom.o
-OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o adtsenc.o
+OBJS-$(CONFIG_MPEGTS_MUXER) += mpegtsenc.o
OBJS-$(CONFIG_MPEGVIDEO_DEMUXER) += mpegvideodec.o rawdec.o
OBJS-$(CONFIG_MPJPEG_MUXER) += mpjpeg.o
OBJS-$(CONFIG_MSNWC_TCP_DEMUXER) += msnwc_tcp.o
diff --git a/libavformat/adts.h b/libavformat/adts.h
deleted file mode 100644
index 1da57beff9..0000000000
--- a/libavformat/adts.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * ADTS muxer.
- * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com>
- * Mans Rullgard <mans@mansr.com>
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * FFmpeg is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with FFmpeg; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef AVFORMAT_ADTS_H
-#define AVFORMAT_ADTS_H
-
-#include "avformat.h"
-#include "libavcodec/mpeg4audio.h"
-
-#define ADTS_HEADER_SIZE 7
-
-typedef struct {
- int write_adts;
- int objecttype;
- int sample_rate_index;
- int channel_conf;
- int pce_size;
- uint8_t pce_data[MAX_PCE_SIZE];
-} ADTSContext;
-
-int ff_adts_write_frame_header(ADTSContext *ctx, uint8_t *buf,
- int size, int pce_size);
-int ff_adts_decode_extradata(AVFormatContext *s, ADTSContext *adts,
- uint8_t *buf, int size);
-
-#endif /* AVFORMAT_ADTS_H */
diff --git a/libavformat/adtsenc.c b/libavformat/adtsenc.c
index 18a055a1e5..bc2397f028 100644
--- a/libavformat/adtsenc.c
+++ b/libavformat/adtsenc.c
@@ -25,11 +25,21 @@
#include "libavcodec/avcodec.h"
#include "libavcodec/mpeg4audio.h"
#include "avformat.h"
-#include "adts.h"
+
+#define ADTS_HEADER_SIZE 7
+
+typedef struct {
+ int write_adts;
+ int objecttype;
+ int sample_rate_index;
+ int channel_conf;
+ int pce_size;
+ uint8_t pce_data[MAX_PCE_SIZE];
+} ADTSContext;
#define ADTS_MAX_FRAME_BYTES ((1 << 13) - 1)
-int ff_adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, uint8_t *buf, int size)
+static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, uint8_t *buf, int size)
{
GetBitContext gb;
PutBitContext pb;
@@ -84,14 +94,14 @@ static int adts_write_header(AVFormatContext *s)
AVCodecContext *avc = s->streams[0]->codec;
if (avc->extradata_size > 0 &&
- ff_adts_decode_extradata(s, adts, avc->extradata, avc->extradata_size) < 0)
+ adts_decode_extradata(s, adts, avc->extradata, avc->extradata_size) < 0)
return -1;
return 0;
}
-int ff_adts_write_frame_header(ADTSContext *ctx,
- uint8_t *buf, int size, int pce_size)
+static int adts_write_frame_header(ADTSContext *ctx,
+ uint8_t *buf, int size, int pce_size)
{
PutBitContext pb;
@@ -137,7 +147,7 @@ static int adts_write_packet(AVFormatContext *s, AVPacket *pkt)
if (!pkt->size)
return 0;
if (adts->write_adts) {
- int err = ff_adts_write_frame_header(adts, buf, pkt->size,
+ int err = adts_write_frame_header(adts, buf, pkt->size,
adts->pce_size);
if (err < 0)
return err;
diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c
index 793e2051d4..0a6aa77e65 100644
--- a/libavformat/mpegtsenc.c
+++ b/libavformat/mpegtsenc.c
@@ -29,7 +29,6 @@
#include "avformat.h"
#include "internal.h"
#include "mpegts.h"
-#include "adts.h"
#define PCR_TIME_BASE 27000000
@@ -79,7 +78,11 @@ typedef struct MpegTSWrite {
int start_pid;
int m2ts_mode;
- int reemit_pat_pmt;
+ int reemit_pat_pmt; // backward compatibility
+
+#define MPEGTS_FLAG_REEMIT_PAT_PMT 0x01
+#define MPEGTS_FLAG_AAC_LATM 0x02
+ int flags;
} MpegTSWrite;
/* a PES packet header is generated every DEFAULT_PES_HEADER_FREQ packets */
@@ -103,6 +106,15 @@ static const AVOption options[] = {
{ "muxrate", NULL, offsetof(MpegTSWrite, mux_rate), AV_OPT_TYPE_INT, {1}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
{ "pes_payload_size", "Minimum PES packet payload in bytes",
offsetof(MpegTSWrite, pes_payload_size), AV_OPT_TYPE_INT, {DEFAULT_PES_PAYLOAD_SIZE}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
+ { "mpegts_flags", "MPEG-TS muxing flags", offsetof(MpegTSWrite, flags), AV_OPT_TYPE_FLAGS, {.dbl = 0}, 0, INT_MAX,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags" },
+ { "resend_headers", "Reemit PAT/PMT before writing the next packet",
+ 0, AV_OPT_TYPE_CONST, {.dbl = MPEGTS_FLAG_REEMIT_PAT_PMT}, 0, INT_MAX,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags"},
+ { "latm", "Use LATM packetization for AAC",
+ 0, AV_OPT_TYPE_CONST, {.dbl = MPEGTS_FLAG_AAC_LATM}, 0, INT_MAX,
+ AV_OPT_FLAG_ENCODING_PARAM, "mpegts_flags"},
+ // backward compatibility
{ "resend_headers", "Reemit PAT/PMT before writing the next packet",
offsetof(MpegTSWrite, reemit_pat_pmt), AV_OPT_TYPE_INT, {0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
{ NULL },
@@ -220,7 +232,11 @@ typedef struct MpegTSWriteStream {
int64_t payload_dts;
int payload_flags;
uint8_t *payload;
- ADTSContext *adts;
+
+ uint8_t *adata;
+ int adata_pos;
+ int adata_size;
+ AVFormatContext *amux;
} MpegTSWriteStream;
static void mpegts_write_pat(AVFormatContext *s)
@@ -242,7 +258,7 @@ static void mpegts_write_pat(AVFormatContext *s)
static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
{
- // MpegTSWrite *ts = s->priv_data;
+ MpegTSWrite *ts = s->priv_data;
uint8_t data[1012], *q, *desc_length_ptr, *program_info_length_ptr;
int val, stream_type, i;
@@ -281,7 +297,7 @@ static void mpegts_write_pmt(AVFormatContext *s, MpegTSService *service)
stream_type = STREAM_TYPE_AUDIO_MPEG1;
break;
case CODEC_ID_AAC:
- stream_type = STREAM_TYPE_AUDIO_AAC;
+ stream_type = (ts->flags & MPEGTS_FLAG_AAC_LATM) ? STREAM_TYPE_AUDIO_AAC_LATM : STREAM_TYPE_AUDIO_AAC;
break;
case CODEC_ID_AAC_LATM:
stream_type = STREAM_TYPE_AUDIO_AAC_LATM;
@@ -487,6 +503,19 @@ static void section_write_packet(MpegTSSection *s, const uint8_t *packet)
avio_write(ctx->pb, packet, TS_PACKET_SIZE);
}
+/* Write callback for audio packetizer */
+static int mpegts_audio_write(void *opaque, uint8_t *buf, int size)
+{
+ MpegTSWriteStream *ts_st = (MpegTSWriteStream *)opaque;
+ if (ts_st->adata_pos + size > ts_st->adata_size)
+ return AVERROR(EIO);
+
+ memcpy(ts_st->adata + ts_st->adata_pos, buf, size);
+ ts_st->adata_pos += size;
+
+ return 0;
+}
+
static int mpegts_write_header(AVFormatContext *s)
{
MpegTSWrite *ts = s->priv_data;
@@ -498,6 +527,7 @@ static int mpegts_write_header(AVFormatContext *s)
const char *service_name;
const char *provider_name;
int *pids;
+ int ret;
if (s->max_delay < 0) /* Not set by the caller */
s->max_delay = 0;
@@ -538,12 +568,16 @@ static int mpegts_write_header(AVFormatContext *s)
st = s->streams[i];
avpriv_set_pts_info(st, 33, 1, 90000);
ts_st = av_mallocz(sizeof(MpegTSWriteStream));
- if (!ts_st)
+ if (!ts_st) {
+ ret = AVERROR(ENOMEM);
goto fail;
+ }
st->priv_data = ts_st;
ts_st->payload = av_mallocz(ts->pes_payload_size);
- if (!ts_st->payload)
+ if (!ts_st->payload) {
+ ret = AVERROR(ENOMEM);
goto fail;
+ }
ts_st->service = service;
/* MPEG pid values < 16 are reserved. Applications which set st->id in
* this range are assigned a calculated pid. */
@@ -553,15 +587,18 @@ static int mpegts_write_header(AVFormatContext *s)
ts_st->pid = st->id;
} else {
av_log(s, AV_LOG_ERROR, "Invalid stream id %d, must be less than 8191\n", st->id);
+ ret = AVERROR(EINVAL);
goto fail;
}
if (ts_st->pid == service->pmt.pid) {
av_log(s, AV_LOG_ERROR, "Duplicate stream id %d\n", ts_st->pid);
+ ret = AVERROR(EINVAL);
goto fail;
}
for (j = 0; j < i; j++)
if (pids[j] == ts_st->pid) {
av_log(s, AV_LOG_ERROR, "Duplicate stream id %d\n", ts_st->pid);
+ ret = AVERROR(EINVAL);
goto fail;
}
pids[i] = ts_st->pid;
@@ -576,12 +613,39 @@ static int mpegts_write_header(AVFormatContext *s)
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)
+ st->codec->extradata_size > 0)
+ {
+ AVStream *ast;
+ uint8_t *buffer;
+ int buffer_size = 32768;
+ ts_st->amux = avformat_alloc_context();
+ if (!ts_st->amux) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ buffer = av_malloc(buffer_size);
+ if (!buffer) {
+ ret = AVERROR(ENOMEM);
+ goto fail;
+ }
+ ts_st->amux->pb = avio_alloc_context(buffer, buffer_size, AVIO_FLAG_WRITE,
+ ts_st, NULL, mpegts_audio_write, NULL);
+ if (!ts_st->amux->pb) {
+ av_free(buffer);
+ ret = AVERROR(ENOMEM);
goto fail;
- if (ff_adts_decode_extradata(s, ts_st->adts, st->codec->extradata,
- st->codec->extradata_size) < 0)
+ }
+ ts_st->amux->oformat = av_guess_format((ts->flags & MPEGTS_FLAG_AAC_LATM) ? "latm" : "adts", NULL, NULL);
+ if (!ts_st->amux->oformat) {
+ ret = AVERROR(EINVAL);
+ goto fail;
+ }
+ ast = avformat_new_stream(ts_st->amux, NULL);
+ ret = avcodec_copy_context(ast->codec, st->codec);
+ if (ret != 0)
+ goto fail;
+ ret = avformat_write_header(ts_st->amux, NULL);
+ if (ret < 0)
goto fail;
}
}
@@ -658,11 +722,15 @@ static int mpegts_write_header(AVFormatContext *s)
ts_st = st->priv_data;
if (ts_st) {
av_freep(&ts_st->payload);
- av_freep(&ts_st->adts);
+ if (ts_st->amux) {
+ av_free(ts_st->amux->pb->buffer);
+ av_free(ts_st->amux->pb);
+ avformat_free_context(ts_st->amux);
+ }
}
av_freep(&st->priv_data);
}
- return AVERROR(EINVAL);
+ return ret;
}
/* send SDT, PAT and PMT tables regulary */
@@ -994,9 +1062,15 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
int64_t dts = AV_NOPTS_VALUE, pts = AV_NOPTS_VALUE;
if (ts->reemit_pat_pmt) {
+ av_log(s, AV_LOG_WARNING, "resend_headers option is deprecated, use -mpegts_flags resend_headers\n");
+ ts->reemit_pat_pmt = 0;
+ ts->flags |= MPEGTS_FLAG_REEMIT_PAT_PMT;
+ }
+
+ if (ts->flags & MPEGTS_FLAG_REEMIT_PAT_PMT) {
ts->pat_packet_count = ts->pat_packet_period - 1;
ts->sdt_packet_count = ts->sdt_packet_period - 1;
- ts->reemit_pat_pmt = 0;
+ ts->flags &= ~MPEGTS_FLAG_REEMIT_PAT_PMT;
}
if (pkt->pts != AV_NOPTS_VALUE)
@@ -1017,7 +1091,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
if (pkt->size < 5 || AV_RB32(pkt->data) != 0x0000001) {
av_log(s, AV_LOG_ERROR, "H.264 bitstream malformed, "
"no startcode found, use the h264_mp4toannexb bitstream filter (-bsf h264_mp4toannexb)\n");
- return AVERROR_INVALIDDATA;
+ return AVERROR(EINVAL);
}
do {
@@ -1038,35 +1112,41 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
size = pkt->size+6;
}
} else if (st->codec->codec_id == CODEC_ID_AAC) {
- if (pkt->size < 2)
+ if (pkt->size < 2) {
+ av_log(s, AV_LOG_ERROR, "AAC packet too short\n");
return AVERROR_INVALIDDATA;
+ }
if ((AV_RB16(pkt->data) & 0xfff0) != 0xfff0) {
- ADTSContext *adts = ts_st->adts;
- int new_size, err;
- if (!adts) {
+ int ret;
+ AVPacket pkt2;
+
+ if (!ts_st->amux) {
av_log(s, AV_LOG_ERROR, "AAC bitstream not in ADTS format "
"and extradata missing\n");
return AVERROR_INVALIDDATA;
}
- new_size = ADTS_HEADER_SIZE+adts->pce_size+pkt->size;
- if ((unsigned)new_size >= INT_MAX)
- return AVERROR_INVALIDDATA;
- data = av_malloc(new_size);
+
+ av_init_packet(&pkt2);
+ pkt2.data = pkt->data;
+ pkt2.size = pkt->size;
+ ts_st->adata_size = 1024 + pkt->size;
+ ts_st->adata = data = av_malloc(ts_st->adata_size);
+ ts_st->adata_pos = 0;
if (!data)
return AVERROR(ENOMEM);
- err = ff_adts_write_frame_header(adts, data, pkt->size,
- adts->pce_size);
- if (err < 0) {
+
+ ret = av_write_frame(ts_st->amux, &pkt2);
+ if (ret < 0) {
av_free(data);
- return err;
+ return ret;
}
- if (adts->pce_size) {
- memcpy(data+ADTS_HEADER_SIZE, adts->pce_data, adts->pce_size);
- adts->pce_size = 0;
+ avio_flush(ts_st->amux->pb);
+ if (ts_st->amux->pb->error < 0) {
+ av_free(data);
+ return ts_st->amux->pb->error;
}
- memcpy(data+ADTS_HEADER_SIZE+adts->pce_size, pkt->data, pkt->size);
- buf = data;
- size = new_size;
+ buf = ts_st->adata;
+ size = ts_st->adata_pos;
}
}
@@ -1154,7 +1234,11 @@ static int mpegts_write_end(AVFormatContext *s)
AVStream *st = s->streams[i];
MpegTSWriteStream *ts_st = st->priv_data;
av_freep(&ts_st->payload);
- av_freep(&ts_st->adts);
+ if (ts_st->amux) {
+ av_free(ts_st->amux->pb->buffer);
+ av_free(ts_st->amux->pb);
+ avformat_free_context(ts_st->amux);
+ }
}
for(i = 0; i < ts->nb_services; i++) {