Patch by James Darnley <james darnley at gmail>. Originally committed as revision 22605 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.6
| @@ -69,8 +69,9 @@ OBJS-$(CONFIG_FFM_MUXER) += ffmenc.o | |||
| 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 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \ | |||
| 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 | |||
| @@ -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) | |||
| @@ -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 @@ int ff_flac_write_header(ByteIOContext *pb, AVCodecContext *codec) | |||
| 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 @@ AVOutputFormat flac_muxer = { | |||
| flac_write_packet, | |||
| flac_write_trailer, | |||
| .flags= AVFMT_NOTIMESTAMPS, | |||
| .metadata_conv = ff_vorbiscomment_metadata_conv, | |||
| }; | |||
| @@ -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 */ | |||
| @@ -470,7 +470,7 @@ static int mkv_write_codecprivate(AVFormatContext *s, ByteIOContext *pb, AVCodec | |||
| 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) | |||
| @@ -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 | |||
| @@ -112,8 +112,6 @@ extern const struct ogg_codec ff_speex_codec; | |||
| 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 | |||
| @@ -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); | |||
| @@ -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; | |||
| } | |||
| @@ -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 */ | |||
| @@ -1,4 +1,4 @@ | |||
| 7781a016edfc242a39e4d65af02d861a *./tests/data/acodec/flac.flac | |||
| 353368 ./tests/data/acodec/flac.flac | |||
| 151eef9097f944726968bec48649f00a *./tests/data/acodec/flac.flac | |||
| 361582 ./tests/data/acodec/flac.flac | |||
| 95e54b261530a1bcf6de6fe3b21dc5f6 *./tests/data/flac.acodec.out.wav | |||
| stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444 | |||
| @@ -1,4 +1,4 @@ | |||
| ret: 0 st: 0 flags:1 dts: NOPTS pts: NOPTS pos: 42 size: 1024 | |||
| ret: 0 st: 0 flags:1 dts: NOPTS pts: NOPTS pos: 8256 size: 1024 | |||
| ret:-1 st:-1 flags:0 ts:-1.000000 | |||
| ret:-1 st:-1 flags:1 ts: 1.894167 | |||
| ret:-1 st: 0 flags:0 ts: 0.788345 | |||