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_DEMUXER) += filmstripdec.o | ||||
| OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o | OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o | ||||
| OBJS-$(CONFIG_FLAC_DEMUXER) += flacdec.o raw.o id3v1.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_FLIC_DEMUXER) += flic.o | ||||
| OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o | OBJS-$(CONFIG_FLV_DEMUXER) += flvdec.o | ||||
| OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o | OBJS-$(CONFIG_FLV_MUXER) += flvenc.o avc.o | ||||
| @@ -148,7 +149,8 @@ OBJS-$(CONFIG_OGG_DEMUXER) += oggdec.o \ | |||||
| oggparsespeex.o \ | oggparsespeex.o \ | ||||
| oggparsetheora.o \ | oggparsetheora.o \ | ||||
| oggparsevorbis.o \ | oggparsevorbis.o \ | ||||
| riff.o | |||||
| riff.o \ | |||||
| vorbiscomment.o | |||||
| OBJS-$(CONFIG_OGG_MUXER) += oggenc.o | OBJS-$(CONFIG_OGG_MUXER) += oggenc.o | ||||
| OBJS-$(CONFIG_OMA_DEMUXER) += oma.o raw.o | OBJS-$(CONFIG_OMA_DEMUXER) += oma.o raw.o | ||||
| OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += raw.o | OBJS-$(CONFIG_PCM_ALAW_DEMUXER) += raw.o | ||||
| @@ -24,6 +24,7 @@ | |||||
| #include "raw.h" | #include "raw.h" | ||||
| #include "id3v2.h" | #include "id3v2.h" | ||||
| #include "oggdec.h" | #include "oggdec.h" | ||||
| #include "vorbiscomment.h" | |||||
| static int flac_read_header(AVFormatContext *s, | static int flac_read_header(AVFormatContext *s, | ||||
| AVFormatParameters *ap) | AVFormatParameters *ap) | ||||
| @@ -22,15 +22,20 @@ | |||||
| #include "libavcodec/flac.h" | #include "libavcodec/flac.h" | ||||
| #include "avformat.h" | #include "avformat.h" | ||||
| #include "flacenc.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; | uint8_t *streaminfo; | ||||
| enum FLACExtradataFormat format; | enum FLACExtradataFormat format; | ||||
| header[4] = last_block ? 0x80 : 0x00; | |||||
| if (!ff_flac_is_extradata_valid(codec, &format, &streaminfo)) | if (!ff_flac_is_extradata_valid(codec, &format, &streaminfo)) | ||||
| return -1; | return -1; | ||||
| @@ -45,9 +50,63 @@ int ff_flac_write_header(ByteIOContext *pb, AVCodecContext *codec) | |||||
| return 0; | 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) | 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) | static int flac_write_trailer(struct AVFormatContext *s) | ||||
| @@ -92,4 +151,5 @@ AVOutputFormat flac_muxer = { | |||||
| flac_write_packet, | flac_write_packet, | ||||
| flac_write_trailer, | flac_write_trailer, | ||||
| .flags= AVFMT_NOTIMESTAMPS, | .flags= AVFMT_NOTIMESTAMPS, | ||||
| .metadata_conv = ff_vorbiscomment_metadata_conv, | |||||
| }; | }; | ||||
| @@ -24,6 +24,7 @@ | |||||
| #include "avformat.h" | #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 */ | #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) | if (codec->codec_id == CODEC_ID_VORBIS || codec->codec_id == CODEC_ID_THEORA) | ||||
| ret = put_xiph_codecpriv(s, dyn_cp, codec); | ret = put_xiph_codecpriv(s, dyn_cp, codec); | ||||
| else if (codec->codec_id == CODEC_ID_FLAC) | 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) | else if (codec->codec_id == CODEC_ID_H264) | ||||
| ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); | ret = ff_isom_write_avcc(dyn_cp, codec->extradata, codec->extradata_size); | ||||
| else if (codec->extradata_size) | else if (codec->extradata_size) | ||||
| @@ -33,6 +33,7 @@ | |||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include "oggdec.h" | #include "oggdec.h" | ||||
| #include "avformat.h" | #include "avformat.h" | ||||
| #include "vorbiscomment.h" | |||||
| #define MAX_PAGE_SIZE 65307 | #define MAX_PAGE_SIZE 65307 | ||||
| #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE | #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_theora_codec; | ||||
| extern const struct ogg_codec ff_vorbis_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); | int ff_vorbis_comment(AVFormatContext *ms, AVMetadata **m, const uint8_t *buf, int size); | ||||
| static inline int | static inline int | ||||
| @@ -30,17 +30,6 @@ | |||||
| #include "avformat.h" | #include "avformat.h" | ||||
| #include "oggdec.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) | static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) | ||||
| { | { | ||||
| int i, cnum, h, m, s, ms, keylen = strlen(key); | 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 | 95e54b261530a1bcf6de6fe3b21dc5f6 *./tests/data/flac.acodec.out.wav | ||||
| stddev: 0.00 PSNR:999.99 bytes: 1058444/ 1058444 | 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:0 ts:-1.000000 | ||||
| ret:-1 st:-1 flags:1 ts: 1.894167 | ret:-1 st:-1 flags:1 ts: 1.894167 | ||||
| ret:-1 st: 0 flags:0 ts: 0.788345 | ret:-1 st: 0 flags:0 ts: 0.788345 | ||||