Mercurial > libavformat.hg
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 |