3 * Copyright (c) 2003 Fabrice Bellard
5 * This file is part of Libav.
7 * Libav 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.
12 * Libav 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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "libavutil/avstring.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/dict.h"
27 #include "avio_internal.h"
29 const AVMetadataConv ff_id3v2_34_metadata_conv
[] = {
31 { "TCOM", "composer"},
33 { "TCOP", "copyright"},
34 { "TENC", "encoded_by"},
36 { "TLAN", "language"},
38 { "TPE2", "album_artist"},
39 { "TPE3", "performer"},
41 { "TPUB", "publisher"},
47 const AVMetadataConv ff_id3v2_4_metadata_conv
[] = {
50 { "TDEN", "creation_time"},
51 { "TSOA", "album-sort"},
52 { "TSOP", "artist-sort"},
53 { "TSOT", "title-sort"},
57 const AVMetadataConv ff_id3v2_2_metadata_conv
[] = {
61 { "TEN", "encoded_by"},
63 { "TP2", "album_artist"},
64 { "TP3", "performer"},
70 const char ff_id3v2_tags
[][4] = {
71 "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
72 "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
73 "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
74 "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
78 const char ff_id3v2_4_tags
[][4] = {
79 "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
80 "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
84 const char ff_id3v2_3_tags
[][4] = {
85 "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
89 int ff_id3v2_match(const uint8_t *buf
, const char * magic
)
91 return buf
[0] == magic
[0] &&
96 (buf
[6] & 0x80) == 0 &&
97 (buf
[7] & 0x80) == 0 &&
98 (buf
[8] & 0x80) == 0 &&
102 int ff_id3v2_tag_len(const uint8_t * buf
)
104 int len
= ((buf
[6] & 0x7f) << 21) +
105 ((buf
[7] & 0x7f) << 14) +
106 ((buf
[8] & 0x7f) << 7) +
110 len
+= ID3v2_HEADER_SIZE
;
114 static unsigned int get_size(AVIOContext
*s
, int len
)
118 v
= (v
<< 7) + (avio_r8(s
) & 0x7F);
123 * Free GEOB type extra metadata.
125 static void free_geobtag(ID3v2ExtraMetaGEOB
*geob
)
127 av_free(geob
->mime_type
);
128 av_free(geob
->file_name
);
129 av_free(geob
->description
);
135 * Decode characters to UTF-8 according to encoding type. The decoded buffer is
136 * always null terminated. Stop reading when either *maxread bytes are read from
137 * pb or U+0000 character is found.
139 * @param dst Pointer where the address of the buffer with the decoded bytes is
140 * stored. Buffer must be freed by caller.
141 * @param maxread Pointer to maximum number of characters to read from the
142 * AVIOContext. After execution the value is decremented by the number of bytes
144 * @returns 0 if no error occured, dst is uninitialized on error
146 static int decode_str(AVFormatContext
*s
, AVIOContext
*pb
, int encoding
,
147 uint8_t **dst
, int *maxread
)
153 unsigned int (*get
)(AVIOContext
*) = avio_rb16
;
156 if ((ret
= avio_open_dyn_buf(&dynbuf
)) < 0) {
157 av_log(s
, AV_LOG_ERROR
, "Error opening memory stream\n");
163 case ID3v2_ENCODING_ISO8859
:
166 PUT_UTF8(ch
, tmp
, avio_w8(dynbuf
, tmp
);)
171 case ID3v2_ENCODING_UTF16BOM
:
172 if ((left
-= 2) < 0) {
173 av_log(s
, AV_LOG_ERROR
, "Cannot read BOM value, input too short\n");
174 avio_close_dyn_buf(dynbuf
, dst
);
176 return AVERROR_INVALIDDATA
;
178 switch (avio_rb16(pb
)) {
184 av_log(s
, AV_LOG_ERROR
, "Incorrect BOM value\n");
185 avio_close_dyn_buf(dynbuf
, dst
);
188 return AVERROR_INVALIDDATA
;
192 case ID3v2_ENCODING_UTF16BE
:
193 while ((left
> 1) && ch
) {
194 GET_UTF16(ch
, ((left
-= 2) >= 0 ?
get(pb
) : 0), break;)
195 PUT_UTF8(ch
, tmp
, avio_w8(dynbuf
, tmp
);)
198 left
+= 2; /* did not read last char from pb */
201 case ID3v2_ENCODING_UTF8
:
209 av_log(s
, AV_LOG_WARNING
, "Unknown encoding\n");
215 avio_close_dyn_buf(dynbuf
, dst
);
224 static void read_ttag(AVFormatContext
*s
, AVIOContext
*pb
, int taglen
, const char *key
)
227 int encoding
, dict_flags
= AV_DICT_DONT_OVERWRITE
;
233 encoding
= avio_r8(pb
);
234 taglen
--; /* account for encoding type byte */
236 if (decode_str(s
, pb
, encoding
, &dst
, &taglen
) < 0) {
237 av_log(s
, AV_LOG_ERROR
, "Error reading frame %s, skipped\n", key
);
241 if (!(strcmp(key
, "TCON") && strcmp(key
, "TCO"))
242 && (sscanf(dst
, "(%d)", &genre
) == 1 || sscanf(dst
, "%d", &genre
) == 1)
243 && genre
<= ID3v1_GENRE_MAX
) {
245 dst
= ff_id3v1_genre_str
[genre
];
246 } else if (!(strcmp(key
, "TXXX") && strcmp(key
, "TXX"))) {
247 /* dst now contains the key, need to get value */
249 if (decode_str(s
, pb
, encoding
, &dst
, &taglen
) < 0) {
250 av_log(s
, AV_LOG_ERROR
, "Error reading frame %s, skipped\n", key
);
254 dict_flags
|= AV_DICT_DONT_STRDUP_VAL
| AV_DICT_DONT_STRDUP_KEY
;
257 dict_flags
|= AV_DICT_DONT_STRDUP_VAL
;
260 av_dict_set(&s
->metadata
, key
, dst
, dict_flags
);
264 * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
266 static void read_geobtag(AVFormatContext
*s
, AVIOContext
*pb
, int taglen
, char *tag
, ID3v2ExtraMeta
**extra_meta
)
268 ID3v2ExtraMetaGEOB
*geob_data
= NULL
;
269 ID3v2ExtraMeta
*new_extra
= NULL
;
276 geob_data
= av_mallocz(sizeof(ID3v2ExtraMetaGEOB
));
278 av_log(s
, AV_LOG_ERROR
, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMetaGEOB
));
282 new_extra
= av_mallocz(sizeof(ID3v2ExtraMeta
));
284 av_log(s
, AV_LOG_ERROR
, "Failed to alloc %zu bytes\n", sizeof(ID3v2ExtraMeta
));
288 /* read encoding type byte */
289 encoding
= avio_r8(pb
);
292 /* read MIME type (always ISO-8859) */
293 if (decode_str(s
, pb
, ID3v2_ENCODING_ISO8859
, &geob_data
->mime_type
, &taglen
) < 0
298 if (decode_str(s
, pb
, encoding
, &geob_data
->file_name
, &taglen
) < 0
302 /* read content description */
303 if (decode_str(s
, pb
, encoding
, &geob_data
->description
, &taglen
) < 0
308 /* save encapsulated binary data */
309 geob_data
->data
= av_malloc(taglen
);
310 if (!geob_data
->data
) {
311 av_log(s
, AV_LOG_ERROR
, "Failed to alloc %d bytes\n", taglen
);
314 if ((len
= avio_read(pb
, geob_data
->data
, taglen
)) < taglen
)
315 av_log(s
, AV_LOG_WARNING
, "Error reading GEOB frame, data truncated.\n");
316 geob_data
->datasize
= len
;
318 geob_data
->data
= NULL
;
319 geob_data
->datasize
= 0;
322 /* add data to the list */
323 new_extra
->tag
= "GEOB";
324 new_extra
->data
= geob_data
;
325 new_extra
->next
= *extra_meta
;
326 *extra_meta
= new_extra
;
331 av_log(s
, AV_LOG_ERROR
, "Error reading frame %s, skipped\n", tag
);
332 free_geobtag(geob_data
);
337 static int is_number(const char *str
)
339 while (*str
>= '0' && *str
<= '9') str
++;
343 static AVDictionaryEntry
* get_date_tag(AVDictionary
*m
, const char *tag
)
345 AVDictionaryEntry
*t
;
346 if ((t
= av_dict_get(m
, tag
, NULL
, AV_DICT_MATCH_CASE
)) &&
347 strlen(t
->value
) == 4 && is_number(t
->value
))
352 static void merge_date(AVDictionary
**m
)
354 AVDictionaryEntry
*t
;
355 char date
[17] = {0}; // YYYY-MM-DD hh:mm
357 if (!(t
= get_date_tag(*m
, "TYER")) &&
358 !(t
= get_date_tag(*m
, "TYE")))
360 av_strlcpy(date
, t
->value
, 5);
361 av_dict_set(m
, "TYER", NULL
, 0);
362 av_dict_set(m
, "TYE", NULL
, 0);
364 if (!(t
= get_date_tag(*m
, "TDAT")) &&
365 !(t
= get_date_tag(*m
, "TDA")))
367 snprintf(date
+ 4, sizeof(date
) - 4, "-%.2s-%.2s", t
->value
+ 2, t
->value
);
368 av_dict_set(m
, "TDAT", NULL
, 0);
369 av_dict_set(m
, "TDA", NULL
, 0);
371 if (!(t
= get_date_tag(*m
, "TIME")) &&
372 !(t
= get_date_tag(*m
, "TIM")))
374 snprintf(date
+ 10, sizeof(date
) - 10, " %.2s:%.2s", t
->value
, t
->value
+ 2);
375 av_dict_set(m
, "TIME", NULL
, 0);
376 av_dict_set(m
, "TIM", NULL
, 0);
380 av_dict_set(m
, "date", date
, 0);
383 const ID3v2EMFunc ff_id3v2_extra_meta_funcs
[] = {
384 { "GEO", "GEOB", read_geobtag
, free_geobtag
},
389 * Get the corresponding ID3v2EMFunc struct for a tag.
390 * @param isv34 Determines if v2.2 or v2.3/4 strings are used
391 * @return A pointer to the ID3v2EMFunc struct if found, NULL otherwise.
393 static const ID3v2EMFunc
*get_extra_meta_func(const char *tag
, int isv34
)
396 while (ff_id3v2_extra_meta_funcs
[i
].tag3
) {
399 ff_id3v2_extra_meta_funcs
[i
].tag4
:
400 ff_id3v2_extra_meta_funcs
[i
].tag3
),
402 return &ff_id3v2_extra_meta_funcs
[i
];
408 static void ff_id3v2_parse(AVFormatContext
*s
, int len
, uint8_t version
, uint8_t flags
, ID3v2ExtraMeta
**extra_meta
)
410 int isv34
, tlen
, unsync
;
412 int64_t next
, end
= avio_tell(s
->pb
) + len
;
414 const char *reason
= NULL
;
417 unsigned char *buffer
= NULL
;
419 const ID3v2EMFunc
*extra_func
;
424 reason
= "compression";
442 unsync
= flags
& 0x80;
444 if (isv34
&& flags
& 0x40) /* Extended header present, just skip over it */
445 avio_skip(s
->pb
, get_size(s
->pb
, 4));
447 while (len
>= taghdrlen
) {
448 unsigned int tflags
= 0;
452 avio_read(s
->pb
, tag
, 4);
455 tlen
= avio_rb32(s
->pb
);
457 tlen
= get_size(s
->pb
, 4);
458 tflags
= avio_rb16(s
->pb
);
459 tunsync
= tflags
& ID3v2_FLAG_UNSYNCH
;
461 avio_read(s
->pb
, tag
, 3);
463 tlen
= avio_rb24(s
->pb
);
465 if (tlen
< 0 || tlen
> len
- taghdrlen
) {
466 av_log(s
, AV_LOG_WARNING
, "Invalid size in frame %s, skipping the rest of tag.\n", tag
);
469 len
-= taghdrlen
+ tlen
;
470 next
= avio_tell(s
->pb
) + tlen
;
474 av_log(s
, AV_LOG_DEBUG
, "Invalid empty frame %s, skipping.\n", tag
);
478 if (tflags
& ID3v2_FLAG_DATALEN
) {
483 if (tflags
& (ID3v2_FLAG_ENCRYPTION
| ID3v2_FLAG_COMPRESSION
)) {
484 av_log(s
, AV_LOG_WARNING
, "Skipping encrypted/compressed ID3v2 frame %s.\n", tag
);
485 avio_skip(s
->pb
, tlen
);
486 /* check for text tag or supported special meta tag */
487 } else if (tag
[0] == 'T' || (extra_meta
&& (extra_func
= get_extra_meta_func(tag
, isv34
)))) {
488 if (unsync
|| tunsync
) {
490 av_fast_malloc(&buffer
, &buffer_size
, tlen
);
492 av_log(s
, AV_LOG_ERROR
, "Failed to alloc %d bytes\n", tlen
);
495 for (i
= 0, j
= 0; i
< tlen
; i
++, j
++) {
496 buffer
[j
] = avio_r8(s
->pb
);
497 if (j
> 0 && !buffer
[j
] && buffer
[j
- 1] == 0xff) {
498 /* Unsynchronised byte, skip it */
502 ffio_init_context(&pb
, buffer
, j
, 0, NULL
, NULL
, NULL
, NULL
);
504 pbx
= &pb
; // read from sync buffer
506 pbx
= s
->pb
; // read straight from input
510 read_ttag(s
, pbx
, tlen
, tag
);
512 /* parse special meta tag */
513 extra_func
->read(s
, pbx
, tlen
, tag
, extra_meta
);
517 av_log(s
, AV_LOG_WARNING
, "invalid frame id, assuming padding");
518 avio_skip(s
->pb
, tlen
);
521 /* Skip to end of tag */
523 avio_seek(s
->pb
, next
, SEEK_SET
);
526 if (version
== 4 && flags
& 0x10) /* Footer preset, always 10 bytes, skip over it */
531 av_log(s
, AV_LOG_INFO
, "ID3v2.%d tag skipped, cannot handle %s\n", version
, reason
);
532 avio_seek(s
->pb
, end
, SEEK_SET
);
537 void ff_id3v2_read_all(AVFormatContext
*s
, const char *magic
, ID3v2ExtraMeta
**extra_meta
)
540 uint8_t buf
[ID3v2_HEADER_SIZE
];
545 /* save the current offset in case there's nothing to read/skip */
546 off
= avio_tell(s
->pb
);
547 ret
= avio_read(s
->pb
, buf
, ID3v2_HEADER_SIZE
);
548 if (ret
!= ID3v2_HEADER_SIZE
)
550 found_header
= ff_id3v2_match(buf
, magic
);
552 /* parse ID3v2 header */
553 len
= ((buf
[6] & 0x7f) << 21) |
554 ((buf
[7] & 0x7f) << 14) |
555 ((buf
[8] & 0x7f) << 7) |
557 ff_id3v2_parse(s
, len
, buf
[3], buf
[5], extra_meta
);
559 avio_seek(s
->pb
, off
, SEEK_SET
);
561 } while (found_header
);
562 ff_metadata_conv(&s
->metadata
, NULL
, ff_id3v2_34_metadata_conv
);
563 ff_metadata_conv(&s
->metadata
, NULL
, ff_id3v2_2_metadata_conv
);
564 ff_metadata_conv(&s
->metadata
, NULL
, ff_id3v2_4_metadata_conv
);
565 merge_date(&s
->metadata
);
568 void ff_id3v2_read(AVFormatContext
*s
, const char *magic
)
570 ff_id3v2_read_all(s
, magic
, NULL
);
573 void ff_id3v2_free_extra_meta(ID3v2ExtraMeta
**extra_meta
)
575 ID3v2ExtraMeta
*current
= *extra_meta
, *next
;
576 const ID3v2EMFunc
*extra_func
;
579 if ((extra_func
= get_extra_meta_func(current
->tag
, 1)))
580 extra_func
->free(current
->data
);
581 next
= current
->next
;