* ID3v1 header parser
* Copyright (c) 2003 Fabrice Bellard
*
- * This file is part of FFmpeg.
+ * This file is part of Libav.
*
- * FFmpeg is free software; you can redistribute it and/or
+ * Libav 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,
+ * Libav 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
+ * License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "id3v1.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/dict.h"
-const char *ff_id3v1_genre_str[ID3v1_GENRE_MAX + 1] = {
+const char * const ff_id3v1_genre_str[ID3v1_GENRE_MAX + 1] = {
[0] = "Blues",
[1] = "Classic Rock",
[2] = "Country",
[123] = "A capella",
[124] = "Euro-House",
[125] = "Dance Hall",
+ [126] = "Goa",
+ [127] = "Drum & Bass",
+ [128] = "Club-House",
+ [129] = "Hardcore",
+ [130] = "Terror",
+ [131] = "Indie",
+ [132] = "BritPop",
+ [133] = "Negerpunk",
+ [134] = "Polsk Punk",
+ [135] = "Beat",
+ [136] = "Christian Gangsta",
+ [137] = "Heavy Metal",
+ [138] = "Black Metal",
+ [139] = "Crossover",
+ [140] = "Contemporary Christian",
+ [141] = "Christian Rock",
+ [142] = "Merengue",
+ [143] = "Salsa",
+ [144] = "Thrash Metal",
+ [145] = "Anime",
+ [146] = "JPop",
+ [147] = "SynthPop",
};
+
+static void get_string(AVFormatContext *s, const char *key,
+ const uint8_t *buf, int buf_size)
+{
+ int i, c;
+ char *q, str[512];
+
+ q = str;
+ for(i = 0; i < buf_size; i++) {
+ c = buf[i];
+ if (c == '\0')
+ break;
+ if ((q - str) >= sizeof(str) - 1)
+ break;
+ *q++ = c;
+ }
+ *q = '\0';
+
+ if (*str)
+ av_dict_set(&s->metadata, key, str, 0);
+}
+
+/**
+ * Parse an ID3v1 tag
+ *
+ * @param buf ID3v1_TAG_SIZE long buffer containing the tag
+ */
+static int parse_tag(AVFormatContext *s, const uint8_t *buf)
+{
+ char str[5];
+ int genre;
+
+ if (!(buf[0] == 'T' &&
+ buf[1] == 'A' &&
+ buf[2] == 'G'))
+ return -1;
+ get_string(s, "title", buf + 3, 30);
+ get_string(s, "artist", buf + 33, 30);
+ get_string(s, "album", buf + 63, 30);
+ get_string(s, "date", buf + 93, 4);
+ get_string(s, "comment", buf + 97, 30);
+ if (buf[125] == 0 && buf[126] != 0) {
+ snprintf(str, sizeof(str), "%d", buf[126]);
+ av_dict_set(&s->metadata, "track", str, 0);
+ }
+ genre = buf[127];
+ if (genre <= ID3v1_GENRE_MAX)
+ av_dict_set(&s->metadata, "genre", ff_id3v1_genre_str[genre], 0);
+ return 0;
+}
+
+void ff_id3v1_read(AVFormatContext *s)
+{
+ int ret;
+ uint8_t buf[ID3v1_TAG_SIZE];
+ int64_t filesize, position = avio_tell(s->pb);
+
+ if (s->pb->seekable) {
+ /* XXX: change that */
+ filesize = avio_size(s->pb);
+ if (filesize > 128) {
+ avio_seek(s->pb, filesize - 128, SEEK_SET);
+ ret = avio_read(s->pb, buf, ID3v1_TAG_SIZE);
+ if (ret == ID3v1_TAG_SIZE) {
+ parse_tag(s, buf);
+ }
+ avio_seek(s->pb, position, SEEK_SET);
+ }
+ }
+}