From 0832122880fa50e66dfd62eb6aa5c814f83f68d9 Mon Sep 17 00:00:00 2001 From: Juan Carlos Rodriguez Date: Wed, 18 May 2011 15:00:03 +0300 Subject: rtpenc: MP4A-LATM payload support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is enabled with an AVOption on the RTP muxer. The SDP generator looks for a latm flag in the rtpflags field. Signed-off-by: Martin Storsjö --- libavformat/Makefile | 1 + libavformat/rtpenc.c | 20 +++++++++++- libavformat/rtpenc.h | 6 ++++ libavformat/rtpenc_latm.c | 61 ++++++++++++++++++++++++++++++++++++ libavformat/sdp.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++ libavformat/version.h | 2 +- 6 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 libavformat/rtpenc_latm.c (limited to 'libavformat') diff --git a/libavformat/Makefile b/libavformat/Makefile index ba978af7a4..c2fa8af466 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -228,6 +228,7 @@ OBJS-$(CONFIG_RSO_MUXER) += rsoenc.o rso.o OBJS-$(CONFIG_RPL_DEMUXER) += rpl.o OBJS-$(CONFIG_RTP_MUXER) += rtp.o \ rtpenc_aac.o \ + rtpenc_latm.o \ rtpenc_amr.o \ rtpenc_h263.o \ rtpenc_mpv.o \ diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index 7cedff382e..c264b30a07 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -23,11 +23,25 @@ #include "mpegts.h" #include "internal.h" #include "libavutil/random_seed.h" +#include "libavutil/opt.h" #include "rtpenc.h" //#define DEBUG +static const AVOption options[] = { + { "rtpflags", "RTP muxer flags", offsetof(RTPMuxContext, flags), FF_OPT_TYPE_FLAGS, {.dbl = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, + { "latm", "Use MP4A-LATM packetization instead of MPEG4-GENERIC for AAC", 0, FF_OPT_TYPE_CONST, {.dbl = FF_RTP_FLAG_MP4A_LATM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "rtpflags" }, + { NULL }, +}; + +static const AVClass rtp_muxer_class = { + .class_name = "RTP muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + #define RTCP_SR_SIZE 28 static int is_supported(enum CodecID id) @@ -404,7 +418,10 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) ff_rtp_send_mpegvideo(s1, pkt->data, size); break; case CODEC_ID_AAC: - ff_rtp_send_aac(s1, pkt->data, size); + if (s->flags & FF_RTP_FLAG_MP4A_LATM) + ff_rtp_send_latm(s1, pkt->data, size); + else + ff_rtp_send_aac(s1, pkt->data, size); break; case CODEC_ID_AMR_NB: case CODEC_ID_AMR_WB: @@ -455,4 +472,5 @@ AVOutputFormat ff_rtp_muxer = { rtp_write_header, rtp_write_packet, rtp_write_trailer, + .priv_class = &rtp_muxer_class, }; diff --git a/libavformat/rtpenc.h b/libavformat/rtpenc.h index 21c5c312a4..ac5a62242d 100644 --- a/libavformat/rtpenc.h +++ b/libavformat/rtpenc.h @@ -25,6 +25,7 @@ #include "rtp.h" struct RTPMuxContext { + const AVClass *av_class; AVFormatContext *ic; AVStream *st; int payload_type; @@ -56,15 +57,20 @@ struct RTPMuxContext { * (1, 2 or 4) */ int nal_length_size; + + int flags; }; typedef struct RTPMuxContext RTPMuxContext; +#define FF_RTP_FLAG_MP4A_LATM 1 + void ff_rtp_send_data(AVFormatContext *s1, const uint8_t *buf1, int len, int m); void ff_rtp_send_h264(AVFormatContext *s1, const uint8_t *buf1, int size); void ff_rtp_send_h263(AVFormatContext *s1, const uint8_t *buf1, int size); void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size); +void ff_rtp_send_latm(AVFormatContext *s1, const uint8_t *buff, int size); void ff_rtp_send_amr(AVFormatContext *s1, const uint8_t *buff, int size); void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size); void ff_rtp_send_xiph(AVFormatContext *s1, const uint8_t *buff, int size); diff --git a/libavformat/rtpenc_latm.c b/libavformat/rtpenc_latm.c new file mode 100644 index 0000000000..aa6e29117f --- /dev/null +++ b/libavformat/rtpenc_latm.c @@ -0,0 +1,61 @@ +/* + * RTP Packetization of MPEG-4 Audio (RFC 3016) + * Copyright (c) 2011 Juan Carlos Rodriguez + * + * This file is part of Libav. + * + * Libav 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 + */ + +#include "avformat.h" +#include "rtpenc.h" + +void ff_rtp_send_latm(AVFormatContext *s1, const uint8_t *buff, int size) +{ + /* MP4A-LATM + * The RTP payload format specification is described in RFC 3016 + * The encoding specifications are provided in ISO/IEC 14496-3 */ + + RTPMuxContext *s = s1->priv_data; + int header_size; + int offset = 0; + int len = 0; + + /* skip ADTS header, if present */ + if ((s1->streams[0]->codec->extradata_size) == 0) { + size -= 7; + buff += 7; + } + + /* PayloadLengthInfo() */ + header_size = size/0xFF + 1; + memset(s->buf, 0xFF, header_size - 1); + s->buf[header_size - 1] = size % 0xFF; + + s->timestamp = s->cur_timestamp; + + /* PayloadMux() */ + while (size > 0) { + len = FFMIN(size, s->max_payload_size - (!offset ? header_size : 0)); + size -= len; + if (!offset) { + memcpy(s->buf + header_size, buff, len); + ff_rtp_send_data(s1, s->buf, header_size + len, !size); + } else { + ff_rtp_send_data(s1, buff + offset, len, !size); + } + offset += len; + } +} diff --git a/libavformat/sdp.c b/libavformat/sdp.c index b996bf65f5..92690f58a3 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -23,7 +23,9 @@ #include "libavutil/base64.h" #include "libavutil/dict.h" #include "libavutil/parseutils.h" +#include "libavutil/opt.h" #include "libavcodec/xiph.h" +#include "libavcodec/mpeg4audio.h" #include "avformat.h" #include "internal.h" #include "avc.h" @@ -300,6 +302,71 @@ xiph_fail: return NULL; } +static int latm_context2profilelevel(AVCodecContext *c) +{ + /* MP4A-LATM + * The RTP payload format specification is described in RFC 3016 + * The encoding specifications are provided in ISO/IEC 14496-3 */ + + int profile_level = 0x2B; + + /* TODO: AAC Profile only supports AAC LC Object Type. + * Different Object Types should implement different Profile Levels */ + + if (c->sample_rate <= 24000) { + if (c->channels <= 2) + profile_level = 0x28; // AAC Profile, Level 1 + } else if (c->sample_rate <= 48000) { + if (c->channels <= 2) { + profile_level = 0x29; // AAC Profile, Level 2 + } else if (c->channels <= 5) { + profile_level = 0x2A; // AAC Profile, Level 4 + } + } else if (c->sample_rate <= 96000) { + if (c->channels <= 5) { + profile_level = 0x2B; // AAC Profile, Level 5 + } + } + + return profile_level; +} + +static char *latm_context2config(AVCodecContext *c) +{ + /* MP4A-LATM + * The RTP payload format specification is described in RFC 3016 + * The encoding specifications are provided in ISO/IEC 14496-3 */ + + uint8_t config_byte[6]; + int rate_index; + char *config; + + for (rate_index = 0; rate_index < 16; rate_index++) + if (ff_mpeg4audio_sample_rates[rate_index] == c->sample_rate) + break; + if (rate_index == 16) { + av_log(c, AV_LOG_ERROR, "Unsupported sample rate\n"); + return NULL; + } + + config_byte[0] = 0x40; + config_byte[1] = 0; + config_byte[2] = 0x20 | rate_index; + config_byte[3] = c->channels << 4; + config_byte[4] = 0x3f; + config_byte[5] = 0xc0; + + config = av_malloc(6*2+1); + if (!config) { + av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n"); + return NULL; + } + ff_data_to_hex(config, config_byte, 6, 1); + config[12] = 0; + + return config; +} + static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, int payload_type, AVFormatContext *fmt) { char *config = NULL; @@ -335,6 +402,16 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, payload_type, config ? config : ""); break; case CODEC_ID_AAC: + if (fmt && fmt->oformat->priv_class && + av_opt_flag_is_set(fmt->priv_data, "rtpflags", "latm")) { + config = latm_context2config(c); + if (!config) + return NULL; + av_strlcatf(buff, size, "a=rtpmap:%d MP4A-LATM/%d/%d\r\n" + "a=fmtp:%d profile-level-id=%d;cpresent=0;config=%s\r\n", + payload_type, c->sample_rate, c->channels, + payload_type, latm_context2profilelevel(c), config); + } else { if (c->extradata_size) { config = extradata2config(c); } else { @@ -353,6 +430,7 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, "indexdeltalength=3%s\r\n", payload_type, c->sample_rate, c->channels, payload_type, config); + } break; case CODEC_ID_PCM_S16BE: if (payload_type >= RTP_PT_PRIVATE) diff --git a/libavformat/version.h b/libavformat/version.h index 0b53005a6f..ca61ab165f 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -25,7 +25,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 53 #define LIBAVFORMAT_VERSION_MINOR 1 -#define LIBAVFORMAT_VERSION_MICRO 0 +#define LIBAVFORMAT_VERSION_MICRO 1 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ -- cgit v1.2.3