Commit bcc1f7ca authored by Nathan Caldwell's avatar Nathan Caldwell Committed by Diego Biurrun

Add Opus support to the Ogg muxer.

Signed-off-by: 's avatarDiego Biurrun <diego@biurrun.de>
parent 2a3d82ab
...@@ -336,6 +336,35 @@ static int ogg_build_speex_headers(AVCodecContext *avctx, ...@@ -336,6 +336,35 @@ static int ogg_build_speex_headers(AVCodecContext *avctx,
return 0; return 0;
} }
#define OPUS_HEADER_SIZE 19
static int ogg_build_opus_headers(AVCodecContext *avctx,
OGGStreamContext *oggstream, int bitexact,
AVDictionary **m)
{
uint8_t *p;
if (avctx->extradata_size < OPUS_HEADER_SIZE)
return -1;
/* first packet: Opus header */
p = av_mallocz(avctx->extradata_size);
if (!p)
return AVERROR(ENOMEM);
oggstream->header[0] = p;
oggstream->header_len[0] = avctx->extradata_size;
bytestream_put_buffer(&p, avctx->extradata, avctx->extradata_size);
/* second packet: VorbisComment */
p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0);
if (!p)
return AVERROR(ENOMEM);
oggstream->header[1] = p;
bytestream_put_buffer(&p, "OpusTags", 8);
return 0;
}
static int ogg_write_header(AVFormatContext *s) static int ogg_write_header(AVFormatContext *s)
{ {
OGGStreamContext *oggstream; OGGStreamContext *oggstream;
...@@ -346,13 +375,18 @@ static int ogg_write_header(AVFormatContext *s) ...@@ -346,13 +375,18 @@ static int ogg_write_header(AVFormatContext *s)
unsigned serial_num = i; unsigned serial_num = i;
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO)
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); if (st->codec->codec_id == AV_CODEC_ID_OPUS)
/* Opus requires a fixed 48kHz clock */
avpriv_set_pts_info(st, 64, 1, 48000);
else
avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den); avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
if (st->codec->codec_id != AV_CODEC_ID_VORBIS && if (st->codec->codec_id != AV_CODEC_ID_VORBIS &&
st->codec->codec_id != AV_CODEC_ID_THEORA && st->codec->codec_id != AV_CODEC_ID_THEORA &&
st->codec->codec_id != AV_CODEC_ID_SPEEX && st->codec->codec_id != AV_CODEC_ID_SPEEX &&
st->codec->codec_id != AV_CODEC_ID_FLAC) { st->codec->codec_id != AV_CODEC_ID_FLAC &&
st->codec->codec_id != AV_CODEC_ID_OPUS) {
av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i); av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i);
return -1; return -1;
} }
...@@ -394,6 +428,15 @@ static int ogg_write_header(AVFormatContext *s) ...@@ -394,6 +428,15 @@ static int ogg_write_header(AVFormatContext *s)
av_freep(&st->priv_data); av_freep(&st->priv_data);
return err; return err;
} }
} else if (st->codec->codec_id == AV_CODEC_ID_OPUS) {
int err = ogg_build_opus_headers(st->codec, oggstream,
st->codec->flags & CODEC_FLAG_BITEXACT,
&s->metadata);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n");
av_freep(&st->priv_data);
return err;
}
} else { } else {
uint8_t *p; uint8_t *p;
const char *cstr = st->codec->codec_id == AV_CODEC_ID_VORBIS ? "vorbis" : "theora"; const char *cstr = st->codec->codec_id == AV_CODEC_ID_VORBIS ? "vorbis" : "theora";
...@@ -490,7 +533,9 @@ static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -490,7 +533,9 @@ static int ogg_write_packet(AVFormatContext *s, AVPacket *pkt)
pframe_count = 0; pframe_count = 0;
} }
granule = (oggstream->last_kf_pts<<oggstream->kfgshift) | pframe_count; granule = (oggstream->last_kf_pts<<oggstream->kfgshift) | pframe_count;
} else } else if (st->codec->codec_id == AV_CODEC_ID_OPUS)
granule = pkt->pts + pkt->duration + av_rescale_q(st->codec->delay, (AVRational){ 1, st->codec->sample_rate }, st->time_base);
else
granule = pkt->pts + pkt->duration; granule = pkt->pts + pkt->duration;
ret = ogg_buffer_data(s, st, pkt->data, pkt->size, granule, 0); ret = ogg_buffer_data(s, st, pkt->data, pkt->size, granule, 0);
...@@ -518,7 +563,8 @@ static int ogg_write_trailer(AVFormatContext *s) ...@@ -518,7 +563,8 @@ static int ogg_write_trailer(AVFormatContext *s)
AVStream *st = s->streams[i]; AVStream *st = s->streams[i];
OGGStreamContext *oggstream = st->priv_data; OGGStreamContext *oggstream = st->priv_data;
if (st->codec->codec_id == AV_CODEC_ID_FLAC || if (st->codec->codec_id == AV_CODEC_ID_FLAC ||
st->codec->codec_id == AV_CODEC_ID_SPEEX) { st->codec->codec_id == AV_CODEC_ID_SPEEX ||
st->codec->codec_id == AV_CODEC_ID_OPUS) {
av_free(oggstream->header[0]); av_free(oggstream->header[0]);
} }
av_freep(&oggstream->header[1]); av_freep(&oggstream->header[1]);
...@@ -531,7 +577,7 @@ AVOutputFormat ff_ogg_muxer = { ...@@ -531,7 +577,7 @@ AVOutputFormat ff_ogg_muxer = {
.name = "ogg", .name = "ogg",
.long_name = NULL_IF_CONFIG_SMALL("Ogg"), .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
.mime_type = "application/ogg", .mime_type = "application/ogg",
.extensions = "ogg,ogv,spx", .extensions = "ogg,ogv,spx,opus",
.priv_data_size = sizeof(OGGContext), .priv_data_size = sizeof(OGGContext),
.audio_codec = AV_CODEC_ID_FLAC, .audio_codec = AV_CODEC_ID_FLAC,
.video_codec = AV_CODEC_ID_THEORA, .video_codec = AV_CODEC_ID_THEORA,
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#define LIBAVFORMAT_VERSION_MAJOR 54 #define LIBAVFORMAT_VERSION_MAJOR 54
#define LIBAVFORMAT_VERSION_MINOR 17 #define LIBAVFORMAT_VERSION_MINOR 17
#define LIBAVFORMAT_VERSION_MICRO 2 #define LIBAVFORMAT_VERSION_MICRO 3
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \ LIBAVFORMAT_VERSION_MINOR, \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment