FFmpeg
id3v2.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003 Fabrice Bellard
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * ID3v2 header parser
24  *
25  * Specifications available at:
26  * http://id3.org/Developer_Information
27  */
28 
29 #include "config.h"
30 #include "libavutil/attributes.h"
31 
32 #if CONFIG_ZLIB
33 #include <zlib.h>
34 #endif
35 
37 #include "libavutil/avstring.h"
38 #include "libavutil/bprint.h"
39 #include "libavutil/dict.h"
40 #include "libavutil/intreadwrite.h"
41 #include "libavutil/mem.h"
42 #include "libavcodec/png.h"
43 #include "avio_internal.h"
44 #include "demux.h"
45 #include "id3v1.h"
46 #include "id3v2.h"
47 
49  { "TALB", "album" },
50  { "TCOM", "composer" },
51  { "TCON", "genre" },
52  { "TCOP", "copyright" },
53  { "TENC", "encoded_by" },
54  { "TIT2", "title" },
55  { "TLAN", "language" },
56  { "TPE1", "artist" },
57  { "TPE2", "album_artist" },
58  { "TPE3", "performer" },
59  { "TPOS", "disc" },
60  { "TPUB", "publisher" },
61  { "TRCK", "track" },
62  { "TSSE", "encoder" },
63  { "USLT", "lyrics" },
64  { 0 }
65 };
66 
68  { "TCMP", "compilation" },
69  { "TDRC", "date" },
70  { "TDRL", "date" },
71  { "TDEN", "creation_time" },
72  { "TSOA", "album-sort" },
73  { "TSOP", "artist-sort" },
74  { "TSOT", "title-sort" },
75  { "TIT1", "grouping" },
76  { 0 }
77 };
78 
80  { "TAL", "album" },
81  { "TCO", "genre" },
82  { "TCP", "compilation" },
83  { "TT2", "title" },
84  { "TEN", "encoded_by" },
85  { "TP1", "artist" },
86  { "TP2", "album_artist" },
87  { "TP3", "performer" },
88  { "TRK", "track" },
89  { 0 }
90 };
91 
93  "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
94  "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
95  "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
96  "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
97  { 0 },
98 };
99 
101  "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
102  "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
103  { 0 },
104 };
105 
107  "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
108  { 0 },
109 };
110 
111 const char * const ff_id3v2_picture_types[21] = {
112  "Other",
113  "32x32 pixels 'file icon'",
114  "Other file icon",
115  "Cover (front)",
116  "Cover (back)",
117  "Leaflet page",
118  "Media (e.g. label side of CD)",
119  "Lead artist/lead performer/soloist",
120  "Artist/performer",
121  "Conductor",
122  "Band/Orchestra",
123  "Composer",
124  "Lyricist/text writer",
125  "Recording Location",
126  "During recording",
127  "During performance",
128  "Movie/video screen capture",
129  "A bright coloured fish",
130  "Illustration",
131  "Band/artist logotype",
132  "Publisher/Studio logotype",
133 };
134 
136  { "image/gif", AV_CODEC_ID_GIF },
137  { "image/jpeg", AV_CODEC_ID_MJPEG },
138  { "image/jpg", AV_CODEC_ID_MJPEG },
139  { "image/jxl", AV_CODEC_ID_JPEGXL },
140  { "image/png", AV_CODEC_ID_PNG },
141  { "image/tiff", AV_CODEC_ID_TIFF },
142  { "image/bmp", AV_CODEC_ID_BMP },
143  { "image/webp", AV_CODEC_ID_WEBP },
144  { "JPG", AV_CODEC_ID_MJPEG }, /* ID3v2.2 */
145  { "PNG", AV_CODEC_ID_PNG }, /* ID3v2.2 */
146  { "", AV_CODEC_ID_NONE },
147 };
148 
149 int ff_id3v2_match(const uint8_t *buf, const char *magic)
150 {
151  return buf[0] == magic[0] &&
152  buf[1] == magic[1] &&
153  buf[2] == magic[2] &&
154  buf[3] != 0xff &&
155  buf[4] != 0xff &&
156  (buf[6] & 0x80) == 0 &&
157  (buf[7] & 0x80) == 0 &&
158  (buf[8] & 0x80) == 0 &&
159  (buf[9] & 0x80) == 0;
160 }
161 
162 int ff_id3v2_tag_len(const uint8_t *buf)
163 {
164  int len = ((buf[6] & 0x7f) << 21) +
165  ((buf[7] & 0x7f) << 14) +
166  ((buf[8] & 0x7f) << 7) +
167  (buf[9] & 0x7f) +
169  if (buf[5] & 0x10)
171  return len;
172 }
173 
174 static unsigned int get_size(AVIOContext *s, int len)
175 {
176  int v = 0;
177  while (len--)
178  v = (v << 7) + (avio_r8(s) & 0x7F);
179  return v;
180 }
181 
182 static unsigned int size_to_syncsafe(unsigned int size)
183 {
184  return (((size) & (0x7f << 0)) >> 0) +
185  (((size) & (0x7f << 8)) >> 1) +
186  (((size) & (0x7f << 16)) >> 2) +
187  (((size) & (0x7f << 24)) >> 3);
188 }
189 
190 /* No real verification, only check that the tag consists of
191  * a combination of capital alpha-numerical characters */
192 static int is_tag(const char *buf, unsigned int len)
193 {
194  if (!len)
195  return 0;
196 
197  while (len--)
198  if ((buf[len] < 'A' ||
199  buf[len] > 'Z') &&
200  (buf[len] < '0' ||
201  buf[len] > '9'))
202  return 0;
203 
204  return 1;
205 }
206 
207 /**
208  * Return 1 if the tag of length len at the given offset is valid, 0 if not, -1 on error
209  */
210 static int check_tag(AVIOContext *s, int offset, unsigned int len)
211 {
212  char tag[4];
213 
214  if (len > 4 ||
215  avio_seek(s, offset, SEEK_SET) < 0 ||
216  avio_read(s, tag, len) < (int)len)
217  return -1;
218  else if (!AV_RB32(tag) || is_tag(tag, len))
219  return 1;
220 
221  return 0;
222 }
223 
224 /**
225  * Free GEOB type extra metadata.
226  */
227 static void free_geobtag(void *obj)
228 {
229  ID3v2ExtraMetaGEOB *geob = obj;
230  av_freep(&geob->mime_type);
231  av_freep(&geob->file_name);
232  av_freep(&geob->description);
233  av_freep(&geob->data);
234 }
235 
236 /**
237  * Decode characters to UTF-8 according to encoding type. The decoded buffer is
238  * always null terminated. Stop reading when either *maxread bytes are read from
239  * pb or U+0000 character is found.
240  *
241  * @param dst Pointer where the address of the buffer with the decoded bytes is
242  * stored. Buffer must be freed by caller.
243  * @param maxread Pointer to maximum number of characters to read from the
244  * AVIOContext. After execution the value is decremented by the number of bytes
245  * actually read.
246  * @returns 0 if no error occurred, dst is uninitialized on error
247  */
248 static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
249  uint8_t **dst, int *maxread)
250 {
251  int ret;
252  uint8_t tmp;
253  uint32_t ch = 1;
254  int left = *maxread, dynsize;
255  unsigned int (*get)(AVIOContext*) = avio_rb16;
256  AVIOContext *dynbuf;
257 
258  if ((ret = avio_open_dyn_buf(&dynbuf)) < 0) {
259  av_log(s, AV_LOG_ERROR, "Error opening memory stream\n");
260  return ret;
261  }
262 
263  if (left == 0)
264  goto end;
265 
266  switch (encoding) {
268  while (left && ch) {
269  ch = avio_r8(pb);
270  PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
271  left--;
272  }
273  break;
274 
276  if ((left -= 2) < 0) {
277  av_log(s, AV_LOG_ERROR, "Cannot read BOM value, input too short %d\n", left);
278  ffio_free_dyn_buf(&dynbuf);
279  *dst = NULL;
280  return AVERROR_INVALIDDATA;
281  }
282  uint16_t bom = avio_rb16(pb);
283  switch (bom) {
284  case 0xfffe:
285  get = avio_rl16;
286  break;
287  case 0xfeff:
288  break;
289  case 0: // empty string without bom
290  goto end;
291  default:
292  av_log(s, AV_LOG_ERROR, "Incorrect BOM value: 0x%x\n", bom);
293  ffio_free_dyn_buf(&dynbuf);
294  *dst = NULL;
295  *maxread = left;
296  return AVERROR_INVALIDDATA;
297  }
299 
301  while ((left > 1) && ch) {
302  GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;)
303  PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
304  }
305  if (left < 0)
306  left += 2; /* did not read last char from pb */
307  break;
308 
309  case ID3v2_ENCODING_UTF8:
310  while (left && ch) {
311  ch = avio_r8(pb);
312  avio_w8(dynbuf, ch);
313  left--;
314  }
315  break;
316  default:
317  av_log(s, AV_LOG_WARNING, "Unknown encoding %d\n", encoding);
318  }
319 
320 end:
321  if (ch)
322  avio_w8(dynbuf, 0);
323 
324  dynsize = avio_close_dyn_buf(dynbuf, dst);
325  if (dynsize <= 0) {
326  av_freep(dst);
327  return AVERROR(ENOMEM);
328  }
329  *maxread = left;
330 
331  return 0;
332 }
333 
334 /**
335  * Parse a text tag.
336  */
337 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
338  AVDictionary **metadata, const char *key)
339 {
340  uint8_t *dst;
341  int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
342  unsigned genre;
343 
344  if (taglen < 1)
345  return;
346 
347  encoding = avio_r8(pb);
348  taglen--; /* account for encoding type byte */
349 
350  if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
351  av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
352  return;
353  }
354 
355  if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) &&
356  (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) &&
357  genre <= ID3v1_GENRE_MAX) {
358  av_freep(&dst);
359  dst = av_strdup(ff_id3v1_genre_str[genre]);
360  } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
361  /* dst now contains the key, need to get value */
362  key = dst;
363  if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
364  av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
365  av_freep(&key);
366  return;
367  }
368  dict_flags |= AV_DICT_DONT_STRDUP_KEY;
369  } else if (!*dst)
370  av_freep(&dst);
371 
372  if (dst)
373  av_dict_set(metadata, key, dst, dict_flags);
374 }
375 
376 static void read_uslt(AVFormatContext *s, AVIOContext *pb, int taglen,
378 {
379  uint8_t lang[4];
380  uint8_t *descriptor = NULL; // 'Content descriptor'
381  uint8_t *text;
382  char *key;
383  int encoding;
384  int ok = 0;
385 
386  if (taglen < 4)
387  goto error;
388 
389  encoding = avio_r8(pb);
390  taglen--;
391 
392  if (avio_read(pb, lang, 3) < 3)
393  goto error;
394  lang[3] = '\0';
395  taglen -= 3;
396 
397  if (decode_str(s, pb, encoding, &descriptor, &taglen) < 0 || taglen < 0)
398  goto error;
399 
400  if (decode_str(s, pb, encoding, &text, &taglen) < 0 || taglen < 0)
401  goto error;
402 
403  // FFmpeg does not support hierarchical metadata, so concatenate the keys.
404  key = av_asprintf("lyrics-%s%s%s", descriptor[0] ? (char *)descriptor : "",
405  descriptor[0] ? "-" : "",
406  lang);
407  if (!key) {
408  av_free(text);
409  goto error;
410  }
411 
412  av_dict_set(metadata, key, text,
414 
415  ok = 1;
416 error:
417  if (!ok)
418  av_log(s, AV_LOG_ERROR, "Error reading lyrics, skipped\n");
419  av_free(descriptor);
420 }
421 
422 /**
423  * Parse a comment tag.
424  */
425 static void read_comment(AVFormatContext *s, AVIOContext *pb, int taglen,
427 {
428  const char *key = "comment";
429  uint8_t *dst;
430  int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
431  av_unused int language;
432 
433  if (taglen < 4)
434  return;
435 
436  encoding = avio_r8(pb);
437  language = avio_rl24(pb);
438  taglen -= 4;
439 
440  if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
441  av_log(s, AV_LOG_ERROR, "Error reading comment frame, skipped\n");
442  return;
443  }
444 
445  if (dst && !*dst)
446  av_freep(&dst);
447 
448  if (dst) {
449  key = (const char *) dst;
450  dict_flags |= AV_DICT_DONT_STRDUP_KEY;
451  }
452 
453  if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
454  av_log(s, AV_LOG_ERROR, "Error reading comment frame, skipped\n");
455  if (dict_flags & AV_DICT_DONT_STRDUP_KEY)
456  av_freep((void*)&key);
457  return;
458  }
459 
460  if (dst)
461  av_dict_set(metadata, key, (const char *) dst, dict_flags);
462 }
463 
464 typedef struct ExtraMetaList {
466 } ExtraMetaList;
467 
469 {
470  if (list->tail)
471  list->tail->next = new_elem;
472  else
473  list->head = new_elem;
474  list->tail = new_elem;
475 }
476 
477 /**
478  * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
479  */
480 static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen,
481  const char *tag, ExtraMetaList *extra_meta, int isv34)
482 {
483  ID3v2ExtraMetaGEOB *geob_data = NULL;
484  ID3v2ExtraMeta *new_extra = NULL;
485  char encoding;
486  unsigned int len;
487 
488  if (taglen < 1)
489  return;
490 
491  new_extra = av_mallocz(sizeof(ID3v2ExtraMeta));
492  if (!new_extra) {
493  av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n",
494  sizeof(ID3v2ExtraMeta));
495  return;
496  }
497 
498  geob_data = &new_extra->data.geob;
499 
500  /* read encoding type byte */
501  encoding = avio_r8(pb);
502  taglen--;
503 
504  /* read MIME type (always ISO-8859) */
505  if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type,
506  &taglen) < 0 ||
507  taglen <= 0)
508  goto fail;
509 
510  /* read file name */
511  if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0 ||
512  taglen <= 0)
513  goto fail;
514 
515  /* read content description */
516  if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0 ||
517  taglen < 0)
518  goto fail;
519 
520  if (taglen) {
521  /* save encapsulated binary data */
522  geob_data->data = av_malloc(taglen);
523  if (!geob_data->data) {
524  av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", taglen);
525  goto fail;
526  }
527  if ((len = avio_read(pb, geob_data->data, taglen)) < taglen)
529  "Error reading GEOB frame, data truncated.\n");
530  geob_data->datasize = len;
531  } else {
532  geob_data->data = NULL;
533  geob_data->datasize = 0;
534  }
535 
536  /* add data to the list */
537  new_extra->tag = "GEOB";
538  list_append(new_extra, extra_meta);
539 
540  return;
541 
542 fail:
543  av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", tag);
544  free_geobtag(geob_data);
545  av_free(new_extra);
546  return;
547 }
548 
549 static int is_number(const char *str)
550 {
551  while (*str >= '0' && *str <= '9')
552  str++;
553  return !*str;
554 }
555 
557 {
559  if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
560  strlen(t->value) == 4 && is_number(t->value))
561  return t;
562  return NULL;
563 }
564 
565 static void merge_date(AVDictionary **m)
566 {
568  char date[17] = { 0 }; // YYYY-MM-DD hh:mm
569 
570  if (!(t = get_date_tag(*m, "TYER")) &&
571  !(t = get_date_tag(*m, "TYE")))
572  return;
573  av_strlcpy(date, t->value, 5);
574  av_dict_set(m, "TYER", NULL, 0);
575  av_dict_set(m, "TYE", NULL, 0);
576 
577  if (!(t = get_date_tag(*m, "TDAT")) &&
578  !(t = get_date_tag(*m, "TDA")))
579  goto finish;
580  snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
581  av_dict_set(m, "TDAT", NULL, 0);
582  av_dict_set(m, "TDA", NULL, 0);
583 
584  if (!(t = get_date_tag(*m, "TIME")) &&
585  !(t = get_date_tag(*m, "TIM")))
586  goto finish;
587  snprintf(date + 10, sizeof(date) - 10,
588  " %.2s:%.2s", t->value, t->value + 2);
589  av_dict_set(m, "TIME", NULL, 0);
590  av_dict_set(m, "TIM", NULL, 0);
591 
592 finish:
593  if (date[0])
594  av_dict_set(m, "date", date, 0);
595 }
596 
597 static void free_apic(void *obj)
598 {
599  ID3v2ExtraMetaAPIC *apic = obj;
600  av_buffer_unref(&apic->buf);
601  av_freep(&apic->description);
602 }
603 
604 static void rstrip_spaces(char *buf)
605 {
606  size_t len = strlen(buf);
607  while (len > 0 && buf[len - 1] == ' ')
608  buf[--len] = 0;
609 }
610 
611 static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
612  const char *tag, ExtraMetaList *extra_meta, int isv34)
613 {
614  int enc, pic_type;
615  char mimetype[64] = {0};
616  const CodecMime *mime = ff_id3v2_mime_tags;
617  enum AVCodecID id = AV_CODEC_ID_NONE;
618  ID3v2ExtraMetaAPIC *apic = NULL;
619  ID3v2ExtraMeta *new_extra = NULL;
620  int64_t end = avio_tell(pb) + taglen;
621 
622  if (taglen <= 4 || (!isv34 && taglen <= 6))
623  goto fail;
624 
625  new_extra = av_mallocz(sizeof(*new_extra));
626  if (!new_extra)
627  goto fail;
628 
629  apic = &new_extra->data.apic;
630 
631  enc = avio_r8(pb);
632  taglen--;
633 
634  /* mimetype */
635  if (isv34) {
636  int ret = avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
637  if (ret < 0 || ret >= taglen)
638  goto fail;
639  taglen -= ret;
640  } else {
641  if (avio_read(pb, mimetype, 3) < 0)
642  goto fail;
643 
644  mimetype[3] = 0;
645  taglen -= 3;
646  }
647 
648  while (mime->id != AV_CODEC_ID_NONE) {
649  if (!av_strncasecmp(mime->str, mimetype, sizeof(mimetype))) {
650  id = mime->id;
651  break;
652  }
653  mime++;
654  }
655  if (id == AV_CODEC_ID_NONE) {
657  "Unknown attached picture mimetype: %s, skipping.\n", mimetype);
658  goto fail;
659  }
660  apic->id = id;
661 
662  /* picture type */
663  pic_type = avio_r8(pb);
664  taglen--;
665  if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) {
666  av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n",
667  pic_type);
668  pic_type = 0;
669  }
670  apic->type = ff_id3v2_picture_types[pic_type];
671 
672  /* description and picture data */
673  if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) {
675  "Error decoding attached picture description.\n");
676  goto fail;
677  }
678 
680  if (!apic->buf || !taglen || avio_read(pb, apic->buf->data, taglen) != taglen)
681  goto fail;
682  memset(apic->buf->data + taglen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
683 
684  new_extra->tag = "APIC";
685 
686  // The description must be unique, and some ID3v2 tag writers add spaces
687  // to write several APIC entries with the same description.
688  rstrip_spaces(apic->description);
689  list_append(new_extra, extra_meta);
690 
691  return;
692 
693 fail:
694  if (apic)
695  free_apic(apic);
696  av_freep(&new_extra);
697  avio_seek(pb, end, SEEK_SET);
698 }
699 
700 static void free_chapter(void *obj)
701 {
702  ID3v2ExtraMetaCHAP *chap = obj;
703  av_freep(&chap->element_id);
704  av_dict_free(&chap->meta);
705 }
706 
708  const char *ttag, ExtraMetaList *extra_meta, int isv34)
709 {
710  int taglen;
711  char tag[5];
712  ID3v2ExtraMeta *new_extra = NULL;
713  ID3v2ExtraMetaCHAP *chap = NULL;
714 
715  new_extra = av_mallocz(sizeof(*new_extra));
716  if (!new_extra)
717  return;
718 
719  chap = &new_extra->data.chap;
720 
721  if (decode_str(s, pb, 0, &chap->element_id, &len) < 0)
722  goto fail;
723 
724  if (len < 16)
725  goto fail;
726 
727  chap->start = avio_rb32(pb);
728  chap->end = avio_rb32(pb);
729  avio_skip(pb, 8);
730 
731  len -= 16;
732  while (len > 10) {
733  if (avio_read(pb, tag, 4) < 4)
734  goto fail;
735  tag[4] = 0;
736  taglen = avio_rb32(pb);
737  avio_skip(pb, 2);
738  len -= 10;
739  if (taglen < 0 || taglen > len)
740  goto fail;
741  if (tag[0] == 'T')
742  read_ttag(s, pb, taglen, &chap->meta, tag);
743  else
744  avio_skip(pb, taglen);
745  len -= taglen;
746  }
747 
750 
751  new_extra->tag = "CHAP";
752  list_append(new_extra, extra_meta);
753 
754  return;
755 
756 fail:
757  free_chapter(chap);
758  av_freep(&new_extra);
759 }
760 
761 static void free_priv(void *obj)
762 {
763  ID3v2ExtraMetaPRIV *priv = obj;
764  av_freep(&priv->owner);
765  av_freep(&priv->data);
766 }
767 
768 static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen,
769  const char *tag, ExtraMetaList *extra_meta, int isv34)
770 {
771  ID3v2ExtraMeta *meta;
772  ID3v2ExtraMetaPRIV *priv;
773 
774  meta = av_mallocz(sizeof(*meta));
775  if (!meta)
776  return;
777 
778  priv = &meta->data.priv;
779 
780  if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &priv->owner, &taglen) < 0)
781  goto fail;
782 
783  priv->data = av_malloc(taglen);
784  if (!priv->data)
785  goto fail;
786 
787  priv->datasize = taglen;
788 
789  if (avio_read(pb, priv->data, priv->datasize) != priv->datasize)
790  goto fail;
791 
792  meta->tag = "PRIV";
793  list_append(meta, extra_meta);
794 
795  return;
796 
797 fail:
798  free_priv(priv);
799  av_freep(&meta);
800 }
801 
802 typedef struct ID3v2EMFunc {
803  const char *tag3;
804  const char *tag4;
805  void (*read)(AVFormatContext *s, AVIOContext *pb, int taglen,
806  const char *tag, ExtraMetaList *extra_meta,
807  int isv34);
808  void (*free)(void *obj);
809 } ID3v2EMFunc;
810 
812  { "GEO", "GEOB", read_geobtag, free_geobtag },
813  { "PIC", "APIC", read_apic, free_apic },
814  { "CHAP","CHAP", read_chapter, free_chapter },
815  { "PRIV","PRIV", read_priv, free_priv },
816  { NULL }
817 };
818 
819 /**
820  * Get the corresponding ID3v2EMFunc struct for a tag.
821  * @param isv34 Determines if v2.2 or v2.3/4 strings are used
822  * @return A pointer to the ID3v2EMFunc struct if found, NULL otherwise.
823  */
824 static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
825 {
826  int i = 0;
827  while (id3v2_extra_meta_funcs[i].tag3) {
828  if (tag && !memcmp(tag,
829  (isv34 ? id3v2_extra_meta_funcs[i].tag4 :
830  id3v2_extra_meta_funcs[i].tag3),
831  (isv34 ? 4 : 3)))
832  return &id3v2_extra_meta_funcs[i];
833  i++;
834  }
835  return NULL;
836 }
837 
839  AVFormatContext *s, int len, uint8_t version,
840  uint8_t flags, ExtraMetaList *extra_meta)
841 {
842  int isv34, unsync;
843  unsigned tlen;
844  char tag[5];
845  int64_t next, end = avio_tell(pb);
846  int taghdrlen;
847  const char *reason = NULL;
848  FFIOContext pb_local;
849  AVIOContext *pbx;
850  unsigned char *buffer = NULL;
851  int buffer_size = 0;
852  const ID3v2EMFunc *extra_func = NULL;
853  unsigned char *uncompressed_buffer = NULL;
854  av_unused int uncompressed_buffer_size = 0;
855  const char *comm_frame;
856 
857  if (end > INT64_MAX - len - 10)
858  return;
859  end += len;
860 
861  av_log(s, AV_LOG_DEBUG, "id3v2 ver:%d flags:%02X len:%d\n", version, flags, len);
862 
863  switch (version) {
864  case 2:
865  if (flags & 0x40) {
866  reason = "compression";
867  goto error;
868  }
869  isv34 = 0;
870  taghdrlen = 6;
871  comm_frame = "COM";
872  break;
873 
874  case 3:
875  case 4:
876  isv34 = 1;
877  taghdrlen = 10;
878  comm_frame = "COMM";
879  break;
880 
881  default:
882  reason = "version";
883  goto error;
884  }
885 
886  unsync = flags & 0x80;
887 
888  if (isv34 && flags & 0x40) { /* Extended header present, just skip over it */
889  int extlen = get_size(pb, 4);
890  if (version == 4)
891  /* In v2.4 the length includes the length field we just read. */
892  extlen -= 4;
893 
894  if (extlen < 0) {
895  reason = "invalid extended header length";
896  goto error;
897  }
898  avio_skip(pb, extlen);
899  len -= extlen + 4;
900  if (len < 0) {
901  reason = "extended header too long.";
902  goto error;
903  }
904  }
905 
906  while (len >= taghdrlen) {
907  unsigned int tflags = 0;
908  int tunsync = 0;
909  int tcomp = 0;
910  int tencr = 0;
911  av_unused unsigned long dlen;
912 
913  if (isv34) {
914  if (avio_read(pb, tag, 4) < 4)
915  break;
916  tag[4] = 0;
917  if (version == 3) {
918  tlen = avio_rb32(pb);
919  } else {
920  /* some encoders incorrectly uses v3 sizes instead of syncsafe ones
921  * so check the next tag to see which one to use */
922  tlen = avio_rb32(pb);
923  if (tlen > 0x7f) {
924  if (tlen < len) {
925  int64_t cur = avio_tell(pb);
926 
927  if (ffio_ensure_seekback(pb, 2 /* tflags */ + tlen + 4 /* next tag */))
928  break;
929 
930  if (check_tag(pb, cur + 2 + size_to_syncsafe(tlen), 4) == 1)
931  tlen = size_to_syncsafe(tlen);
932  else if (check_tag(pb, cur + 2 + tlen, 4) != 1)
933  break;
934  avio_seek(pb, cur, SEEK_SET);
935  } else
936  tlen = size_to_syncsafe(tlen);
937  }
938  }
939  tflags = avio_rb16(pb);
940  tunsync = tflags & ID3v2_FLAG_UNSYNCH;
941  } else {
942  if (avio_read(pb, tag, 3) < 3)
943  break;
944  tag[3] = 0;
945  tlen = avio_rb24(pb);
946  }
947  if (tlen > (1<<28))
948  break;
949  len -= taghdrlen + tlen;
950 
951  if (len < 0)
952  break;
953 
954  next = avio_tell(pb) + tlen;
955 
956  if (!tlen) {
957  if (tag[0])
958  av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n",
959  tag);
960  continue;
961  }
962 
963  if (tflags & ID3v2_FLAG_DATALEN) {
964  if (tlen < 4)
965  break;
966  dlen = avio_rb32(pb);
967  tlen -= 4;
968  } else
969  dlen = tlen;
970 
971  tcomp = tflags & ID3v2_FLAG_COMPRESSION;
972  tencr = tflags & ID3v2_FLAG_ENCRYPTION;
973 
974  /* skip encrypted tags and, if no zlib, compressed tags */
975  if (tencr || (!CONFIG_ZLIB && tcomp)) {
976  const char *type;
977  if (!tcomp)
978  type = "encrypted";
979  else if (!tencr)
980  type = "compressed";
981  else
982  type = "encrypted and compressed";
983 
984  av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag);
985  avio_skip(pb, tlen);
986  /* check for text tag or supported special meta tag */
987  } else if (tag[0] == 'T' ||
988  !memcmp(tag, "USLT", 4) ||
989  !strcmp(tag, comm_frame) ||
990  (extra_meta &&
991  (extra_func = get_extra_meta_func(tag, isv34)))) {
992  pbx = pb;
993 
994  if (unsync || tunsync || tcomp) {
995  av_fast_malloc(&buffer, &buffer_size, tlen);
996  if (!buffer) {
997  av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
998  goto seek;
999  }
1000  }
1001  if (unsync || tunsync) {
1002  uint8_t *b = buffer;
1003  uint8_t *t = buffer;
1004 
1005  if (avio_read(pb, buffer, tlen) != tlen) {
1006  av_log(s, AV_LOG_ERROR, "Failed to read tag data\n");
1007  goto seek;
1008  }
1009 
1010  const uint8_t *const buf_end = t + tlen;
1011  while (t != buf_end) {
1012  *b++ = *t++;
1013  if (t != buf_end && t[-1] == 0xff && !t[0])
1014  t++;
1015  }
1016 
1017  ffio_init_read_context(&pb_local, buffer, b - buffer);
1018  tlen = b - buffer;
1019  pbx = &pb_local.pub; // read from sync buffer
1020  }
1021 
1022 #if CONFIG_ZLIB
1023  if (tcomp) {
1024  int err;
1025 
1026  av_log(s, AV_LOG_DEBUG, "Compressed frame %s tlen=%d dlen=%ld\n", tag, tlen, dlen);
1027 
1028  if (tlen <= 0)
1029  goto seek;
1030  if (dlen / 32768 > tlen)
1031  goto seek;
1032 
1033  av_fast_malloc(&uncompressed_buffer, &uncompressed_buffer_size, dlen);
1034  if (!uncompressed_buffer) {
1035  av_log(s, AV_LOG_ERROR, "Failed to alloc %ld bytes\n", dlen);
1036  goto seek;
1037  }
1038 
1039  if (!(unsync || tunsync)) {
1040  err = avio_read(pb, buffer, tlen);
1041  if (err < 0) {
1042  av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n");
1043  goto seek;
1044  }
1045  tlen = err;
1046  }
1047 
1048  err = uncompress(uncompressed_buffer, &dlen, buffer, tlen);
1049  if (err != Z_OK) {
1050  av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err);
1051  goto seek;
1052  }
1053  ffio_init_read_context(&pb_local, uncompressed_buffer, dlen);
1054  tlen = dlen;
1055  pbx = &pb_local.pub; // read from sync buffer
1056  }
1057 #endif
1058  if (tag[0] == 'T')
1059  /* parse text tag */
1060  read_ttag(s, pbx, tlen, metadata, tag);
1061  else if (!memcmp(tag, "USLT", 4))
1062  read_uslt(s, pbx, tlen, metadata);
1063  else if (!strcmp(tag, comm_frame))
1064  read_comment(s, pbx, tlen, metadata);
1065  else
1066  /* parse special meta tag */
1067  extra_func->read(s, pbx, tlen, tag, extra_meta, isv34);
1068  } else if (!tag[0]) {
1069  if (tag[1])
1070  av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding\n");
1071  avio_skip(pb, tlen);
1072  break;
1073  }
1074  /* Skip to end of tag */
1075 seek:
1076  avio_seek(pb, next, SEEK_SET);
1077  }
1078 
1079  /* Footer preset, always 10 bytes, skip over it */
1080  if (version == 4 && flags & 0x10)
1081  end += 10;
1082 
1083 error:
1084  if (reason)
1085  av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n",
1086  version, reason);
1087  avio_seek(pb, end, SEEK_SET);
1088  av_free(buffer);
1089  av_free(uncompressed_buffer);
1090  return;
1091 }
1092 
1094  AVFormatContext *s, const char *magic,
1095  ID3v2ExtraMeta **extra_metap, int64_t max_search_size)
1096 {
1097  int len, ret;
1098  uint8_t buf[ID3v2_HEADER_SIZE];
1099  ExtraMetaList extra_meta = { NULL };
1100  int found_header;
1101  int64_t start, off;
1102 
1103  if (extra_metap)
1104  *extra_metap = NULL;
1105 
1106  if (max_search_size && max_search_size < ID3v2_HEADER_SIZE)
1107  return;
1108 
1109  start = avio_tell(pb);
1110  do {
1111  /* save the current offset in case there's nothing to read/skip */
1112  off = avio_tell(pb);
1113  if (max_search_size && off - start >= max_search_size - ID3v2_HEADER_SIZE) {
1114  avio_seek(pb, off, SEEK_SET);
1115  break;
1116  }
1117 
1119  if (ret >= 0)
1120  ret = avio_read(pb, buf, ID3v2_HEADER_SIZE);
1121  if (ret != ID3v2_HEADER_SIZE) {
1122  avio_seek(pb, off, SEEK_SET);
1123  break;
1124  }
1125  found_header = ff_id3v2_match(buf, magic);
1126  if (found_header) {
1127  /* parse ID3v2 header */
1128  len = ((buf[6] & 0x7f) << 21) |
1129  ((buf[7] & 0x7f) << 14) |
1130  ((buf[8] & 0x7f) << 7) |
1131  (buf[9] & 0x7f);
1132  id3v2_parse(pb, metadata, s, len, buf[3], buf[5],
1133  extra_metap ? &extra_meta : NULL);
1134  } else {
1135  avio_seek(pb, off, SEEK_SET);
1136  }
1137  } while (found_header);
1142  if (extra_metap)
1143  *extra_metap = extra_meta.head;
1144 }
1145 
1147  const char *magic, ID3v2ExtraMeta **extra_meta)
1148 {
1149  id3v2_read_internal(pb, metadata, NULL, magic, extra_meta, 0);
1150 }
1151 
1152 void ff_id3v2_read(AVFormatContext *s, const char *magic,
1153  ID3v2ExtraMeta **extra_meta, unsigned int max_search_size)
1154 {
1155  id3v2_read_internal(s->pb, &s->metadata, s, magic, extra_meta, max_search_size);
1156 }
1157 
1159 {
1160  ID3v2ExtraMeta *current = *extra_meta, *next;
1161  const ID3v2EMFunc *extra_func;
1162 
1163  while (current) {
1164  if ((extra_func = get_extra_meta_func(current->tag, 1)))
1165  extra_func->free(&current->data);
1166  next = current->next;
1167  av_freep(&current);
1168  current = next;
1169  }
1170 
1171  *extra_meta = NULL;
1172 }
1173 
1175 {
1176  ID3v2ExtraMeta *cur;
1177 
1178  for (cur = extra_meta; cur; cur = cur->next) {
1179  ID3v2ExtraMetaAPIC *apic;
1180  AVStream *st;
1181  int ret;
1182 
1183  if (strcmp(cur->tag, "APIC"))
1184  continue;
1185  apic = &cur->data.apic;
1186 
1187  ret = ff_add_attached_pic(s, NULL, NULL, &apic->buf, 0);
1188  if (ret < 0)
1189  return ret;
1190  st = s->streams[s->nb_streams - 1];
1191  st->codecpar->codec_id = apic->id;
1192 
1193  if (AV_RB64(st->attached_pic.data) == PNGSIG)
1195 
1196  if (apic->description[0])
1197  av_dict_set(&st->metadata, "title", apic->description, 0);
1198 
1199  av_dict_set(&st->metadata, "comment", apic->type, 0);
1200  }
1201 
1202  return 0;
1203 }
1204 
1206 {
1207  AVRational time_base = {1, 1000};
1208  int ret;
1209 
1210  for (unsigned i = 0; cur; cur = cur->next) {
1211  ID3v2ExtraMetaCHAP *chap;
1212  AVChapter *chapter;
1213 
1214  if (strcmp(cur->tag, "CHAP"))
1215  continue;
1216 
1217  chap = &cur->data.chap;
1218  chapter = avpriv_new_chapter(s, i++, time_base, chap->start,
1219  chap->end, chap->element_id);
1220  if (!chapter)
1221  continue;
1222 
1223  if ((ret = av_dict_copy(&chapter->metadata, chap->meta, 0)) < 0)
1224  return ret;
1225  }
1226 
1227  return 0;
1228 }
1229 
1231 {
1232  ID3v2ExtraMeta *cur;
1234 
1235  for (cur = extra_meta; cur; cur = cur->next) {
1236  if (!strcmp(cur->tag, "PRIV")) {
1237  ID3v2ExtraMetaPRIV *priv = &cur->data.priv;
1238  AVBPrint bprint;
1239  char *escaped, *key;
1240  int i, ret;
1241 
1242  if ((key = av_asprintf(ID3v2_PRIV_METADATA_PREFIX "%s", priv->owner)) == NULL) {
1243  return AVERROR(ENOMEM);
1244  }
1245 
1246  av_bprint_init(&bprint, priv->datasize + 1, AV_BPRINT_SIZE_UNLIMITED);
1247 
1248  for (i = 0; i < priv->datasize; i++) {
1249  if (priv->data[i] < 32 || priv->data[i] > 126 || priv->data[i] == '\\') {
1250  av_bprintf(&bprint, "\\x%02x", priv->data[i]);
1251  } else {
1252  av_bprint_chars(&bprint, priv->data[i], 1);
1253  }
1254  }
1255 
1256  if ((ret = av_bprint_finalize(&bprint, &escaped)) < 0) {
1257  av_free(key);
1258  return ret;
1259  }
1260 
1261  if ((ret = av_dict_set(metadata, key, escaped, dict_flags)) < 0) {
1262  return ret;
1263  }
1264  }
1265  }
1266 
1267  return 0;
1268 }
1269 
1271 {
1272  return ff_id3v2_parse_priv_dict(&s->metadata, extra_meta);
1273 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
avpriv_new_chapter
AVChapter * avpriv_new_chapter(AVFormatContext *s, int64_t id, AVRational time_base, int64_t start, int64_t end, const char *title)
Add a new chapter.
Definition: demux_utils.c:43
flags
const SwsFlags flags[]
Definition: swscale.c:72
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
PUT_UTF8
#define PUT_UTF8(val, tmp, PUT_BYTE)
Definition: common.h:541
ID3v2ExtraMeta::geob
ID3v2ExtraMetaGEOB geob
Definition: id3v2.h:90
AVChapter::metadata
AVDictionary * metadata
Definition: avformat.h:1226
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
ID3v2ExtraMeta::next
struct ID3v2ExtraMeta * next
Definition: id3v2.h:86
free_chapter
static void free_chapter(void *obj)
Definition: id3v2.c:700
rstrip_spaces
static void rstrip_spaces(char *buf)
Definition: id3v2.c:604
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
free_geobtag
static void free_geobtag(void *obj)
Free GEOB type extra metadata.
Definition: id3v2.c:227
size_to_syncsafe
static unsigned int size_to_syncsafe(unsigned int size)
Definition: id3v2.c:182
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
int64_t
long long int64_t
Definition: coverity.c:34
av_asprintf
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:115
av_unused
#define av_unused
Definition: attributes.h:164
id3v2.h
ff_metadata_conv
void ff_metadata_conv(AVDictionary **pm, const AVMetadataConv *d_conv, const AVMetadataConv *s_conv)
Definition: metadata.c:26
list_append
static void list_append(ID3v2ExtraMeta *new_elem, ExtraMetaList *list)
Definition: id3v2.c:468
ID3v1_GENRE_MAX
#define ID3v1_GENRE_MAX
Definition: id3v1.h:29
AVPacket::data
uint8_t * data
Definition: packet.h:595
b
#define b
Definition: input.c:43
ff_id3v2_read
void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta, unsigned int max_search_size)
Read an ID3v2 tag, including supported extra metadata.
Definition: id3v2.c:1152
AVMetadataConv
Definition: metadata.h:34
read_apic
static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, const char *tag, ExtraMetaList *extra_meta, int isv34)
Definition: id3v2.c:611
ID3v2ExtraMetaAPIC::id
enum AVCodecID id
Definition: id3v2.h:69
read_ttag
static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen, AVDictionary **metadata, const char *key)
Parse a text tag.
Definition: id3v2.c:337
AVDictionary
Definition: dict.c:32
ffio_init_read_context
void ffio_init_read_context(FFIOContext *s, const uint8_t *buffer, int buffer_size)
Wrap a buffer in an AVIOContext for reading.
Definition: aviobuf.c:99
ID3v2_FLAG_ENCRYPTION
#define ID3v2_FLAG_ENCRYPTION
Definition: id3v2.h:39
id3v1.h
FFIOContext
Definition: avio_internal.h:28
decode_str
static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding, uint8_t **dst, int *maxread)
Decode characters to UTF-8 according to encoding type.
Definition: id3v2.c:248
ID3v2ExtraMetaGEOB
Definition: id3v2.h:57
free_apic
static void free_apic(void *obj)
Definition: id3v2.c:597
ExtraMetaList
Definition: id3v2.c:464
CodecMime
Definition: internal.h:47
ID3v2EMFunc::tag3
const char * tag3
Definition: id3v2.c:803
attribute_nonstring
#define attribute_nonstring
Definition: attributes_internal.h:42
finish
static void finish(void)
Definition: movenc.c:374
ExtraMetaList::tail
ID3v2ExtraMeta * tail
Definition: id3v2.c:465
fail
#define fail()
Definition: checkasm.h:224
check_tag
static int check_tag(AVIOContext *s, int offset, unsigned int len)
Return 1 if the tag of length len at the given offset is valid, 0 if not, -1 on error.
Definition: id3v2.c:210
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
AVChapter
Definition: avformat.h:1222
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
ID3v2ExtraMetaCHAP
Definition: id3v2.h:78
ID3v2ExtraMeta::apic
ID3v2ExtraMetaAPIC apic
Definition: id3v2.h:88
avio_rl16
unsigned int avio_rl16(AVIOContext *s)
Definition: aviobuf.c:717
AVStream::attached_pic
AVPacket attached_pic
For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet will contain the attached pictu...
Definition: avformat.h:842
ff_id3v2_parse_chapters
int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta *cur)
Create chapters for all CHAP tags found in the ID3v2 header.
Definition: id3v2.c:1205
AV_DICT_DONT_STRDUP_VAL
#define AV_DICT_DONT_STRDUP_VAL
Take ownership of a value that's been allocated with av_malloc() or another memory allocation functio...
Definition: dict.h:79
ID3v2_PRIV_METADATA_PREFIX
#define ID3v2_PRIV_METADATA_PREFIX
Definition: id3v2.h:42
avio_close_dyn_buf
int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer)
Return the written size and a pointer to the buffer.
Definition: aviobuf.c:1410
get_date_tag
static AVDictionaryEntry * get_date_tag(AVDictionary *m, const char *tag)
Definition: id3v2.c:556
avio_rb32
unsigned int avio_rb32(AVIOContext *s)
Definition: aviobuf.c:764
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
read_chapter
static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, const char *ttag, ExtraMetaList *extra_meta, int isv34)
Definition: id3v2.c:707
ID3v2ExtraMeta
Definition: id3v2.h:84
ID3v2_ENCODING_UTF8
@ ID3v2_ENCODING_UTF8
Definition: id3v2.h:48
ID3v2ExtraMetaCHAP::element_id
uint8_t * element_id
Definition: id3v2.h:79
av_dict_get
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:60
avio_open_dyn_buf
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1365
ff_add_attached_pic
int ff_add_attached_pic(AVFormatContext *s, AVStream *st, AVIOContext *pb, AVBufferRef **buf, int size)
Add an attached pic to an AVStream.
Definition: demux_utils.c:107
read_comment
static void read_comment(AVFormatContext *s, AVIOContext *pb, int taglen, AVDictionary **metadata)
Parse a comment tag.
Definition: id3v2.c:425
attributes_internal.h
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
AV_CODEC_ID_BMP
@ AV_CODEC_ID_BMP
Definition: codec_id.h:130
ID3v2_FLAG_UNSYNCH
#define ID3v2_FLAG_UNSYNCH
Definition: id3v2.h:38
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
ff_id3v2_4_tags
const attribute_nonstring char ff_id3v2_4_tags[][4]
ID3v2.4-only text information frames.
Definition: id3v2.c:100
ID3v2ExtraMetaAPIC::buf
AVBufferRef * buf
Definition: id3v2.h:66
free_priv
static void free_priv(void *obj)
Definition: id3v2.c:761
key
const char * key
Definition: hwcontext_opencl.c:189
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
av_fallthrough
#define av_fallthrough
Definition: attributes.h:67
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
ID3v2_FLAG_DATALEN
#define ID3v2_FLAG_DATALEN
Definition: id3v2.h:37
ID3v2ExtraMetaGEOB::datasize
uint32_t datasize
Definition: id3v2.h:58
AV_CODEC_ID_PNG
@ AV_CODEC_ID_PNG
Definition: codec_id.h:113
ID3v2ExtraMeta::tag
const char * tag
Definition: id3v2.h:85
AVFormatContext
Format I/O context.
Definition: avformat.h:1263
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:767
id3v2_read_internal
static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata, AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_metap, int64_t max_search_size)
Definition: id3v2.c:1093
metadata
Stream codec metadata
Definition: ogg-flac-chained-meta.txt:2
NULL
#define NULL
Definition: coverity.c:32
ID3v2EMFunc::free
void(* free)(void *obj)
Definition: id3v2.c:808
av_buffer_unref
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:139
ID3v2ExtraMetaPRIV::data
uint8_t * data
Definition: id3v2.h:74
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
ID3v2ExtraMetaGEOB::mime_type
uint8_t * mime_type
Definition: id3v2.h:59
ff_id3v2_parse_apic
int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta *extra_meta)
Create a stream for each APIC (attached picture) extracted from the ID3v2 header.
Definition: id3v2.c:1174
ExtraMetaList::head
ID3v2ExtraMeta * head
Definition: id3v2.c:465
list
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining list
Definition: filter_design.txt:25
AVStream::metadata
AVDictionary * metadata
Definition: avformat.h:824
seek
static void BS_FUNC() seek(BSCTX *bc, unsigned pos)
Seek to the given bit position.
Definition: bitstream_template.h:407
AV_DICT_DONT_OVERWRITE
#define AV_DICT_DONT_OVERWRITE
Don't overwrite existing entries.
Definition: dict.h:81
avio_w8
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:184
get
static void get(const uint8_t *pixels, int stride, int16_t *block)
Definition: proresenc_anatoliy.c:318
ff_id3v2_picture_types
const char *const ff_id3v2_picture_types[21]
Definition: id3v2.c:111
ID3v2_HEADER_SIZE
#define ID3v2_HEADER_SIZE
Definition: id3v2.h:30
ff_id3v2_3_tags
const attribute_nonstring char ff_id3v2_3_tags[][4]
ID3v2.3-only text information frames.
Definition: id3v2.c:106
ff_id3v2_mime_tags
const CodecMime ff_id3v2_mime_tags[]
Definition: id3v2.c:135
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:49
av_strncasecmp
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:218
ID3v2ExtraMetaGEOB::file_name
uint8_t * file_name
Definition: id3v2.h:60
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
avio_rb24
unsigned int avio_rb24(AVIOContext *s)
Definition: aviobuf.c:757
get_size
static unsigned int get_size(AVIOContext *s, int len)
Definition: id3v2.c:174
is_number
static int is_number(const char *str)
Definition: id3v2.c:549
ID3v2_ENCODING_UTF16BOM
@ ID3v2_ENCODING_UTF16BOM
Definition: id3v2.h:46
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
ID3v2ExtraMetaCHAP::start
uint32_t start
Definition: id3v2.h:80
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
FFIOContext::pub
AVIOContext pub
Definition: avio_internal.h:29
is_tag
static int is_tag(const char *buf, unsigned int len)
Definition: id3v2.c:192
avio_get_str
int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen)
Read a string from pb into buf.
Definition: aviobuf.c:869
merge_date
static void merge_date(AVDictionary **m)
Definition: id3v2.c:565
size
int size
Definition: twinvq_data.h:10344
AV_RB32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:96
ff_id3v2_34_metadata_conv
const AVMetadataConv ff_id3v2_34_metadata_conv[]
Definition: id3v2.c:48
avio_r8
int avio_r8(AVIOContext *s)
Definition: aviobuf.c:606
ffio_ensure_seekback
int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size)
Ensures that the requested seekback buffer size will be available.
Definition: aviobuf.c:1026
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
attributes.h
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:233
av_buffer_alloc
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:77
version
version
Definition: libkvazaar.c:313
ID3v2ExtraMetaAPIC
Definition: id3v2.h:65
ID3v2ExtraMeta::chap
ID3v2ExtraMetaCHAP chap
Definition: id3v2.h:89
PNGSIG
#define PNGSIG
Definition: png.h:49
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:221
ID3v2ExtraMeta::data
union ID3v2ExtraMeta::@475 data
AV_CODEC_ID_GIF
@ AV_CODEC_ID_GIF
Definition: codec_id.h:149
AV_CODEC_ID_MJPEG
@ AV_CODEC_ID_MJPEG
Definition: codec_id.h:59
bprint.h
av_malloc
#define av_malloc(s)
Definition: ops_asmgen.c:44
AV_CODEC_ID_NONE
@ AV_CODEC_ID_NONE
Definition: codec_id.h:50
avio_rl24
unsigned int avio_rl24(AVIOContext *s)
Definition: aviobuf.c:725
avio_internal.h
ff_id3v2_read_dict
void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, const char *magic, ID3v2ExtraMeta **extra_meta)
Read an ID3v2 tag into specified dictionary and retrieve supported extra metadata.
Definition: id3v2.c:1146
ff_id3v1_genre_str
const char *const ff_id3v1_genre_str[ID3v1_GENRE_MAX+1]
ID3v1 genres.
Definition: id3v1.c:26
AV_CODEC_ID_JPEGXL
@ AV_CODEC_ID_JPEGXL
Definition: codec_id.h:317
id3v2_parse
static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata, AVFormatContext *s, int len, uint8_t version, uint8_t flags, ExtraMetaList *extra_meta)
Definition: id3v2.c:838
GET_UTF16
#define GET_UTF16(val, GET_16BIT, ERROR)
Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form.
Definition: common.h:513
demux.h
AV_CODEC_ID_WEBP
@ AV_CODEC_ID_WEBP
Definition: codec_id.h:226
len
int len
Definition: vorbis_enc_data.h:426
ID3v2ExtraMetaPRIV::datasize
uint32_t datasize
Definition: id3v2.h:75
get_extra_meta_func
static const ID3v2EMFunc * get_extra_meta_func(const char *tag, int isv34)
Get the corresponding ID3v2EMFunc struct for a tag.
Definition: id3v2.c:824
ID3v2_ENCODING_UTF16BE
@ ID3v2_ENCODING_UTF16BE
Definition: id3v2.h:47
language
Undefined Behavior In the C language
Definition: undefined.txt:3
ff_id3v2_tag_len
int ff_id3v2_tag_len(const uint8_t *buf)
Get the length of an ID3v2 tag.
Definition: id3v2.c:162
tag
uint32_t tag
Definition: movenc.c:2046
ffio_free_dyn_buf
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1438
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:744
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:236
avio_rb16
unsigned int avio_rb16(AVIOContext *s)
Definition: aviobuf.c:749
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
dict.h
ff_id3v2_tags
const attribute_nonstring char ff_id3v2_tags[][4]
A list of text information frames allowed in both ID3 v2.3 and v2.4 http://www.id3....
Definition: id3v2.c:92
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
id
enum AVCodecID id
Definition: dts2pts.c:550
left
Tag MUST be and< 10hcoeff half pel interpolation filter coefficients, hcoeff[0] are the 2 middle coefficients[1] are the next outer ones and so on, resulting in a filter like:...eff[2], hcoeff[1], hcoeff[0], hcoeff[0], hcoeff[1], hcoeff[2] ... the sign of the coefficients is not explicitly stored but alternates after each coeff and coeff[0] is positive, so ...,+,-,+,-,+,+,-,+,-,+,... hcoeff[0] is not explicitly stored but found by subtracting the sum of all stored coefficients with signs from 32 hcoeff[0]=32 - hcoeff[1] - hcoeff[2] - ... a good choice for hcoeff and htaps is htaps=6 hcoeff={40,-10, 2} an alternative which requires more computations at both encoder and decoder side and may or may not be better is htaps=8 hcoeff={42,-14, 6,-2}ref_frames minimum of the number of available reference frames and max_ref_frames for example the first frame after a key frame always has ref_frames=1spatial_decomposition_type wavelet type 0 is a 9/7 symmetric compact integer wavelet 1 is a 5/3 symmetric compact integer wavelet others are reserved stored as delta from last, last is reset to 0 if always_reset||keyframeqlog quality(logarithmic quantizer scale) stored as delta from last, last is reset to 0 if always_reset||keyframemv_scale stored as delta from last, last is reset to 0 if always_reset||keyframe FIXME check that everything works fine if this changes between framesqbias dequantization bias stored as delta from last, last is reset to 0 if always_reset||keyframeblock_max_depth maximum depth of the block tree stored as delta from last, last is reset to 0 if always_reset||keyframequant_table quantization tableHighlevel bitstream structure:==============================--------------------------------------------|Header|--------------------------------------------|------------------------------------|||Block0||||split?||||yes no||||......... intra?||||:Block01 :yes no||||:Block02 :....... ..........||||:Block03 ::y DC ::ref index:||||:Block04 ::cb DC ::motion x :||||......... :cr DC ::motion y :||||....... ..........|||------------------------------------||------------------------------------|||Block1|||...|--------------------------------------------|------------ ------------ ------------|||Y subbands||Cb subbands||Cr subbands||||--- ---||--- ---||--- ---|||||LL0||HL0||||LL0||HL0||||LL0||HL0|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||LH0||HH0||||LH0||HH0||||LH0||HH0|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||HL1||LH1||||HL1||LH1||||HL1||LH1|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||HH1||HL2||||HH1||HL2||||HH1||HL2|||||...||...||...|||------------ ------------ ------------|--------------------------------------------Decoding process:=================------------|||Subbands|------------||||------------|Intra DC||||LL0 subband prediction ------------|\ Dequantization ------------------- \||Reference frames|\ IDWT|------- -------|Motion \|||Frame 0||Frame 1||Compensation . OBMC v -------|------- -------|--------------. \------> Frame n output Frame Frame<----------------------------------/|...|------------------- Range Coder:============Binary Range Coder:------------------- The implemented range coder is an adapted version based upon "Range encoding: an algorithm for removing redundancy from a digitised message." by G. N. N. Martin. The symbols encoded by the Snow range coder are bits(0|1). The associated probabilities are not fix but change depending on the symbol mix seen so far. bit seen|new state ---------+----------------------------------------------- 0|256 - state_transition_table[256 - old_state];1|state_transition_table[old_state];state_transition_table={ 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 194, 194, 195, 196, 197, 198, 199, 200, 201, 202, 202, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 215, 215, 216, 217, 218, 219, 220, 220, 222, 223, 224, 225, 226, 227, 227, 229, 229, 230, 231, 232, 234, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 0, 0, 0, 0, 0, 0, 0};FIXME Range Coding of integers:------------------------- FIXME Neighboring Blocks:===================left and top are set to the respective blocks unless they are outside of the image in which case they are set to the Null block top-left is set to the top left block unless it is outside of the image in which case it is set to the left block if this block has no larger parent block or it is at the left side of its parent block and the top right block is not outside of the image then the top right block is used for top-right else the top-left block is used Null block y, cb, cr are 128 level, ref, mx and my are 0 Motion Vector Prediction:=========================1. the motion vectors of all the neighboring blocks are scaled to compensate for the difference of reference frames scaled_mv=(mv *(256 *(current_reference+1)/(mv.reference+1))+128)> the median of the scaled left
Definition: snow.txt:386
AV_DICT_MATCH_CASE
#define AV_DICT_MATCH_CASE
Only get an entry with exact-case key match.
Definition: dict.h:74
ID3v2ExtraMetaGEOB::description
uint8_t * description
Definition: id3v2.h:61
ID3v2ExtraMetaAPIC::type
const char * type
Definition: id3v2.h:67
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
ff_id3v2_4_metadata_conv
const AVMetadataConv ff_id3v2_4_metadata_conv[]
Definition: id3v2.c:67
avio_read
int avio_read(AVIOContext *s, unsigned char *buf, int size)
Read size bytes from AVIOContext into buf.
Definition: aviobuf.c:615
ID3v2ExtraMetaGEOB::data
uint8_t * data
Definition: id3v2.h:62
avio_skip
int64_t avio_skip(AVIOContext *s, int64_t offset)
Skip given number of bytes forward.
Definition: aviobuf.c:321
read_geobtag
static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen, const char *tag, ExtraMetaList *extra_meta, int isv34)
Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
Definition: id3v2.c:480
CodecMime::str
char str[32]
Definition: internal.h:48
CodecMime::id
enum AVCodecID id
Definition: internal.h:49
ID3v2_FLAG_COMPRESSION
#define ID3v2_FLAG_COMPRESSION
Definition: id3v2.h:40
mem.h
av_strdup
#define av_strdup(s)
Definition: ops_asmgen.c:47
read_priv
static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen, const char *tag, ExtraMetaList *extra_meta, int isv34)
Definition: id3v2.c:768
ID3v2EMFunc
Definition: id3v2.c:802
id3v2_extra_meta_funcs
static const ID3v2EMFunc id3v2_extra_meta_funcs[]
Definition: id3v2.c:811
ID3v2ExtraMetaCHAP::end
uint32_t end
Definition: id3v2.h:80
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVDictionaryEntry
Definition: dict.h:90
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:57
png.h
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
av_dict_set
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:86
av_fast_malloc
void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size)
Allocate a buffer, reusing the given one if large enough.
Definition: mem.c:557
av_dict_copy
int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:247
ff_id3v2_free_extra_meta
void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta)
Free memory allocated parsing special (non-text) metadata.
Definition: id3v2.c:1158
ID3v2EMFunc::read
void(* read)(AVFormatContext *s, AVIOContext *pb, int taglen, const char *tag, ExtraMetaList *extra_meta, int isv34)
Definition: id3v2.c:805
av_strlcpy
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:85
ff_id3v2_parse_priv
int ff_id3v2_parse_priv(AVFormatContext *s, ID3v2ExtraMeta *extra_meta)
Add metadata for all PRIV tags in the ID3v2 header.
Definition: id3v2.c:1270
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
id3v2_2_metadata_conv
static const AVMetadataConv id3v2_2_metadata_conv[]
Definition: id3v2.c:79
av_bprint_chars
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:130
AV_CODEC_ID_TIFF
@ AV_CODEC_ID_TIFF
Definition: codec_id.h:148
AVDictionaryEntry::value
char * value
Definition: dict.h:92
avstring.h
ID3v2EMFunc::tag4
const char * tag4
Definition: id3v2.c:804
ff_id3v2_parse_priv_dict
int ff_id3v2_parse_priv_dict(AVDictionary **metadata, ID3v2ExtraMeta *extra_meta)
Parse PRIV tags into a dictionary.
Definition: id3v2.c:1230
snprintf
#define snprintf
Definition: snprintf.h:34
ID3v2ExtraMetaCHAP::meta
AVDictionary * meta
Definition: id3v2.h:81
ID3v2ExtraMetaPRIV
Definition: id3v2.h:72
AV_RB64
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_RB64
Definition: bytestream.h:95
ID3v2ExtraMetaPRIV::owner
uint8_t * owner
Definition: id3v2.h:73
AV_DICT_DONT_STRDUP_KEY
#define AV_DICT_DONT_STRDUP_KEY
Take ownership of a key that's been allocated with av_malloc() or another memory allocation function.
Definition: dict.h:77
ID3v2_ENCODING_ISO8859
@ ID3v2_ENCODING_ISO8859
Definition: id3v2.h:45
ff_id3v2_match
int ff_id3v2_match(const uint8_t *buf, const char *magic)
Detect ID3v2 Header.
Definition: id3v2.c:149
bom
static const char * bom
Definition: microdvddec.c:78
read_uslt
static void read_uslt(AVFormatContext *s, AVIOContext *pb, int taglen, AVDictionary **metadata)
Definition: id3v2.c:376
ID3v2ExtraMetaAPIC::description
uint8_t * description
Definition: id3v2.h:68
ID3v2ExtraMeta::priv
ID3v2ExtraMetaPRIV priv
Definition: id3v2.h:91