summaryrefslogtreecommitdiff
path: root/libavformat/latmenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/latmenc.c')
-rw-r--r--libavformat/latmenc.c108
1 files changed, 79 insertions, 29 deletions
diff --git a/libavformat/latmenc.c b/libavformat/latmenc.c
index a98a6ff6b0..43ca4821cb 100644
--- a/libavformat/latmenc.c
+++ b/libavformat/latmenc.c
@@ -2,20 +2,20 @@
* LATM/LOAS muxer
* Copyright (c) 2011 Kieran Kunhya <kieran@kunhya.com>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * 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.
*
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -25,6 +25,10 @@
#include "libavcodec/mpeg4audio.h"
#include "libavutil/opt.h"
#include "avformat.h"
+#include "internal.h"
+#include "rawenc.h"
+
+#define MAX_EXTRADATA_SIZE 1024
typedef struct LATMContext {
AVClass *av_class;
@@ -33,6 +37,7 @@ typedef struct LATMContext {
int object_type;
int counter;
int mod;
+ uint8_t buffer[0x1fff + MAX_EXTRADATA_SIZE + 1024];
} LATMContext;
static const AVOption options[] = {
@@ -50,15 +55,21 @@ static const AVClass latm_muxer_class = {
static int latm_decode_extradata(LATMContext *ctx, uint8_t *buf, int size)
{
- GetBitContext gb;
MPEG4AudioConfig m4ac;
- init_get_bits(&gb, buf, size * 8);
+ if (size > MAX_EXTRADATA_SIZE) {
+ av_log(ctx, AV_LOG_ERROR, "Extradata is larger than currently supported.\n");
+ return AVERROR_INVALIDDATA;
+ }
ctx->off = avpriv_mpeg4audio_get_config(&m4ac, buf, size * 8, 1);
if (ctx->off < 0)
return ctx->off;
- skip_bits_long(&gb, ctx->off);
+ if (ctx->object_type == AOT_ALS && (ctx->off & 7)) {
+ // as long as avpriv_mpeg4audio_get_config works correctly this is impossible
+ av_log(ctx, AV_LOG_ERROR, "BUG: ALS offset is not byte-aligned\n");
+ return AVERROR_INVALIDDATA;
+ }
/* FIXME: are any formats not allowed in LATM? */
if (m4ac.object_type > AOT_SBR && m4ac.object_type != AOT_ALS) {
@@ -76,6 +87,9 @@ static int latm_write_header(AVFormatContext *s)
LATMContext *ctx = s->priv_data;
AVCodecParameters *par = s->streams[0]->codecpar;
+ if (par->codec_id == AV_CODEC_ID_AAC_LATM)
+ return 0;
+
if (par->extradata_size > 0 &&
latm_decode_extradata(ctx, par->extradata, par->extradata_size) < 0)
return AVERROR_INVALIDDATA;
@@ -83,19 +97,16 @@ static int latm_write_header(AVFormatContext *s)
return 0;
}
-static int latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
+static void latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
{
LATMContext *ctx = s->priv_data;
AVCodecParameters *par = s->streams[0]->codecpar;
- GetBitContext gb;
int header_size;
/* AudioMuxElement */
put_bits(bs, 1, !!ctx->counter);
if (!ctx->counter) {
- init_get_bits(&gb, par->extradata, par->extradata_size * 8);
-
/* StreamMuxConfig */
put_bits(bs, 1, 0); /* audioMuxVersion */
put_bits(bs, 1, 1); /* allStreamsSameTimeFraming */
@@ -105,12 +116,18 @@ static int latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
/* AudioSpecificConfig */
if (ctx->object_type == AOT_ALS) {
- header_size = par->extradata_size-(ctx->off + 7) >> 3;
- avpriv_copy_bits(bs, &par->extradata[ctx->off], header_size);
+ header_size = par->extradata_size-(ctx->off >> 3);
+ avpriv_copy_bits(bs, &par->extradata[ctx->off >> 3], header_size);
} else {
+ // + 3 assumes not scalable and dependsOnCoreCoder == 0,
+ // see decode_ga_specific_config in libavcodec/aacdec.c
avpriv_copy_bits(bs, par->extradata, ctx->off + 3);
if (!ctx->channel_conf) {
+ GetBitContext gb;
+ int ret = init_get_bits8(&gb, par->extradata, par->extradata_size);
+ av_assert0(ret >= 0); // extradata size has been checked already, so this should not fail
+ skip_bits_long(&gb, ctx->off + 3);
avpriv_copy_pce_data(bs, &gb);
}
}
@@ -124,28 +141,31 @@ static int latm_write_frame_header(AVFormatContext *s, PutBitContext *bs)
ctx->counter++;
ctx->counter %= ctx->mod;
-
- return 0;
}
static int latm_write_packet(AVFormatContext *s, AVPacket *pkt)
{
+ LATMContext *ctx = s->priv_data;
AVIOContext *pb = s->pb;
PutBitContext bs;
int i, len;
uint8_t loas_header[] = "\x56\xe0\x00";
- uint8_t *buf;
- if (pkt->size > 2 && pkt->data[0] == 0xff && (pkt->data[1] >> 4) == 0xf) {
- av_log(s, AV_LOG_ERROR, "ADTS header detected - ADTS will not be incorrectly muxed into LATM\n");
- return AVERROR_INVALIDDATA;
+ if (s->streams[0]->codecpar->codec_id == AV_CODEC_ID_AAC_LATM)
+ return ff_raw_write_packet(s, pkt);
+
+ if (!s->streams[0]->codecpar->extradata) {
+ if(pkt->size > 2 && pkt->data[0] == 0x56 && (pkt->data[1] >> 4) == 0xe &&
+ (AV_RB16(pkt->data + 1) & 0x1FFF) + 3 == pkt->size)
+ return ff_raw_write_packet(s, pkt);
+ else
+ return AVERROR_INVALIDDATA;
}
- buf = av_malloc(pkt->size+1024);
- if (!buf)
- return AVERROR(ENOMEM);
+ if (pkt->size > 0x1fff)
+ goto too_large;
- init_put_bits(&bs, buf, pkt->size+1024);
+ init_put_bits(&bs, ctx->buffer, pkt->size+1024+MAX_EXTRADATA_SIZE);
latm_write_frame_header(s, &bs);
@@ -158,35 +178,65 @@ static int latm_write_packet(AVFormatContext *s, AVPacket *pkt)
/* The LATM payload is written unaligned */
/* PayloadMux() */
- for (i = 0; i < pkt->size; i++)
- put_bits(&bs, 8, pkt->data[i]);
+ if (pkt->size && (pkt->data[0] & 0xe1) == 0x81) {
+ // Convert byte-aligned DSE to non-aligned.
+ // Due to the input format encoding we know that
+ // it is naturally byte-aligned in the input stream,
+ // so there are no padding bits to account for.
+ // To avoid having to add padding bits and rearrange
+ // the whole stream we just remove the byte-align flag.
+ // This allows us to remux our FATE AAC samples into latm
+ // files that are still playable with minimal effort.
+ put_bits(&bs, 8, pkt->data[0] & 0xfe);
+ avpriv_copy_bits(&bs, pkt->data + 1, 8*pkt->size - 8);
+ } else
+ avpriv_copy_bits(&bs, pkt->data, 8*pkt->size);
avpriv_align_put_bits(&bs);
flush_put_bits(&bs);
len = put_bits_count(&bs) >> 3;
+ if (len > 0x1fff)
+ goto too_large;
+
loas_header[1] |= (len >> 8) & 0x1f;
loas_header[2] |= len & 0xff;
avio_write(pb, loas_header, 3);
- avio_write(pb, buf, len);
-
- av_free(buf);
+ avio_write(pb, ctx->buffer, len);
return 0;
+
+too_large:
+ av_log(s, AV_LOG_ERROR, "LATM packet size larger than maximum size 0x1fff\n");
+ return AVERROR_INVALIDDATA;
+}
+
+static int latm_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt)
+{
+ int ret = 1;
+ AVStream *st = s->streams[pkt->stream_index];
+
+ if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
+ if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
+ ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
+ }
+
+ return ret;
}
AVOutputFormat ff_latm_muxer = {
.name = "latm",
.long_name = NULL_IF_CONFIG_SMALL("LOAS/LATM"),
.mime_type = "audio/MP4A-LATM",
- .extensions = "latm",
+ .extensions = "latm,loas",
.priv_data_size = sizeof(LATMContext),
.audio_codec = AV_CODEC_ID_AAC,
.video_codec = AV_CODEC_ID_NONE,
.write_header = latm_write_header,
.write_packet = latm_write_packet,
.priv_class = &latm_muxer_class,
+ .check_bitstream= latm_check_bitstream,
.flags = AVFMT_NOTIMESTAMPS,
};