From: Andrew D'Addesio <modchip...@gmail.com> Additionally add the codec_id for it. ---
Split out from GSOC repository, voluteers to help me getting at least silk in would be much appreciated. libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 ++ libavformat/Makefile | 1 + libavformat/oggdec.c | 3 +- libavformat/oggdec.h | 1 + libavformat/oggenc.c | 2 +- libavformat/oggparseopus.c | 136 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 libavformat/oggparseopus.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index efd1698..d8bad33 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -629,6 +629,7 @@ OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o \ mpegaudiodecheader.o mpegaudiodata.o OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ mpeg12.o mpeg12data.o +OBJS-$(CONFIG_OPUS_DECODER) += opus.o OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o OBJS-$(CONFIG_RV40_PARSER) += rv34_parser.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index c6df818..04a85a1 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -286,6 +286,7 @@ void avcodec_register_all(void) REGISTER_DECODER (MPC7, mpc7); REGISTER_DECODER (MPC8, mpc8); REGISTER_ENCDEC (NELLYMOSER, nellymoser); + REGISTER_DECODER (OPUS, opus); REGISTER_DECODER (QCELP, qcelp); REGISTER_DECODER (QDM2, qdm2); REGISTER_ENCDEC (RA_144, ra_144); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 8a091bd..c0c66e1 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -405,6 +405,7 @@ enum AVCodecID { AV_CODEC_ID_RALF, AV_CODEC_ID_IAC, AV_CODEC_ID_ILBC, + AV_CODEC_ID_OPUS, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 51fc171..818a35e 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -2105,6 +2105,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("iLBC (Internet Low Bitrate Codec)"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_OPUS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "opus", + .long_name = NULL_IF_CONFIG_SMALL("Opus (Opus Interactive Audio Codec)"), + .props = AV_CODEC_PROP_LOSSY, + }, /* subtitle codecs */ { diff --git a/libavformat/Makefile b/libavformat/Makefile index 61e1fa1..81be3cc 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -184,6 +184,7 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \ oggparsedirac.o \ oggparseflac.o \ oggparseogm.o \ + oggparseopus.o \ oggparseskeleton.o \ oggparsespeex.o \ oggparsetheora.o \ diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index e04a4e7..dd67115 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -46,6 +46,7 @@ static const struct ogg_codec * const ogg_codecs[] = { &ff_theora_codec, &ff_flac_codec, &ff_celt_codec, + &ff_opus_codec, &ff_old_dirac_codec, &ff_old_flac_codec, &ff_ogm_video_codec, @@ -661,6 +662,6 @@ AVInputFormat ff_ogg_demuxer = { .read_close = ogg_read_close, .read_seek = ogg_read_seek, .read_timestamp = ogg_read_timestamp, - .extensions = "ogg", + .extensions = "ogg,ogv,oga,spx,opus", .flags = AVFMT_GENERIC_INDEX, }; diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h index 184a628..5dafbd5 100644 --- a/libavformat/oggdec.h +++ b/libavformat/oggdec.h @@ -107,6 +107,7 @@ extern const struct ogg_codec ff_ogm_text_codec; extern const struct ogg_codec ff_ogm_video_codec; extern const struct ogg_codec ff_old_dirac_codec; extern const struct ogg_codec ff_old_flac_codec; +extern const struct ogg_codec ff_opus_codec; extern const struct ogg_codec ff_skeleton_codec; extern const struct ogg_codec ff_speex_codec; extern const struct ogg_codec ff_theora_codec; diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index c23a1ad..4c7f2d8 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -531,7 +531,7 @@ AVOutputFormat ff_ogg_muxer = { .name = "ogg", .long_name = NULL_IF_CONFIG_SMALL("Ogg"), .mime_type = "application/ogg", - .extensions = "ogg,ogv,spx", + .extensions = "ogg,ogv,oga,spx", .priv_data_size = sizeof(OGGContext), .audio_codec = AV_CODEC_ID_FLAC, .video_codec = AV_CODEC_ID_THEORA, diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c new file mode 100644 index 0000000..3ce6123 --- /dev/null +++ b/libavformat/oggparseopus.c @@ -0,0 +1,136 @@ +/* + * Opus parser for Ogg + * Copyright (c) 2011 Justin Ruggles + * + * 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. + * + * Libav 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/audioconvert.h" +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "oggdec.h" + +struct opus_params { + int header_count; + int pre_skip; +}; + +static const uint64_t opus_channel_layouts[9] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_QUAD, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER, + AV_CH_LAYOUT_7POINT1, + 0 +}; + +static int opus_header(AVFormatContext *s, int idx) { + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + struct opus_params *op = os->private; + AVStream *st = s->streams[idx]; + uint8_t *p = os->buf + os->pstart; + + if (!op) { + op = av_mallocz(sizeof(*op)); + if (!op) + return AVERROR(ENOMEM); + os->private = op; + } else if (op->header_count > 1) + return 0; + + if (op->header_count == 0) { + // ID header + if (os->psize < 19) { + av_log(s, AV_LOG_ERROR, "OpusHead header packet is too small\n"); + return AVERROR_INVALIDDATA; + } + if (memcmp(p, "OpusHead", 8)) { + av_log(s, AV_LOG_ERROR, "first packet must be an id header\n"); + return AVERROR_INVALIDDATA; + } + if (AV_RL8(p + 8) != 1) { + av_log(s, AV_LOG_ERROR, "unrecognized OggOpus version\n"); + return AVERROR_INVALIDDATA; + } + + st->codec->channels = AV_RL8(p + 9); + if (st->codec->channels == 0) { + av_log(s, AV_LOG_ERROR, "invalid number of source channels\n"); + return AVERROR_INVALIDDATA; + } + + op->pre_skip = AV_RL16(p + 10); + + st->codec->sample_rate = AV_RL32(p + 12); + if (st->codec->sample_rate == 0) { + av_log(s, AV_LOG_ERROR, "invalid sample rate\n"); + return AVERROR_INVALIDDATA; + } + + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = AV_CODEC_ID_OPUS; + st->codec->channel_layout = (st->codec->channels > 8) ? 0 : + opus_channel_layouts[st->codec->channels - 1]; + + if (AV_RL8(p + 18) == 0 && st->codec->channels > 2) + av_log(s, AV_LOG_WARNING, + "RTP channel mapping is undefined for more than one stream\n"); + if (AV_RL8(p + 18) > 1) + av_log(s, AV_LOG_WARNING, "channel mapping unrecognized\n"); + + avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); + } else { + // comment header + if (os->psize < 8) { + av_log(s, AV_LOG_ERROR, "OpusTags header packet is too small\n"); + return AVERROR_INVALIDDATA; + } + if (memcmp(p, "OpusTags", 8)) { + av_log(s, AV_LOG_ERROR, "second packet must be a comment header\n"); + return AVERROR_INVALIDDATA; + } + if (ff_vorbis_comment(s, &st->metadata, p + 8, os->psize - 8)) { + av_log(s, AV_LOG_ERROR, "invalid OpusTags header packet\n"); + return AVERROR_INVALIDDATA; + } + } + + op->header_count++; + return 1; +} + +static uint64_t opus_gptopts(AVFormatContext *s, int idx, uint64_t granule, + int64_t *dts_out) +{ + struct ogg *ogg = s->priv_data; + struct ogg_stream *os = ogg->streams + idx; + struct opus_params *op = os->private; + AVStream *st = s->streams[idx]; + return (granule - op->pre_skip)*st->codec->sample_rate/48000; +} + +const struct ogg_codec ff_opus_codec = { + .magic = "OpusHead", + .magicsize = 8, + .header = opus_header, + .gptopts = opus_gptopts, +}; -- 1.7.8.rc1 _______________________________________________ libav-devel mailing list libav-devel@libav.org https://lists.libav.org/mailman/listinfo/libav-devel