Patch by Anton Khirnov (gmail{wyskas}).
Originally committed as revision 21653 to svn://svn.ffmpeg.org/ffmpeg/trunk
tags/v0.6
| @@ -35,8 +35,8 @@ OBJS-$(CONFIG_ASS_DEMUXER) += assdec.o | |||||
| OBJS-$(CONFIG_ASS_MUXER) += assenc.o | OBJS-$(CONFIG_ASS_MUXER) += assenc.o | ||||
| OBJS-$(CONFIG_AU_DEMUXER) += au.o raw.o | OBJS-$(CONFIG_AU_DEMUXER) += au.o raw.o | ||||
| OBJS-$(CONFIG_AU_MUXER) += au.o | OBJS-$(CONFIG_AU_MUXER) += au.o | ||||
| OBJS-$(CONFIG_AVI_DEMUXER) += avidec.o riff.o | |||||
| OBJS-$(CONFIG_AVI_MUXER) += avienc.o riff.o | |||||
| OBJS-$(CONFIG_AVI_DEMUXER) += avidec.o riff.o avi.o | |||||
| OBJS-$(CONFIG_AVI_MUXER) += avienc.o riff.o avi.o | |||||
| OBJS-$(CONFIG_AVISYNTH) += avisynth.o | OBJS-$(CONFIG_AVISYNTH) += avisynth.o | ||||
| OBJS-$(CONFIG_AVM2_MUXER) += swfenc.o | OBJS-$(CONFIG_AVM2_MUXER) += swfenc.o | ||||
| OBJS-$(CONFIG_AVS_DEMUXER) += avs.o vocdec.o voc.o | OBJS-$(CONFIG_AVS_DEMUXER) += avs.o vocdec.o voc.o | ||||
| @@ -0,0 +1,45 @@ | |||||
| /* | |||||
| * AVI common data | |||||
| * Copyright (c) 2010 Anton Khirnov | |||||
| * | |||||
| * 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 "avi.h" | |||||
| const AVMetadataConv ff_avi_metadata_conv[] = { | |||||
| { "IART", "artist" }, | |||||
| { "ICMT", "comment" }, | |||||
| { "ICOP", "copyright" }, | |||||
| { "ICRD", "date" }, | |||||
| { "IGNR", "genre" }, | |||||
| { "ILNG", "language" }, | |||||
| { "INAM", "title" }, | |||||
| { "IPRD", "album" }, | |||||
| { "IPRT", "track" }, | |||||
| { "ISFT", "encoder" }, | |||||
| { "ITCH", "encoded_by"}, | |||||
| { "strn", "title" }, | |||||
| { 0 }, | |||||
| }; | |||||
| const char ff_avi_tags[][5] = { | |||||
| "IARL", "IART", "ICMS", "ICMT", "ICOP", "ICRD", "ICRP", "IDIM", "IDPI", | |||||
| "IENG", "IGNR", "IKEY", "ILGT", "ILNG", "IMED", "INAM", "IPLT", "IPRD", | |||||
| "IPRT", "ISBJ",/*"ISFT"*/"ISHP", "ISRC", "ISRF", "ITCH", | |||||
| {0} | |||||
| }; | |||||
| @@ -21,6 +21,8 @@ | |||||
| #ifndef AVFORMAT_AVI_H | #ifndef AVFORMAT_AVI_H | ||||
| #define AVFORMAT_AVI_H | #define AVFORMAT_AVI_H | ||||
| #include "metadata.h" | |||||
| #define AVIF_HASINDEX 0x00000010 // Index at end of file? | #define AVIF_HASINDEX 0x00000010 // Index at end of file? | ||||
| #define AVIF_MUSTUSEINDEX 0x00000020 | #define AVIF_MUSTUSEINDEX 0x00000020 | ||||
| #define AVIF_ISINTERLEAVED 0x00000100 | #define AVIF_ISINTERLEAVED 0x00000100 | ||||
| @@ -34,4 +36,11 @@ | |||||
| /* index flags */ | /* index flags */ | ||||
| #define AVIIF_INDEX 0x10 | #define AVIIF_INDEX 0x10 | ||||
| extern const AVMetadataConv ff_avi_metadata_conv[]; | |||||
| /** | |||||
| * A list of AVI info tags. | |||||
| */ | |||||
| extern const char ff_avi_tags[][5]; | |||||
| #endif /* AVFORMAT_AVI_H */ | #endif /* AVFORMAT_AVI_H */ | ||||
| @@ -227,10 +227,10 @@ static void clean_index(AVFormatContext *s){ | |||||
| } | } | ||||
| } | } | ||||
| static int avi_read_tag(AVFormatContext *s, AVStream *st, const char *key, unsigned int size) | |||||
| static int avi_read_tag(AVFormatContext *s, AVStream *st, uint32_t tag, uint32_t size) | |||||
| { | { | ||||
| ByteIOContext *pb = s->pb; | ByteIOContext *pb = s->pb; | ||||
| char *value; | |||||
| char key[5] = {0}, *value; | |||||
| size += (size & 1); | size += (size & 1); | ||||
| @@ -242,6 +242,8 @@ static int avi_read_tag(AVFormatContext *s, AVStream *st, const char *key, unsig | |||||
| get_buffer(pb, value, size); | get_buffer(pb, value, size); | ||||
| value[size]=0; | value[size]=0; | ||||
| AV_WL32(key, tag); | |||||
| if(st) | if(st) | ||||
| return av_metadata_set2(&st->metadata, key, value, | return av_metadata_set2(&st->metadata, key, value, | ||||
| AV_METADATA_DONT_STRDUP_VAL); | AV_METADATA_DONT_STRDUP_VAL); | ||||
| @@ -250,6 +252,15 @@ static int avi_read_tag(AVFormatContext *s, AVStream *st, const char *key, unsig | |||||
| AV_METADATA_DONT_STRDUP_VAL); | AV_METADATA_DONT_STRDUP_VAL); | ||||
| } | } | ||||
| static void avi_read_info(AVFormatContext *s, uint64_t end) | |||||
| { | |||||
| while (url_ftell(s->pb) < end) { | |||||
| uint32_t tag = get_le32(s->pb); | |||||
| uint32_t size = get_le32(s->pb); | |||||
| avi_read_tag(s, NULL, tag, size); | |||||
| } | |||||
| } | |||||
| static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) | static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) | ||||
| { | { | ||||
| AVIContext *avi = s->priv_data; | AVIContext *avi = s->priv_data; | ||||
| @@ -301,6 +312,9 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| dprintf(NULL, "movi end=%"PRIx64"\n", avi->movi_end); | dprintf(NULL, "movi end=%"PRIx64"\n", avi->movi_end); | ||||
| goto end_of_header; | goto end_of_header; | ||||
| } | } | ||||
| else if (tag1 == MKTAG('I', 'N', 'F', 'O')) | |||||
| avi_read_info(s, list_end); | |||||
| break; | break; | ||||
| case MKTAG('d', 'm', 'l', 'h'): | case MKTAG('d', 'm', 'l', 'h'): | ||||
| avi->is_odml = 1; | avi->is_odml = 1; | ||||
| @@ -606,30 +620,9 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) | |||||
| } | } | ||||
| url_fseek(pb, size, SEEK_CUR); | url_fseek(pb, size, SEEK_CUR); | ||||
| break; | break; | ||||
| case MKTAG('I', 'N', 'A', 'M'): | |||||
| avi_read_tag(s, NULL, "Title", size); | |||||
| break; | |||||
| case MKTAG('I', 'A', 'R', 'T'): | |||||
| avi_read_tag(s, NULL, "Artist", size); | |||||
| break; | |||||
| case MKTAG('I', 'C', 'O', 'P'): | |||||
| avi_read_tag(s, NULL, "Copyright", size); | |||||
| break; | |||||
| case MKTAG('I', 'C', 'M', 'T'): | |||||
| avi_read_tag(s, NULL, "Comment", size); | |||||
| break; | |||||
| case MKTAG('I', 'G', 'N', 'R'): | |||||
| avi_read_tag(s, NULL, "Genre", size); | |||||
| break; | |||||
| case MKTAG('I', 'P', 'R', 'D'): | |||||
| avi_read_tag(s, NULL, "Album", size); | |||||
| break; | |||||
| case MKTAG('I', 'P', 'R', 'T'): | |||||
| avi_read_tag(s, NULL, "Track", size); | |||||
| break; | |||||
| case MKTAG('s', 't', 'r', 'n'): | case MKTAG('s', 't', 'r', 'n'): | ||||
| if(s->nb_streams){ | if(s->nb_streams){ | ||||
| avi_read_tag(s, s->streams[s->nb_streams-1], "Title", size); | |||||
| avi_read_tag(s, s->streams[s->nb_streams-1], tag, size); | |||||
| break; | break; | ||||
| } | } | ||||
| default: | default: | ||||
| @@ -1190,4 +1183,5 @@ AVInputFormat avi_demuxer = { | |||||
| avi_read_packet, | avi_read_packet, | ||||
| avi_read_close, | avi_read_close, | ||||
| avi_read_seek, | avi_read_seek, | ||||
| .metadata_conv = ff_avi_metadata_conv, | |||||
| }; | }; | ||||
| @@ -21,6 +21,7 @@ | |||||
| #include "avformat.h" | #include "avformat.h" | ||||
| #include "avi.h" | #include "avi.h" | ||||
| #include "riff.h" | #include "riff.h" | ||||
| #include "libavutil/intreadwrite.h" | |||||
| /* | /* | ||||
| * TODO: | * TODO: | ||||
| @@ -114,22 +115,6 @@ static void avi_write_info_tag(ByteIOContext *pb, const char *tag, const char *s | |||||
| } | } | ||||
| } | } | ||||
| static void avi_write_info_tag2(AVFormatContext *s, AVStream *st, const char *fourcc, const char *key1, const char *key2) | |||||
| { | |||||
| AVMetadataTag *tag; | |||||
| if(st){ | |||||
| tag= av_metadata_get(st->metadata, key1, NULL, 0); | |||||
| if(!tag && key2) | |||||
| tag= av_metadata_get(st->metadata, key2, NULL, 0); | |||||
| }else{ | |||||
| tag= av_metadata_get(s->metadata, key1, NULL, 0); | |||||
| if(!tag && key2) | |||||
| tag= av_metadata_get(s->metadata, key2, NULL, 0); | |||||
| } | |||||
| if(tag) | |||||
| avi_write_info_tag(s->pb, fourcc, tag->value); | |||||
| } | |||||
| static int avi_write_counters(AVFormatContext* s, int riff_id) | static int avi_write_counters(AVFormatContext* s, int riff_id) | ||||
| { | { | ||||
| ByteIOContext *pb = s->pb; | ByteIOContext *pb = s->pb; | ||||
| @@ -171,6 +156,7 @@ static int avi_write_header(AVFormatContext *s) | |||||
| int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; | int bitrate, n, i, nb_frames, au_byterate, au_ssize, au_scale; | ||||
| AVCodecContext *stream, *video_enc; | AVCodecContext *stream, *video_enc; | ||||
| int64_t list1, list2, strh, strf; | int64_t list1, list2, strh, strf; | ||||
| AVMetadataTag *t = NULL; | |||||
| for(n=0;n<s->nb_streams;n++) { | for(n=0;n<s->nb_streams;n++) { | ||||
| s->streams[n]->priv_data= av_mallocz(sizeof(AVIStream)); | s->streams[n]->priv_data= av_mallocz(sizeof(AVIStream)); | ||||
| @@ -301,7 +287,15 @@ static int avi_write_header(AVFormatContext *s) | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| ff_end_tag(pb, strf); | ff_end_tag(pb, strf); | ||||
| avi_write_info_tag2(s, s->streams[i], "strn", "Title", "Description"); | |||||
| if ((t = av_metadata_get(s->streams[i]->metadata, "strn", NULL, 0))) { | |||||
| avi_write_info_tag(s->pb, t->key, t->value); | |||||
| t = NULL; | |||||
| } | |||||
| //FIXME a limitation of metadata conversion system | |||||
| else if ((t = av_metadata_get(s->streams[i]->metadata, "INAM", NULL, 0))) { | |||||
| avi_write_info_tag(s->pb, "strn", t->value); | |||||
| t = NULL; | |||||
| } | |||||
| } | } | ||||
| if (!url_is_streamed(pb)) { | if (!url_is_streamed(pb)) { | ||||
| @@ -378,13 +372,10 @@ static int avi_write_header(AVFormatContext *s) | |||||
| list2 = ff_start_tag(pb, "LIST"); | list2 = ff_start_tag(pb, "LIST"); | ||||
| put_tag(pb, "INFO"); | put_tag(pb, "INFO"); | ||||
| avi_write_info_tag2(s, NULL, "INAM", "Title", NULL); | |||||
| avi_write_info_tag2(s, NULL, "IART", "Artist", "Author"); | |||||
| avi_write_info_tag2(s, NULL, "ICOP", "Copyright", NULL); | |||||
| avi_write_info_tag2(s, NULL, "ICMT", "Comment", NULL); | |||||
| avi_write_info_tag2(s, NULL, "IPRD", "Album", NULL); | |||||
| avi_write_info_tag2(s, NULL, "IGNR", "Genre", NULL); | |||||
| avi_write_info_tag2(s, NULL, "IPRT", "Track", NULL); | |||||
| for (i = 0; *ff_avi_tags[i]; i++) { | |||||
| if ((t = av_metadata_get(s->metadata, ff_avi_tags[i], NULL, AV_METADATA_MATCH_CASE))) | |||||
| avi_write_info_tag(s->pb, t->key, t->value); | |||||
| } | |||||
| if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) | if(!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) | ||||
| avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); | avi_write_info_tag(pb, "ISFT", LIBAVFORMAT_IDENT); | ||||
| ff_end_tag(pb, list2); | ff_end_tag(pb, list2); | ||||
| @@ -655,4 +646,5 @@ AVOutputFormat avi_muxer = { | |||||
| avi_write_trailer, | avi_write_trailer, | ||||
| .codec_tag= (const AVCodecTag* const []){ff_codec_bmp_tags, ff_codec_wav_tags, 0}, | .codec_tag= (const AVCodecTag* const []){ff_codec_bmp_tags, ff_codec_wav_tags, 0}, | ||||
| .flags= AVFMT_VARIABLE_FPS, | .flags= AVFMT_VARIABLE_FPS, | ||||
| .metadata_conv = ff_avi_metadata_conv, | |||||
| }; | }; | ||||