comparison ape.c @ 5134:6c0318c8a127 libavformat

Move APE tag parsing into separate module. Based on patch by Matti Hamalainen (mhamalai<mot>students<punkt>oamk<punkt>)
author kostya
date Tue, 11 Aug 2009 17:08:09 +0000
parents 1df917933244
children 28094e9bd013
comparison
equal deleted inserted replaced
5133:1df917933244 5134:6c0318c8a127
22 22
23 #include <stdio.h> 23 #include <stdio.h>
24 24
25 #include "libavutil/intreadwrite.h" 25 #include "libavutil/intreadwrite.h"
26 #include "avformat.h" 26 #include "avformat.h"
27 #include "apetag.h"
27 28
28 #define ENABLE_DEBUG 0 29 #define ENABLE_DEBUG 0
29 30
30 /* The earliest and latest file formats supported by this library */ 31 /* The earliest and latest file formats supported by this library */
31 #define APE_MIN_VERSION 3950 32 #define APE_MIN_VERSION 3950
39 #define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored) 40 #define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored)
40 41
41 #define MAC_SUBFRAME_SIZE 4608 42 #define MAC_SUBFRAME_SIZE 4608
42 43
43 #define APE_EXTRADATA_SIZE 6 44 #define APE_EXTRADATA_SIZE 6
44
45 /* APE tags */
46 #define APE_TAG_VERSION 2000
47 #define APE_TAG_FOOTER_BYTES 32
48 #define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
49 #define APE_TAG_FLAG_IS_HEADER (1 << 29)
50 45
51 typedef struct { 46 typedef struct {
52 int64_t pos; 47 int64_t pos;
53 int nblocks; 48 int nblocks;
54 int size; 49 int size;
88 uint32_t samplerate; 83 uint32_t samplerate;
89 84
90 /* Seektable */ 85 /* Seektable */
91 uint32_t *seektable; 86 uint32_t *seektable;
92 } APEContext; 87 } APEContext;
93
94 static int ape_tag_read_field(AVFormatContext *s)
95 {
96 ByteIOContext *pb = s->pb;
97 uint8_t key[1024], value[1024];
98 uint32_t size, flags;
99 int i, l, c;
100
101 size = get_le32(pb); /* field size */
102 flags = get_le32(pb); /* field flags */
103 for (i = 0; i < sizeof(key) - 1; i++) {
104 c = get_byte(pb);
105 if (c < 0x20 || c > 0x7E)
106 break;
107 else
108 key[i] = c;
109 }
110 key[i] = 0;
111 if (c != 0) {
112 av_log(s, AV_LOG_WARNING, "Invalid APE tag key '%s'.\n", key);
113 return -1;
114 }
115 l = FFMIN(size, sizeof(value)-1);
116 get_buffer(pb, value, l);
117 value[l] = 0;
118 url_fskip(pb, size-l);
119 if (l < size)
120 av_log(s, AV_LOG_WARNING, "Too long '%s' tag was truncated.\n", key);
121 av_metadata_set(&s->metadata, key, value);
122 return 0;
123 }
124
125 static void ape_parse_tag(AVFormatContext *s)
126 {
127 ByteIOContext *pb = s->pb;
128 int file_size = url_fsize(pb);
129 uint32_t val, fields, tag_bytes;
130 uint8_t buf[8];
131 int i;
132
133 if (file_size < APE_TAG_FOOTER_BYTES)
134 return;
135
136 url_fseek(pb, file_size - APE_TAG_FOOTER_BYTES, SEEK_SET);
137
138 get_buffer(pb, buf, 8); /* APETAGEX */
139 if (strncmp(buf, "APETAGEX", 8)) {
140 return;
141 }
142
143 val = get_le32(pb); /* APE tag version */
144 if (val > APE_TAG_VERSION) {
145 av_log(s, AV_LOG_ERROR, "Unsupported tag version. (>=%d)\n", APE_TAG_VERSION);
146 return;
147 }
148
149 tag_bytes = get_le32(pb); /* tag size */
150 if (tag_bytes - APE_TAG_FOOTER_BYTES > (1024 * 1024 * 16)) {
151 av_log(s, AV_LOG_ERROR, "Tag size is way too big\n");
152 return;
153 }
154
155 fields = get_le32(pb); /* number of fields */
156 if (fields > 65536) {
157 av_log(s, AV_LOG_ERROR, "Too many tag fields (%d)\n", fields);
158 return;
159 }
160
161 val = get_le32(pb); /* flags */
162 if (val & APE_TAG_FLAG_IS_HEADER) {
163 av_log(s, AV_LOG_ERROR, "APE Tag is a header\n");
164 return;
165 }
166
167 url_fseek(pb, file_size - tag_bytes, SEEK_SET);
168
169 for (i=0; i<fields; i++)
170 if (ape_tag_read_field(s) < 0) break;
171
172 #if ENABLE_DEBUG
173 av_log(s, AV_LOG_DEBUG, "\nAPE Tags:\n\n");
174 av_log(s, AV_LOG_DEBUG, "title = %s\n", s->title);
175 av_log(s, AV_LOG_DEBUG, "author = %s\n", s->author);
176 av_log(s, AV_LOG_DEBUG, "copyright = %s\n", s->copyright);
177 av_log(s, AV_LOG_DEBUG, "comment = %s\n", s->comment);
178 av_log(s, AV_LOG_DEBUG, "album = %s\n", s->album);
179 av_log(s, AV_LOG_DEBUG, "year = %d\n", s->year);
180 av_log(s, AV_LOG_DEBUG, "track = %d\n", s->track);
181 av_log(s, AV_LOG_DEBUG, "genre = %s\n", s->genre);
182 #endif
183 }
184 88
185 static int ape_probe(AVProbeData * p) 89 static int ape_probe(AVProbeData * p)
186 { 90 {
187 if (p->buf[0] == 'M' && p->buf[1] == 'A' && p->buf[2] == 'C' && p->buf[3] == ' ') 91 if (p->buf[0] == 'M' && p->buf[1] == 'A' && p->buf[2] == 'C' && p->buf[3] == ' ')
188 return AVPROBE_SCORE_MAX; 92 return AVPROBE_SCORE_MAX;
382 286
383 ape_dumpinfo(s, ape); 287 ape_dumpinfo(s, ape);
384 288
385 /* try to read APE tags */ 289 /* try to read APE tags */
386 if (!url_is_streamed(pb)) { 290 if (!url_is_streamed(pb)) {
387 ape_parse_tag(s); 291 ff_ape_parse_tag(s);
388 url_fseek(pb, 0, SEEK_SET); 292 url_fseek(pb, 0, SEEK_SET);
389 } 293 }
390 294
391 av_log(s, AV_LOG_DEBUG, "Decoding file - v%d.%02d, compression level %d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10, ape->compressiontype); 295 av_log(s, AV_LOG_DEBUG, "Decoding file - v%d.%02d, compression level %d\n", ape->fileversion / 1000, (ape->fileversion % 1000) / 10, ape->compressiontype);
392 296