Skip to content
Snippets Groups Projects
Commit 87462968 authored by Justin Ruggles's avatar Justin Ruggles
Browse files

Add Speex support to the Ogg muxer.

Originally committed as revision 20220 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 24c6f152
No related branches found
No related tags found
No related merge requests found
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#define LIBAVFORMAT_VERSION_MAJOR 52 #define LIBAVFORMAT_VERSION_MAJOR 52
#define LIBAVFORMAT_VERSION_MINOR 39 #define LIBAVFORMAT_VERSION_MINOR 39
#define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_MICRO 1
#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, \
......
...@@ -83,10 +83,31 @@ static int ogg_write_page(AVFormatContext *s, const uint8_t *data, int size, ...@@ -83,10 +83,31 @@ static int ogg_write_page(AVFormatContext *s, const uint8_t *data, int size,
return size; return size;
} }
static uint8_t *ogg_write_vorbiscomment(int offset, int bitexact,
int *header_len)
{
const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
int size;
uint8_t *p, *p0;
size = offset + 4 + strlen(vendor) + 4;
p = av_mallocz(size);
if (!p)
return NULL;
p0 = p;
p += offset;
bytestream_put_le32(&p, strlen(vendor));
bytestream_put_buffer(&p, vendor, strlen(vendor));
bytestream_put_le32(&p, 0); // user comment list length
*header_len = size;
return p0;
}
static int ogg_build_flac_headers(AVCodecContext *avctx, static int ogg_build_flac_headers(AVCodecContext *avctx,
OGGStreamContext *oggstream, int bitexact) OGGStreamContext *oggstream, int bitexact)
{ {
const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT;
enum FLACExtradataFormat format; enum FLACExtradataFormat format;
uint8_t *streaminfo; uint8_t *streaminfo;
uint8_t *p; uint8_t *p;
...@@ -111,16 +132,40 @@ static int ogg_build_flac_headers(AVCodecContext *avctx, ...@@ -111,16 +132,40 @@ static int ogg_build_flac_headers(AVCodecContext *avctx,
bytestream_put_buffer(&p, streaminfo, FLAC_STREAMINFO_SIZE); bytestream_put_buffer(&p, streaminfo, FLAC_STREAMINFO_SIZE);
// second packet: VorbisComment // second packet: VorbisComment
oggstream->header_len[1] = 1+3+4+strlen(vendor)+4; p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1]);
oggstream->header[1] = av_mallocz(oggstream->header_len[1]);
p = oggstream->header[1];
if (!p) if (!p)
return AVERROR_NOMEM; return AVERROR_NOMEM;
oggstream->header[1] = p;
bytestream_put_byte(&p, 0x84); // last metadata block and vorbis comment bytestream_put_byte(&p, 0x84); // last metadata block and vorbis comment
bytestream_put_be24(&p, oggstream->header_len[1] - 4); bytestream_put_be24(&p, oggstream->header_len[1] - 4);
bytestream_put_le32(&p, strlen(vendor));
bytestream_put_buffer(&p, vendor, strlen(vendor)); return 0;
bytestream_put_le32(&p, 0); // user comment list length }
#define SPEEX_HEADER_SIZE 80
static int ogg_build_speex_headers(AVCodecContext *avctx,
OGGStreamContext *oggstream, int bitexact)
{
uint8_t *p;
if (avctx->extradata_size < SPEEX_HEADER_SIZE)
return -1;
// first packet: Speex header
p = av_mallocz(SPEEX_HEADER_SIZE);
if (!p)
return AVERROR_NOMEM;
oggstream->header[0] = p;
oggstream->header_len[0] = SPEEX_HEADER_SIZE;
bytestream_put_buffer(&p, avctx->extradata, SPEEX_HEADER_SIZE);
AV_WL32(&oggstream->header[0][68], 0); // set extra_headers to 0
// second packet: VorbisComment
p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1]);
if (!p)
return AVERROR_NOMEM;
oggstream->header[1] = p;
return 0; return 0;
} }
...@@ -137,6 +182,7 @@ static int ogg_write_header(AVFormatContext *s) ...@@ -137,6 +182,7 @@ static int ogg_write_header(AVFormatContext *s)
av_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den); av_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den);
if (st->codec->codec_id != CODEC_ID_VORBIS && if (st->codec->codec_id != CODEC_ID_VORBIS &&
st->codec->codec_id != CODEC_ID_THEORA && st->codec->codec_id != CODEC_ID_THEORA &&
st->codec->codec_id != CODEC_ID_SPEEX &&
st->codec->codec_id != CODEC_ID_FLAC) { st->codec->codec_id != CODEC_ID_FLAC) {
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;
...@@ -156,6 +202,14 @@ static int ogg_write_header(AVFormatContext *s) ...@@ -156,6 +202,14 @@ 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 == CODEC_ID_SPEEX) {
int err = ogg_build_speex_headers(st->codec, oggstream,
st->codec->flags & CODEC_FLAG_BITEXACT);
if (err) {
av_log(s, AV_LOG_ERROR, "Error writing Speex headers\n");
av_freep(&st->priv_data);
return err;
}
} else { } else {
if (ff_split_xiph_headers(st->codec->extradata, st->codec->extradata_size, if (ff_split_xiph_headers(st->codec->extradata, st->codec->extradata_size,
st->codec->codec_id == CODEC_ID_VORBIS ? 30 : 42, st->codec->codec_id == CODEC_ID_VORBIS ? 30 : 42,
...@@ -281,7 +335,8 @@ static int ogg_write_trailer(AVFormatContext *s) ...@@ -281,7 +335,8 @@ static int ogg_write_trailer(AVFormatContext *s)
for (i = 0; i < s->nb_streams; i++) { for (i = 0; i < s->nb_streams; i++) {
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 == CODEC_ID_FLAC) { if (st->codec->codec_id == CODEC_ID_FLAC ||
st->codec->codec_id == CODEC_ID_SPEEX) {
av_free(oggstream->header[0]); av_free(oggstream->header[0]);
av_free(oggstream->header[1]); av_free(oggstream->header[1]);
} }
...@@ -294,7 +349,7 @@ AVOutputFormat ogg_muxer = { ...@@ -294,7 +349,7 @@ AVOutputFormat ogg_muxer = {
"ogg", "ogg",
NULL_IF_CONFIG_SMALL("Ogg"), NULL_IF_CONFIG_SMALL("Ogg"),
"application/ogg", "application/ogg",
"ogg,ogv", "ogg,ogv,spx",
0, 0,
CODEC_ID_FLAC, CODEC_ID_FLAC,
CODEC_ID_THEORA, CODEC_ID_THEORA,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment