MP3 muxer: Write all metadata.
[libav.git] / libavformat / id3v2.c
CommitLineData
2ea512a6
AC
1/*
2 * ID3v2 header parser
3 * Copyright (c) 2003 Fabrice Bellard
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "id3v2.h"
75411182
PD
23#include "id3v1.h"
24#include "libavutil/avstring.h"
2ea512a6
AC
25
26int ff_id3v2_match(const uint8_t *buf)
27{
7d7b8c32
DB
28 return buf[0] == 'I' &&
29 buf[1] == 'D' &&
30 buf[2] == '3' &&
31 buf[3] != 0xff &&
32 buf[4] != 0xff &&
33 (buf[6] & 0x80) == 0 &&
34 (buf[7] & 0x80) == 0 &&
35 (buf[8] & 0x80) == 0 &&
1d4b1bf2 36 (buf[9] & 0x80) == 0;
2ea512a6 37}
ac3ef4a4
AC
38
39int ff_id3v2_tag_len(const uint8_t * buf)
40{
41 int len = ((buf[6] & 0x7f) << 21) +
7d7b8c32
DB
42 ((buf[7] & 0x7f) << 14) +
43 ((buf[8] & 0x7f) << 7) +
44 (buf[9] & 0x7f) +
45 ID3v2_HEADER_SIZE;
ac3ef4a4
AC
46 if (buf[5] & 0x10)
47 len += ID3v2_HEADER_SIZE;
48 return len;
49}
75411182 50
50fcd5be
PD
51void ff_id3v2_read(AVFormatContext *s)
52{
53 int len, ret;
54 uint8_t buf[ID3v2_HEADER_SIZE];
55
56 ret = get_buffer(s->pb, buf, ID3v2_HEADER_SIZE);
57 if (ret != ID3v2_HEADER_SIZE)
58 return;
59 if (ff_id3v2_match(buf)) {
60 /* parse ID3v2 header */
61 len = ((buf[6] & 0x7f) << 21) |
62 ((buf[7] & 0x7f) << 14) |
63 ((buf[8] & 0x7f) << 7) |
64 (buf[9] & 0x7f);
65 ff_id3v2_parse(s, len, buf[3], buf[5]);
66 } else {
67 url_fseek(s->pb, 0, SEEK_SET);
68 }
69}
70
75411182
PD
71static unsigned int get_size(ByteIOContext *s, int len)
72{
7d7b8c32
DB
73 int v = 0;
74 while (len--)
75 v = (v << 7) + (get_byte(s) & 0x7F);
75411182
PD
76 return v;
77}
78
79static void read_ttag(AVFormatContext *s, int taglen, const char *key)
80{
81 char *q, dst[512];
82 int len, dstlen = sizeof(dst) - 1;
83 unsigned genre;
20c68378 84 unsigned int (*get)(ByteIOContext*) = get_be16;
75411182 85
7d7b8c32
DB
86 dst[0] = 0;
87 if (taglen < 1)
75411182
PD
88 return;
89
90 taglen--; /* account for encoding type byte */
91
7d7b8c32 92 switch (get_byte(s->pb)) { /* encoding type */
75411182
PD
93
94 case 0: /* ISO-8859-1 (0 - 255 maps directly into unicode) */
95 q = dst;
787f8fad 96 while (taglen-- && q - dst < dstlen - 7) {
75411182 97 uint8_t tmp;
787f8fad 98 PUT_UTF8(get_byte(s->pb), tmp, *q++ = tmp;)
75411182 99 }
9aa1bcce 100 *q = 0;
75411182
PD
101 break;
102
20c68378
AK
103 case 1: /* UTF-16 with BOM */
104 taglen -= 2;
105 switch (get_be16(s->pb)) {
106 case 0xfffe:
107 get = get_le16;
108 case 0xfeff:
109 break;
110 default:
111 av_log(s, AV_LOG_ERROR, "Incorrect BOM value in tag %s.\n", key);
112 return;
113 }
114 // fall-through
115
116 case 2: /* UTF-16BE without BOM */
117 q = dst;
118 while (taglen > 1 && q - dst < dstlen - 7) {
119 uint32_t ch;
120 uint8_t tmp;
121
122 GET_UTF16(ch, ((taglen -= 2) >= 0 ? get(s->pb) : 0), break;)
123 PUT_UTF8(ch, tmp, *q++ = tmp;)
124 }
125 *q = 0;
126 break;
127
75411182 128 case 3: /* UTF-8 */
7d7b8c32 129 len = FFMIN(taglen, dstlen - 1);
75411182
PD
130 get_buffer(s->pb, dst, len);
131 dst[len] = 0;
132 break;
20c68378
AK
133 default:
134 av_log(s, AV_LOG_WARNING, "Unknown encoding in tag %s\n.", key);
75411182
PD
135 }
136
137 if (!strcmp(key, "genre")
138 && (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1)
139 && genre <= ID3v1_GENRE_MAX)
140 av_strlcpy(dst, ff_id3v1_genre_str[genre], sizeof(dst));
141
142 if (*dst)
143 av_metadata_set(&s->metadata, key, dst);
144}
145
146void ff_id3v2_parse(AVFormatContext *s, int len, uint8_t version, uint8_t flags)
147{
148 int isv34, tlen;
149 uint32_t tag;
150 int64_t next;
151 int taghdrlen;
152 const char *reason;
153
7d7b8c32 154 switch (version) {
75411182 155 case 2:
7d7b8c32 156 if (flags & 0x40) {
75411182
PD
157 reason = "compression";
158 goto error;
159 }
160 isv34 = 0;
161 taghdrlen = 6;
162 break;
163
164 case 3:
165 case 4:
166 isv34 = 1;
167 taghdrlen = 10;
168 break;
169
170 default:
171 reason = "version";
172 goto error;
173 }
174
7d7b8c32 175 if (flags & 0x80) {
75411182
PD
176 reason = "unsynchronization";
177 goto error;
178 }
179
7d7b8c32 180 if (isv34 && flags & 0x40) /* Extended header present, just skip over it */
75411182
PD
181 url_fskip(s->pb, get_size(s->pb, 4));
182
7d7b8c32
DB
183 while (len >= taghdrlen) {
184 if (isv34) {
75411182 185 tag = get_be32(s->pb);
3fd5a75b 186 if(version==3){
d004179e 187 tlen = get_be32(s->pb);
3fd5a75b
MN
188 }else
189 tlen = get_size(s->pb, 4);
75411182
PD
190 get_be16(s->pb); /* flags */
191 } else {
192 tag = get_be24(s->pb);
1cd44221 193 tlen = get_be24(s->pb);
75411182
PD
194 }
195 len -= taghdrlen + tlen;
196
7d7b8c32 197 if (len < 0)
75411182
PD
198 break;
199
200 next = url_ftell(s->pb) + tlen;
201
7d7b8c32 202 switch (tag) {
75411182
PD
203 case MKBETAG('T', 'I', 'T', '2'):
204 case MKBETAG(0, 'T', 'T', '2'):
205 read_ttag(s, tlen, "title");
206 break;
207 case MKBETAG('T', 'P', 'E', '1'):
208 case MKBETAG(0, 'T', 'P', '1'):
209 read_ttag(s, tlen, "author");
210 break;
211 case MKBETAG('T', 'A', 'L', 'B'):
212 case MKBETAG(0, 'T', 'A', 'L'):
213 read_ttag(s, tlen, "album");
214 break;
215 case MKBETAG('T', 'C', 'O', 'N'):
216 case MKBETAG(0, 'T', 'C', 'O'):
217 read_ttag(s, tlen, "genre");
218 break;
219 case MKBETAG('T', 'C', 'O', 'P'):
220 case MKBETAG(0, 'T', 'C', 'R'):
221 read_ttag(s, tlen, "copyright");
222 break;
223 case MKBETAG('T', 'R', 'C', 'K'):
224 case MKBETAG(0, 'T', 'R', 'K'):
225 read_ttag(s, tlen, "track");
226 break;
227 case 0:
228 /* padding, skip to end */
229 url_fskip(s->pb, len);
230 len = 0;
231 continue;
232 }
233 /* Skip to end of tag */
234 url_fseek(s->pb, next, SEEK_SET);
235 }
236
7d7b8c32 237 if (version == 4 && flags & 0x10) /* Footer preset, always 10 bytes, skip over it */
75411182
PD
238 url_fskip(s->pb, 10);
239 return;
240
241 error:
242 av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n", version, reason);
243 url_fskip(s->pb, len);
244}
6378b062
AK
245
246const AVMetadataConv ff_id3v2_metadata_conv[] = {
247 { "TALB", "album"},
248 { "TCOM", "composer"},
249 { "TCON", "genre"},
250 { "TCOP", "copyright"},
251 { "TDRL", "date"},
252 { "TENC", "encoder"},
253 { "TIT2", "title"},
254 { "TLAN", "language"},
255 { "TPE1", "author"},
256 { "TPOS", "disc"},
257 { "TPUB", "publisher"},
258 { "TRCK", "track"},
259 { "TSOA", "albumsort"},
260 { "TSOP", "authorsort"},
261 { "TSOT", "titlesort"},
262 { 0 }
263};
078d89a2
AK
264
265const char ff_id3v2_tags[][4] = {
266 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDEN", "TDLY", "TDOR", "TDRC",
267 "TDRL", "TDTG", "TENC", "TEXT", "TFLT", "TIPL", "TIT1", "TIT2", "TIT3",
268 "TKEY", "TLAN", "TLEN", "TMCL", "TMED", "TMOO", "TOAL", "TOFN", "TOLY",
269 "TOPE", "TOWN", "TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPRO", "TPUB",
270 "TRCK", "TRSN", "TRSO", "TSOA", "TSOP", "TSOT", "TSRC", "TSSE", "TSST",
271 { 0 },
272};