Message ID | BYAPR15MB26474298A5117FF35E2F9E43F78E0@BYAPR15MB2647.namprd15.prod.outlook.com |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel,v2] avformat/oggenc: Add partial support for OggPCM muxing | expand |
Context | Check | Description |
---|---|---|
andriy/default | pending | |
andriy/make | success | Make finished |
andriy/make_fate | success | Make fate finished |
Apologies for the previous patch (v1), the commit message was incorrect and I failed to add the requested change.
> +static const struct ogg_pcm_codec { > + uint32_t codec_id; > + uint32_t format_id; > +} ogg_pcm_codecs[] = { > + { AV_CODEC_ID_PCM_S8, 0x00 }, > + { AV_CODEC_ID_PCM_U8, 0x01 }, > + { AV_CODEC_ID_PCM_S16LE, 0x02 }, > + { AV_CODEC_ID_PCM_S16BE, 0x03 }, > + { AV_CODEC_ID_PCM_S24LE, 0x04 }, > + { AV_CODEC_ID_PCM_S24BE, 0x05 }, > + { AV_CODEC_ID_PCM_S32LE, 0x06 }, > + { AV_CODEC_ID_PCM_S32BE, 0x07 }, > + { AV_CODEC_ID_PCM_F32LE, 0x20 }, > + { AV_CODEC_ID_PCM_F32BE, 0x21 }, > + { AV_CODEC_ID_PCM_F64LE, 0x22 }, > + { AV_CODEC_ID_PCM_F64BE, 0x23 }, > +}; > + > +static inline uint32_t ogg_get_pcm_format_id(uint32_t codec_id) > +{ > + int i; > + > + for (i = 0; i < FF_ARRAY_ELEMS(ogg_pcm_codecs); i++) > + if (ogg_pcm_codecs[i].codec_id == codec_id) > + return ogg_pcm_codecs[i].format_id; > + > + return 0; > +} > + The ogg_get_pcm_format_id cannot return 0 for an unsupported format since that is already assigned to pcm_s8.
May 28, 2020, 11:34 by oreo639@outlook.com: > This adds partial support for OggPCM muxing. > > +static inline uint32_t ogg_get_pcm_format_id(uint32_t codec_id) > use enum AVCodecID instead of uint32_t. Also use that in ogg_pcm_codec for the codec IDs. > +{ > + int i; > + > + for (i = 0; i < FF_ARRAY_ELEMS(ogg_pcm_codecs); i++) > Save 2 lines, use for (int i... > + if (ogg_pcm_codecs[i].codec_id == codec_id) > + return ogg_pcm_codecs[i].format_id; > + > + return 0; > return AV_CODEC_ID_NONE; > +} > + > static void ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) > { > OGGStreamContext *oggstream = s->streams[page->stream_index]->priv_data; > @@ -363,6 +393,39 @@ static int ogg_build_speex_headers(AVCodecParameters *par, > return 0; > } > > +#define OGGPCM_HEADER_SIZE 224 > + > +static int ogg_build_pcm_headers(AVCodecParameters *par, > + OGGStreamContext *oggstream, int bitexact, > + AVDictionary **m) > Indentation seems wrong here. > +{ > + uint8_t *p; > + > + // first packet: OggPCM header > + p = av_mallocz(OGGPCM_HEADER_SIZE); > + if (!p) > + return AVERROR(ENOMEM); > + oggstream->header[0] = p; > + oggstream->header_len[0] = OGGPCM_HEADER_SIZE; > + bytestream_put_buffer(&p, "PCM ", 8); // Identifier > + bytestream_put_be16(&p, 0x00); // VMAJ > + bytestream_put_be16(&p, 0x00); // VMIN > + bytestream_put_be32(&p, ogg_get_pcm_format_id(par->codec_id)); // PCM fmt > + bytestream_put_be32(&p, par->sample_rate); // Sample rate > + bytestream_put_byte(&p, 0); // Significant bits (0 == Same as fmt) > That's not correct. par->bits_per_raw_sample is what you want it set to. > + bytestream_put_byte(&p, par->channels); // Channels > + bytestream_put_be16(&p, 0); // Max frames per packet TODO:// Actually calculate max frames per packet > That's not really possible. PCM data packets can contain any number of samples. Best you can do is place an upper bound for it, since an Ogg packet cannot be larger than 65xxx bytes. > + bytestream_put_be32(&p, 0); // Number of extra headers > + > + // second packet: VorbisComment > + p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0, NULL, 0); > + if (!p) > + return AVERROR(ENOMEM); > + oggstream->header[1] = p; > + > + return 0; > +} > + > #define OPUS_HEADER_SIZE 19 > > static int ogg_build_opus_headers(AVCodecParameters *par, > @@ -487,18 +550,20 @@ static int ogg_init(AVFormatContext *s) > avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); > } > > - if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS && > - st->codecpar->codec_id != AV_CODEC_ID_THEORA && > - st->codecpar->codec_id != AV_CODEC_ID_SPEEX && > - st->codecpar->codec_id != AV_CODEC_ID_FLAC && > - st->codecpar->codec_id != AV_CODEC_ID_OPUS && > + if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS && > + st->codecpar->codec_id != AV_CODEC_ID_THEORA && > + st->codecpar->codec_id != AV_CODEC_ID_SPEEX && > + st->codecpar->codec_id != AV_CODEC_ID_FLAC && > + st->codecpar->codec_id != AV_CODEC_ID_OPUS && > + !ogg_get_pcm_format_id(st->codecpar->codec_id) && > st->codecpar->codec_id != AV_CODEC_ID_VP8) { > av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i); > return AVERROR(EINVAL); > } > > if ((!st->codecpar->extradata || !st->codecpar->extradata_size) && > - st->codecpar->codec_id != AV_CODEC_ID_VP8) { > + st->codecpar->codec_id != AV_CODEC_ID_VP8 && > + !ogg_get_pcm_format_id(st->codecpar->codec_id)) { > av_log(s, AV_LOG_ERROR, "No extradata present\n"); > return AVERROR_INVALIDDATA; > } > @@ -553,6 +618,14 @@ static int ogg_init(AVFormatContext *s) > av_log(s, AV_LOG_ERROR, "Error writing VP8 headers\n"); > return err; > } > + } else if (ogg_get_pcm_format_id(st->codecpar->codec_id)) { > + int err = ogg_build_pcm_headers(st->codecpar, oggstream, > + s->flags & AVFMT_FLAG_BITEXACT, > + &st->metadata); > Indent seems wrong here too.
diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index f5032759a6..153f7f6760 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -99,6 +99,36 @@ static const AVClass flavor ## _muxer_class = {\ .version = LIBAVUTIL_VERSION_INT,\ }; + +static const struct ogg_pcm_codec { + uint32_t codec_id; + uint32_t format_id; +} ogg_pcm_codecs[] = { + { AV_CODEC_ID_PCM_S8, 0x00 }, + { AV_CODEC_ID_PCM_U8, 0x01 }, + { AV_CODEC_ID_PCM_S16LE, 0x02 }, + { AV_CODEC_ID_PCM_S16BE, 0x03 }, + { AV_CODEC_ID_PCM_S24LE, 0x04 }, + { AV_CODEC_ID_PCM_S24BE, 0x05 }, + { AV_CODEC_ID_PCM_S32LE, 0x06 }, + { AV_CODEC_ID_PCM_S32BE, 0x07 }, + { AV_CODEC_ID_PCM_F32LE, 0x20 }, + { AV_CODEC_ID_PCM_F32BE, 0x21 }, + { AV_CODEC_ID_PCM_F64LE, 0x22 }, + { AV_CODEC_ID_PCM_F64BE, 0x23 }, +}; + +static inline uint32_t ogg_get_pcm_format_id(uint32_t codec_id) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(ogg_pcm_codecs); i++) + if (ogg_pcm_codecs[i].codec_id == codec_id) + return ogg_pcm_codecs[i].format_id; + + return 0; +} + static void ogg_write_page(AVFormatContext *s, OGGPage *page, int extra_flags) { OGGStreamContext *oggstream = s->streams[page->stream_index]->priv_data; @@ -363,6 +393,39 @@ static int ogg_build_speex_headers(AVCodecParameters *par, return 0; } +#define OGGPCM_HEADER_SIZE 224 + +static int ogg_build_pcm_headers(AVCodecParameters *par, + OGGStreamContext *oggstream, int bitexact, + AVDictionary **m) +{ + uint8_t *p; + + // first packet: OggPCM header + p = av_mallocz(OGGPCM_HEADER_SIZE); + if (!p) + return AVERROR(ENOMEM); + oggstream->header[0] = p; + oggstream->header_len[0] = OGGPCM_HEADER_SIZE; + bytestream_put_buffer(&p, "PCM ", 8); // Identifier + bytestream_put_be16(&p, 0x00); // VMAJ + bytestream_put_be16(&p, 0x00); // VMIN + bytestream_put_be32(&p, ogg_get_pcm_format_id(par->codec_id)); // PCM fmt + bytestream_put_be32(&p, par->sample_rate); // Sample rate + bytestream_put_byte(&p, 0); // Significant bits (0 == Same as fmt) + bytestream_put_byte(&p, par->channels); // Channels + bytestream_put_be16(&p, 0); // Max frames per packet TODO:// Actually calculate max frames per packet + bytestream_put_be32(&p, 0); // Number of extra headers + + // second packet: VorbisComment + p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0, NULL, 0); + if (!p) + return AVERROR(ENOMEM); + oggstream->header[1] = p; + + return 0; +} + #define OPUS_HEADER_SIZE 19 static int ogg_build_opus_headers(AVCodecParameters *par, @@ -487,18 +550,20 @@ static int ogg_init(AVFormatContext *s) avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); } - if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS && - st->codecpar->codec_id != AV_CODEC_ID_THEORA && - st->codecpar->codec_id != AV_CODEC_ID_SPEEX && - st->codecpar->codec_id != AV_CODEC_ID_FLAC && - st->codecpar->codec_id != AV_CODEC_ID_OPUS && + if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS && + st->codecpar->codec_id != AV_CODEC_ID_THEORA && + st->codecpar->codec_id != AV_CODEC_ID_SPEEX && + st->codecpar->codec_id != AV_CODEC_ID_FLAC && + st->codecpar->codec_id != AV_CODEC_ID_OPUS && + !ogg_get_pcm_format_id(st->codecpar->codec_id) && st->codecpar->codec_id != AV_CODEC_ID_VP8) { av_log(s, AV_LOG_ERROR, "Unsupported codec id in stream %d\n", i); return AVERROR(EINVAL); } if ((!st->codecpar->extradata || !st->codecpar->extradata_size) && - st->codecpar->codec_id != AV_CODEC_ID_VP8) { + st->codecpar->codec_id != AV_CODEC_ID_VP8 && + !ogg_get_pcm_format_id(st->codecpar->codec_id)) { av_log(s, AV_LOG_ERROR, "No extradata present\n"); return AVERROR_INVALIDDATA; } @@ -553,6 +618,14 @@ static int ogg_init(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "Error writing VP8 headers\n"); return err; } + } else if (ogg_get_pcm_format_id(st->codecpar->codec_id)) { + int err = ogg_build_pcm_headers(st->codecpar, oggstream, + s->flags & AVFMT_FLAG_BITEXACT, + &st->metadata); + if (err) { + av_log(s, AV_LOG_ERROR, "Error writing OggPCM headers\n"); + return err; + } } else { uint8_t *p; const char *cstr = st->codecpar->codec_id == AV_CODEC_ID_VORBIS ? "vorbis" : "theora"; @@ -729,6 +802,7 @@ static void ogg_free(AVFormatContext *s) if (st->codecpar->codec_id == AV_CODEC_ID_FLAC || st->codecpar->codec_id == AV_CODEC_ID_SPEEX || st->codecpar->codec_id == AV_CODEC_ID_OPUS || + ogg_get_pcm_format_id(st->codecpar->codec_id) || st->codecpar->codec_id == AV_CODEC_ID_VP8) { av_freep(&oggstream->header[0]); }