Mercurial > libavformat.hg
changeset 5857:121d6994c20e libavformat
Add VorbisComment writing to FLAC files.
Patch by James Darnley <james darnley at gmail>.
author | jbr |
---|---|
date | Sat, 20 Mar 2010 13:36:43 +0000 |
parents | a1121e5fa662 |
children | 274fed269b59 |
files | Makefile flacdec.c flacenc.c flacenc.h matroskaenc.c oggdec.c oggdec.h oggparsevorbis.c vorbiscomment.c vorbiscomment.h |
diffstat | 10 files changed, 204 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Thu Mar 18 00:22:58 2010 +0000 +++ b/Makefile Sat Mar 20 13:36:43 2010 +0000 @@ -69,8 +69,9 @@ OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o OBJS-$(CONFIG_FLAC_DEMUXER) += flacdec.o raw.o id3v1.o \ - id3v2.o oggparsevorbis.o -OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o + id3v2.o \ + vorbiscomment.o +OBJS-$(CONFIG_FLAC_MUXER) += flacenc.o vorbiscomment.o OBJS-$(CONFIG_FLIC_DEMUXER) += flic.o OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o @@ -148,7 +149,8 @@ oggparsespeex.o \ oggparsetheora.o \ oggparsevorbis.o \ - riff.o + riff.o \ + vorbiscomment.o OBJS-$(CONFIG_OGG_MUXER) += oggenc.o OBJS-$(CONFIG_OMA_DEMUXER) += oma.o raw.o OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += raw.o
--- a/flacdec.c Thu Mar 18 00:22:58 2010 +0000 +++ b/flacdec.c Sat Mar 20 13:36:43 2010 +0000 @@ -24,6 +24,7 @@ #include "raw.h" #include "id3v2.h" #include "oggdec.h" +#include "vorbiscomment.h" static int flac_read_header(AVFormatContext *s, AVFormatParameters *ap)
--- a/flacenc.c Thu Mar 18 00:22:58 2010 +0000 +++ b/flacenc.c Sat Mar 20 13:36:43 2010 +0000 @@ -22,15 +22,20 @@ #include "libavcodec/flac.h" #include "avformat.h" #include "flacenc.h" +#include "metadata.h" +#include "vorbiscomment.h" +#include "libavcodec/bytestream.h" -int ff_flac_write_header(ByteIOContext *pb, AVCodecContext *codec) +int ff_flac_write_header(ByteIOContext *pb, AVCodecContext *codec, + int last_block) { - static const uint8_t header[8] = { - 0x66, 0x4C, 0x61, 0x43, 0x80, 0x00, 0x00, 0x22 + uint8_t header[8] = { + 0x66, 0x4C, 0x61, 0x43, 0x00, 0x00, 0x00, 0x22 }; uint8_t *streaminfo; enum FLACExtradataFormat format; + header[4] = last_block ? 0x80 : 0x00; if (!ff_flac_is_extradata_valid(codec, &format, &streaminfo)) return -1; @@ -45,9 +50,63 @@ return 0; } +static int flac_write_block_padding(ByteIOContext *pb, unsigned int n_padding_bytes, + int last_block) +{ + put_byte(pb, last_block ? 0x81 : 0x01); + put_be24(pb, n_padding_bytes); + while (n_padding_bytes > 0) { + put_byte(pb, 0); + n_padding_bytes--; + } + return 0; +} + +static int flac_write_block_comment(ByteIOContext *pb, AVMetadata *m, + int last_block, int bitexact) +{ + const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; + unsigned int len, count; + uint8_t *p, *p0; + + len = ff_vorbiscomment_length(m, vendor, &count); + p0 = av_malloc(len+4); + if (!p0) + return AVERROR(ENOMEM); + p = p0; + + bytestream_put_byte(&p, last_block ? 0x84 : 0x04); + bytestream_put_be24(&p, len); + ff_vorbiscomment_write(&p, m, vendor, count); + + put_buffer(pb, p0, len+4); + av_freep(&p0); + p = NULL; + + return 0; +} + static int flac_write_header(struct AVFormatContext *s) { - return ff_flac_write_header(s->pb, s->streams[0]->codec); + int ret; + AVCodecContext *codec = s->streams[0]->codec; + + ret = ff_flac_write_header(s->pb, codec, 0); + if (ret) + return ret; + + ret = flac_write_block_comment(s->pb, s->metadata, 0, + codec->flags & CODEC_FLAG_BITEXACT); + if (ret) + return ret; + + /* The command line flac encoder defaults to placing a seekpoint + * every 10s. So one might add padding to allow that later + * but there seems to be no simple way to get the duration here. + * So let's try the flac default of 8192 bytes */ + flac_write_block_padding(s->pb, 8192, 1); + + return ret; } static int flac_write_trailer(struct AVFormatContext *s) @@ -92,4 +151,5 @@ flac_write_packet, flac_write_trailer, .flags= AVFMT_NOTIMESTAMPS, + .metadata_conv = ff_vorbiscomment_metadata_conv, };
--- a/flacenc.h Thu Mar 18 00:22:58 2010 +0000 +++ b/flacenc.h Sat Mar 20 13:36:43 2010 +0000 @@ -24,6 +24,7 @@ #include "avformat.h" -int ff_flac_write_header(ByteIOContext *pb, AVCodecContext *codec); +int ff_flac_write_header(ByteIOContext *pb, AVCodecContext *codec, + int last_block); #endif /* AVFORMAT_FLACENC_H */
--- a/matroskaenc.c Thu Mar 18 00:22:58 2010 +0000 +++ b/matroskaenc.c Sat Mar 20 13:36:43 2010 +0000 @@ -470,7 +470,7 @@ if (codec->codec_id == CODEC_ID_VORBIS || codec->codec_id == CODEC_ID_THEORA) ret = put_xiph_codecpriv(s, dyn_cp, codec); else if (codec->codec_id == CODEC_ID_FLAC) - ret = ff_flac_write_header(dyn_cp, codec); + ret = ff_flac_write_header(dyn_cp, codec, 1); else if (codec->codec_id == CODEC_ID_H264) ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); else if (codec->extradata_size)
--- a/oggdec.c Thu Mar 18 00:22:58 2010 +0000 +++ b/oggdec.c Sat Mar 20 13:36:43 2010 +0000 @@ -33,6 +33,7 @@ #include <stdio.h> #include "oggdec.h" #include "avformat.h" +#include "vorbiscomment.h" #define MAX_PAGE_SIZE 65307 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
--- a/oggdec.h Thu Mar 18 00:22:58 2010 +0000 +++ b/oggdec.h Sat Mar 20 13:36:43 2010 +0000 @@ -112,8 +112,6 @@ extern const struct ogg_codec ff_theora_codec; extern const struct ogg_codec ff_vorbis_codec; -extern const AVMetadataConv ff_vorbiscomment_metadata_conv[]; - int ff_vorbis_comment(AVFormatContext *ms, AVMetadata **m, const uint8_t *buf, int size); static inline int
--- a/oggparsevorbis.c Thu Mar 18 00:22:58 2010 +0000 +++ b/oggparsevorbis.c Sat Mar 20 13:36:43 2010 +0000 @@ -30,17 +30,6 @@ #include "avformat.h" #include "oggdec.h" -/** - * VorbisComment metadata conversion mapping. - * from Ogg Vorbis I format specification: comment field and header specification - * http://xiph.org/vorbis/doc/v-comment.html - */ -const AVMetadataConv ff_vorbiscomment_metadata_conv[] = { - { "ALBUMARTIST", "album_artist"}, - { "TRACKNUMBER", "track" }, - { 0 } -}; - static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) { int i, cnum, h, m, s, ms, keylen = strlen(key);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vorbiscomment.c Sat Mar 20 13:36:43 2010 +0000 @@ -0,0 +1,73 @@ +/* + * VorbisComment writer + * Copyright (c) 2009 James Darnley + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "metadata.h" +#include "vorbiscomment.h" +#include "libavcodec/bytestream.h" + +/** + * VorbisComment metadata conversion mapping. + * from Ogg Vorbis I format specification: comment field and header specification + * http://xiph.org/vorbis/doc/v-comment.html + */ +const AVMetadataConv ff_vorbiscomment_metadata_conv[] = { + { "ALBUMARTIST", "album_artist"}, + { "TRACKNUMBER", "track" }, + { 0 } +}; + +int ff_vorbiscomment_length(AVMetadata *m, const char *vendor_string, + unsigned *count) +{ + int len = 8; + len += strlen(vendor_string); + *count = 0; + if (m) { + AVMetadataTag *tag = NULL; + while ( (tag = av_metadata_get(m, "", tag, AV_METADATA_IGNORE_SUFFIX) ) ) { + len += 4 +strlen(tag->key) + 1 + strlen(tag->value); + (*count)++; + } + } + return len; +} + +int ff_vorbiscomment_write(uint8_t **p, AVMetadata *m, + const char *vendor_string, const unsigned count) +{ + bytestream_put_le32(p, strlen(vendor_string)); + bytestream_put_buffer(p, vendor_string, strlen(vendor_string)); + if (m) { + AVMetadataTag *tag = NULL; + bytestream_put_le32(p, count); + while ( (tag = av_metadata_get(m, "", tag, AV_METADATA_IGNORE_SUFFIX) ) ) { + unsigned int len1 = strlen(tag->key); + unsigned int len2 = strlen(tag->value); + bytestream_put_le32(p, len1+1+len2); + bytestream_put_buffer(p, tag->key, len1); + bytestream_put_byte(p, '='); + bytestream_put_buffer(p, tag->value, len2); + } + } else + bytestream_put_le32(p, 0); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vorbiscomment.h Sat Mar 20 13:36:43 2010 +0000 @@ -0,0 +1,57 @@ +/* + * VorbisComment writer + * Copyright (c) 2009 James Darnley + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_VORBISCOMMENT_H +#define AVFORMAT_VORBISCOMMENT_H + +#include "avformat.h" +#include "metadata.h" + +/** + * Calculates the length in bytes of a VorbisComment. This is the minimum + * size required by ff_vorbiscomment_write(). + * + * @param m The metadata structure to be parsed. For no metadata, set to NULL. + * @param vendor_string The vendor string to be added into the VorbisComment. + * For no string, set to an empty string. + * @param count Pointer to store the number of tags in m because m->count is "not allowed" + * @return The length in bytes. + */ +int ff_vorbiscomment_length(AVMetadata *m, const char *vendor_string, + unsigned *count); + +/** + * Writes a VorbisComment into a buffer. The buffer, p, must have enough + * data to hold the whole VorbisComment. The minimum size required can be + * obtained by passing the same AVMetadata and vendor_string to + * ff_vorbiscomment_length() + * + * @param p The buffer in which to write. + * @param m The metadata struct to write. + * @param vendor_string The vendor string to write. + * @param count The number of tags in m because m->count is "not allowed" + */ +int ff_vorbiscomment_write(uint8_t **p, AVMetadata *m, + const char *vendor_string, const unsigned count); + +extern const AVMetadataConv ff_vorbiscomment_metadata_conv[]; + +#endif /* AVFORMAT_VORBISCOMMENT_H */