Add Opus support to the Ogg muxer.
Signed-off-by: Diego Biurrun <diego@biurrun.de>
This commit is contained in:
parent
2a3d82ab46
commit
bcc1f7caeb
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 = {
|
|||||||
.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 @@
|
|||||||
|
|
||||||
#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, \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user