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 
31 #if CONFIG_ZLIB
32 #include <zlib.h>
33 #endif
34 
36 #include "libavutil/avstring.h"
37 #include "libavutil/bprint.h"
38 #include "libavutil/dict.h"
39 #include "libavutil/intreadwrite.h"
40 #include "libavutil/mem.h"
41 #include "libavcodec/png.h"
42 #include "avio_internal.h"
43 #include "demux.h"
44 #include "id3v1.h"
45 #include "id3v2.h"
46 
48  { "TALB", "album" },
49  { "TCOM", "composer" },
50  { "TCON", "genre" },
51  { "TCOP", "copyright" },
52  { "TENC", "encoded_by" },
53  { "TIT2", "title" },
54  { "TLAN", "language" },
55  { "TPE1", "artist" },
56  { "TPE2", "album_artist" },
57  { "TPE3", "performer" },
58  { "TPOS", "disc" },
59  { "TPUB", "publisher" },
60  { "TRCK", "track" },
61  { "TSSE", "encoder" },
62  { "USLT", "lyrics" },
63  { 0 }
64 };
65 
67  { "TCMP", "compilation" },
68  { "TDRC", "date" },
69  { "TDRL", "date" },
70  { "TDEN", "creation_time" },
71  { "TSOA", "album-sort" },
72  { "TSOP", "artist-sort" },
73  { "TSOT", "title-sort" },
74  { "TIT1", "grouping" },
75  { 0 }
76 };
77 
79  { "TAL", "album" },
80  { "TCO", "genre" },
81  { "TCP", "compilation" },
82  { "TT2", "title" },
83  { "TEN", "encoded_by" },
84  { "TP1", "artist" },
85  { "TP2", "album_artist" },
86  { "TP3", "performer" },
87  { "TRK", "track" },
88  { 0 }
89 };
90 
92  "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDLY", "TENC", "TEXT",
93  "TFLT", "TIT1", "TIT2", "TIT3", "TKEY", "TLAN", "TLEN", "TMED",
94  "TOAL", "TOFN", "TOLY", "TOPE", "TOWN", "TPE1", "TPE2", "TPE3",
95  "TPE4", "TPOS", "TPUB", "TRCK", "TRSN", "TRSO", "TSRC", "TSSE",
96  { 0 },
97 };
98 
100  "TDEN", "TDOR", "TDRC", "TDRL", "TDTG", "TIPL", "TMCL", "TMOO",
101  "TPRO", "TSOA", "TSOP", "TSOT", "TSST",
102  { 0 },
103 };
104 
106  "TDAT", "TIME", "TORY", "TRDA", "TSIZ", "TYER",
107  { 0 },
108 };
109 
110 const char * const ff_id3v2_picture_types[21] = {
111  "Other",
112  "32x32 pixels 'file icon'",
113  "Other file icon",
114  "Cover (front)",
115  "Cover (back)",
116  "Leaflet page",
117  "Media (e.g. label side of CD)",
118  "Lead artist/lead performer/soloist",
119  "Artist/performer",
120  "Conductor",
121  "Band/Orchestra",
122  "Composer",
123  "Lyricist/text writer",
124  "Recording Location",
125  "During recording",
126  "During performance",
127  "Movie/video screen capture",
128  "A bright coloured fish",
129  "Illustration",
130  "Band/artist logotype",
131  "Publisher/Studio logotype",
132 };
133 
135  { "image/gif", AV_CODEC_ID_GIF },
136  { "image/jpeg", AV_CODEC_ID_MJPEG },
137  { "image/jpg", AV_CODEC_ID_MJPEG },
138  { "image/jxl", AV_CODEC_ID_JPEGXL },
139  { "image/png", AV_CODEC_ID_PNG },
140  { "image/tiff", AV_CODEC_ID_TIFF },
141  { "image/bmp", AV_CODEC_ID_BMP },
142  { "image/webp", AV_CODEC_ID_WEBP },
143  { "JPG", AV_CODEC_ID_MJPEG }, /* ID3v2.2 */
144  { "PNG", AV_CODEC_ID_PNG }, /* ID3v2.2 */
145  { "", AV_CODEC_ID_NONE },
146 };
147 
148 int ff_id3v2_match(const uint8_t *buf, const char *magic)
149 {
150  return buf[0] == magic[0] &&
151  buf[1] == magic[1] &&
152  buf[2] == magic[2] &&
153  buf[3] != 0xff &&
154  buf[4] != 0xff &&
155  (buf[6] & 0x80) == 0 &&
156  (buf[7] & 0x80) == 0 &&
157  (buf[8] & 0x80) == 0 &&
158  (buf[9] & 0x80) == 0;
159 }
160 
161 int ff_id3v2_tag_len(const uint8_t *buf)
162 {
163  int len = ((buf[6] & 0x7f) << 21) +
164  ((buf[7] & 0x7f) << 14) +
165  ((buf[8] & 0x7f) << 7) +
166  (buf[9] & 0x7f) +
168  if (buf[5] & 0x10)
170  return len;
171 }
172 
173 static unsigned int get_size(AVIOContext *s, int len)
174 {
175  int v = 0;
176  while (len--)
177  v = (v << 7) + (avio_r8(s) & 0x7F);
178  return v;
179 }
180 
181 static unsigned int size_to_syncsafe(unsigned int size)
182 {
183  return (((size) & (0x7f << 0)) >> 0) +
184  (((size) & (0x7f << 8)) >> 1) +
185  (((size) & (0x7f << 16)) >> 2) +
186  (((size) & (0x7f << 24)) >> 3);
187 }
188 
189 /* No real verification, only check that the tag consists of
190  * a combination of capital alpha-numerical characters */
191 static int is_tag(const char *buf, unsigned int len)
192 {
193  if (!len)
194  return 0;
195 
196  while (len--)
197  if ((buf[len] < 'A' ||
198  buf[len] > 'Z') &&
199  (buf[len] < '0' ||
200  buf[len] > '9'))
201  return 0;
202 
203  return 1;
204 }
205 
206 /**
207  * Return 1 if the tag of length len at the given offset is valid, 0 if not, -1 on error
208  */
209 static int check_tag(AVIOContext *s, int offset, unsigned int len)
210 {
211  char tag[4];
212 
213  if (len > 4 ||
214  avio_seek(s, offset, SEEK_SET) < 0 ||
215  avio_read(s, tag, len) < (int)len)
216  return -1;
217  else if (!AV_RB32(tag) || is_tag(tag, len))
218  return 1;
219 
220  return 0;
221 }
222 
223 /**
224  * Free GEOB type extra metadata.
225  */
226 static void free_geobtag(void *obj)
227 {
228  ID3v2ExtraMetaGEOB *geob = obj;
229  av_freep(&geob->mime_type);
230  av_freep(&geob->file_name);
231  av_freep(&geob->description);
232  av_freep(&geob->data);
233 }
234 
235 /**
236  * Decode characters to UTF-8 according to encoding type. The decoded buffer is
237  * always null terminated. Stop reading when either *maxread bytes are read from
238  * pb or U+0000 character is found.
239  *
240  * @param dst Pointer where the address of the buffer with the decoded bytes is
241  * stored. Buffer must be freed by caller.
242  * @param maxread Pointer to maximum number of characters to read from the
243  * AVIOContext. After execution the value is decremented by the number of bytes
244  * actually read.
245  * @returns 0 if no error occurred, dst is uninitialized on error
246  */
247 static int decode_str(AVFormatContext *s, AVIOContext *pb, int encoding,
248  uint8_t **dst, int *maxread)
249 {
250  int ret;
251  uint8_t tmp;
252  uint32_t ch = 1;
253  int left = *maxread, dynsize;
254  unsigned int (*get)(AVIOContext*) = avio_rb16;
255  AVIOContext *dynbuf;
256 
257  if ((ret = avio_open_dyn_buf(&dynbuf)) < 0) {
258  av_log(s, AV_LOG_ERROR, "Error opening memory stream\n");
259  return ret;
260  }
261 
262  if (left == 0)
263  goto end;
264 
265  switch (encoding) {
267  while (left && ch) {
268  ch = avio_r8(pb);
269  PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
270  left--;
271  }
272  break;
273 
275  if ((left -= 2) < 0) {
276  av_log(s, AV_LOG_ERROR, "Cannot read BOM value, input too short %d\n", left);
277  ffio_free_dyn_buf(&dynbuf);
278  *dst = NULL;
279  return AVERROR_INVALIDDATA;
280  }
281  uint16_t bom = avio_rb16(pb);
282  switch (bom) {
283  case 0xfffe:
284  get = avio_rl16;
285  case 0xfeff:
286  break;
287  case 0: // empty string without bom
288  goto end;
289  default:
290  av_log(s, AV_LOG_ERROR, "Incorrect BOM value: 0x%x\n", bom);
291  ffio_free_dyn_buf(&dynbuf);
292  *dst = NULL;
293  *maxread = left;
294  return AVERROR_INVALIDDATA;
295  }
296  // fall-through
297 
299  while ((left > 1) && ch) {
300  GET_UTF16(ch, ((left -= 2) >= 0 ? get(pb) : 0), break;)
301  PUT_UTF8(ch, tmp, avio_w8(dynbuf, tmp);)
302  }
303  if (left < 0)
304  left += 2; /* did not read last char from pb */
305  break;
306 
307  case ID3v2_ENCODING_UTF8:
308  while (left && ch) {
309  ch = avio_r8(pb);
310  avio_w8(dynbuf, ch);
311  left--;
312  }
313  break;
314  default:
315  av_log(s, AV_LOG_WARNING, "Unknown encoding %d\n", encoding);
316  }
317 
318 end:
319  if (ch)
320  avio_w8(dynbuf, 0);
321 
322  dynsize = avio_close_dyn_buf(dynbuf, dst);
323  if (dynsize <= 0) {
324  av_freep(dst);
325  return AVERROR(ENOMEM);
326  }
327  *maxread = left;
328 
329  return 0;
330 }
331 
332 /**
333  * Parse a text tag.
334  */
335 static void read_ttag(AVFormatContext *s, AVIOContext *pb, int taglen,
336  AVDictionary **metadata, const char *key)
337 {
338  uint8_t *dst;
339  int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
340  unsigned genre;
341 
342  if (taglen < 1)
343  return;
344 
345  encoding = avio_r8(pb);
346  taglen--; /* account for encoding type byte */
347 
348  if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
349  av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
350  return;
351  }
352 
353  if (!(strcmp(key, "TCON") && strcmp(key, "TCO")) &&
354  (sscanf(dst, "(%d)", &genre) == 1 || sscanf(dst, "%d", &genre) == 1) &&
355  genre <= ID3v1_GENRE_MAX) {
356  av_freep(&dst);
357  dst = av_strdup(ff_id3v1_genre_str[genre]);
358  } else if (!(strcmp(key, "TXXX") && strcmp(key, "TXX"))) {
359  /* dst now contains the key, need to get value */
360  key = dst;
361  if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
362  av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", key);
363  av_freep(&key);
364  return;
365  }
366  dict_flags |= AV_DICT_DONT_STRDUP_KEY;
367  } else if (!*dst)
368  av_freep(&dst);
369 
370  if (dst)
371  av_dict_set(metadata, key, dst, dict_flags);
372 }
373 
374 static void read_uslt(AVFormatContext *s, AVIOContext *pb, int taglen,
376 {
377  uint8_t lang[4];
378  uint8_t *descriptor = NULL; // 'Content descriptor'
379  uint8_t *text;
380  char *key;
381  int encoding;
382  int ok = 0;
383 
384  if (taglen < 4)
385  goto error;
386 
387  encoding = avio_r8(pb);
388  taglen--;
389 
390  if (avio_read(pb, lang, 3) < 3)
391  goto error;
392  lang[3] = '\0';
393  taglen -= 3;
394 
395  if (decode_str(s, pb, encoding, &descriptor, &taglen) < 0 || taglen < 0)
396  goto error;
397 
398  if (decode_str(s, pb, encoding, &text, &taglen) < 0 || taglen < 0)
399  goto error;
400 
401  // FFmpeg does not support hierarchical metadata, so concatenate the keys.
402  key = av_asprintf("lyrics-%s%s%s", descriptor[0] ? (char *)descriptor : "",
403  descriptor[0] ? "-" : "",
404  lang);
405  if (!key) {
406  av_free(text);
407  goto error;
408  }
409 
410  av_dict_set(metadata, key, text,
412 
413  ok = 1;
414 error:
415  if (!ok)
416  av_log(s, AV_LOG_ERROR, "Error reading lyrics, skipped\n");
417  av_free(descriptor);
418 }
419 
420 /**
421  * Parse a comment tag.
422  */
423 static void read_comment(AVFormatContext *s, AVIOContext *pb, int taglen,
425 {
426  const char *key = "comment";
427  uint8_t *dst;
428  int encoding, dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_VAL;
429  av_unused int language;
430 
431  if (taglen < 4)
432  return;
433 
434  encoding = avio_r8(pb);
435  language = avio_rl24(pb);
436  taglen -= 4;
437 
438  if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
439  av_log(s, AV_LOG_ERROR, "Error reading comment frame, skipped\n");
440  return;
441  }
442 
443  if (dst && !*dst)
444  av_freep(&dst);
445 
446  if (dst) {
447  key = (const char *) dst;
448  dict_flags |= AV_DICT_DONT_STRDUP_KEY;
449  }
450 
451  if (decode_str(s, pb, encoding, &dst, &taglen) < 0) {
452  av_log(s, AV_LOG_ERROR, "Error reading comment frame, skipped\n");
453  if (dict_flags & AV_DICT_DONT_STRDUP_KEY)
454  av_freep((void*)&key);
455  return;
456  }
457 
458  if (dst)
459  av_dict_set(metadata, key, (const char *) dst, dict_flags);
460 }
461 
462 typedef struct ExtraMetaList {
464 } ExtraMetaList;
465 
467 {
468  if (list->tail)
469  list->tail->next = new_elem;
470  else
471  list->head = new_elem;
472  list->tail = new_elem;
473 }
474 
475 /**
476  * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
477  */
478 static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen,
479  const char *tag, ExtraMetaList *extra_meta, int isv34)
480 {
481  ID3v2ExtraMetaGEOB *geob_data = NULL;
482  ID3v2ExtraMeta *new_extra = NULL;
483  char encoding;
484  unsigned int len;
485 
486  if (taglen < 1)
487  return;
488 
489  new_extra = av_mallocz(sizeof(ID3v2ExtraMeta));
490  if (!new_extra) {
491  av_log(s, AV_LOG_ERROR, "Failed to alloc %zu bytes\n",
492  sizeof(ID3v2ExtraMeta));
493  return;
494  }
495 
496  geob_data = &new_extra->data.geob;
497 
498  /* read encoding type byte */
499  encoding = avio_r8(pb);
500  taglen--;
501 
502  /* read MIME type (always ISO-8859) */
503  if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &geob_data->mime_type,
504  &taglen) < 0 ||
505  taglen <= 0)
506  goto fail;
507 
508  /* read file name */
509  if (decode_str(s, pb, encoding, &geob_data->file_name, &taglen) < 0 ||
510  taglen <= 0)
511  goto fail;
512 
513  /* read content description */
514  if (decode_str(s, pb, encoding, &geob_data->description, &taglen) < 0 ||
515  taglen < 0)
516  goto fail;
517 
518  if (taglen) {
519  /* save encapsulated binary data */
520  geob_data->data = av_malloc(taglen);
521  if (!geob_data->data) {
522  av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", taglen);
523  goto fail;
524  }
525  if ((len = avio_read(pb, geob_data->data, taglen)) < taglen)
527  "Error reading GEOB frame, data truncated.\n");
528  geob_data->datasize = len;
529  } else {
530  geob_data->data = NULL;
531  geob_data->datasize = 0;
532  }
533 
534  /* add data to the list */
535  new_extra->tag = "GEOB";
536  list_append(new_extra, extra_meta);
537 
538  return;
539 
540 fail:
541  av_log(s, AV_LOG_ERROR, "Error reading frame %s, skipped\n", tag);
542  free_geobtag(geob_data);
543  av_free(new_extra);
544  return;
545 }
546 
547 static int is_number(const char *str)
548 {
549  while (*str >= '0' && *str <= '9')
550  str++;
551  return !*str;
552 }
553 
555 {
557  if ((t = av_dict_get(m, tag, NULL, AV_DICT_MATCH_CASE)) &&
558  strlen(t->value) == 4 && is_number(t->value))
559  return t;
560  return NULL;
561 }
562 
563 static void merge_date(AVDictionary **m)
564 {
566  char date[17] = { 0 }; // YYYY-MM-DD hh:mm
567 
568  if (!(t = get_date_tag(*m, "TYER")) &&
569  !(t = get_date_tag(*m, "TYE")))
570  return;
571  av_strlcpy(date, t->value, 5);
572  av_dict_set(m, "TYER", NULL, 0);
573  av_dict_set(m, "TYE", NULL, 0);
574 
575  if (!(t = get_date_tag(*m, "TDAT")) &&
576  !(t = get_date_tag(*m, "TDA")))
577  goto finish;
578  snprintf(date + 4, sizeof(date) - 4, "-%.2s-%.2s", t->value + 2, t->value);
579  av_dict_set(m, "TDAT", NULL, 0);
580  av_dict_set(m, "TDA", NULL, 0);
581 
582  if (!(t = get_date_tag(*m, "TIME")) &&
583  !(t = get_date_tag(*m, "TIM")))
584  goto finish;
585  snprintf(date + 10, sizeof(date) - 10,
586  " %.2s:%.2s", t->value, t->value + 2);
587  av_dict_set(m, "TIME", NULL, 0);
588  av_dict_set(m, "TIM", NULL, 0);
589 
590 finish:
591  if (date[0])
592  av_dict_set(m, "date", date, 0);
593 }
594 
595 static void free_apic(void *obj)
596 {
597  ID3v2ExtraMetaAPIC *apic = obj;
598  av_buffer_unref(&apic->buf);
599  av_freep(&apic->description);
600 }
601 
602 static void rstrip_spaces(char *buf)
603 {
604  size_t len = strlen(buf);
605  while (len > 0 && buf[len - 1] == ' ')
606  buf[--len] = 0;
607 }
608 
609 static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
610  const char *tag, ExtraMetaList *extra_meta, int isv34)
611 {
612  int enc, pic_type;
613  char mimetype[64] = {0};
614  const CodecMime *mime = ff_id3v2_mime_tags;
615  enum AVCodecID id = AV_CODEC_ID_NONE;
616  ID3v2ExtraMetaAPIC *apic = NULL;
617  ID3v2ExtraMeta *new_extra = NULL;
618  int64_t end = avio_tell(pb) + taglen;
619 
620  if (taglen <= 4 || (!isv34 && taglen <= 6))
621  goto fail;
622 
623  new_extra = av_mallocz(sizeof(*new_extra));
624  if (!new_extra)
625  goto fail;
626 
627  apic = &new_extra->data.apic;
628 
629  enc = avio_r8(pb);
630  taglen--;
631 
632  /* mimetype */
633  if (isv34) {
634  int ret = avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
635  if (ret < 0 || ret >= taglen)
636  goto fail;
637  taglen -= ret;
638  } else {
639  if (avio_read(pb, mimetype, 3) < 0)
640  goto fail;
641 
642  mimetype[3] = 0;
643  taglen -= 3;
644  }
645 
646  while (mime->id != AV_CODEC_ID_NONE) {
647  if (!av_strncasecmp(mime->str, mimetype, sizeof(mimetype))) {
648  id = mime->id;
649  break;
650  }
651  mime++;
652  }
653  if (id == AV_CODEC_ID_NONE) {
655  "Unknown attached picture mimetype: %s, skipping.\n", mimetype);
656  goto fail;
657  }
658  apic->id = id;
659 
660  /* picture type */
661  pic_type = avio_r8(pb);
662  taglen--;
663  if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) {
664  av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n",
665  pic_type);
666  pic_type = 0;
667  }
668  apic->type = ff_id3v2_picture_types[pic_type];
669 
670  /* description and picture data */
671  if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) {
673  "Error decoding attached picture description.\n");
674  goto fail;
675  }
676 
678  if (!apic->buf || !taglen || avio_read(pb, apic->buf->data, taglen) != taglen)
679  goto fail;
680  memset(apic->buf->data + taglen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
681 
682  new_extra->tag = "APIC";
683 
684  // The description must be unique, and some ID3v2 tag writers add spaces
685  // to write several APIC entries with the same description.
686  rstrip_spaces(apic->description);
687  list_append(new_extra, extra_meta);
688 
689  return;
690 
691 fail:
692  if (apic)
693  free_apic(apic);
694  av_freep(&new_extra);
695  avio_seek(pb, end, SEEK_SET);
696 }
697 
698 static void free_chapter(void *obj)
699 {
700  ID3v2ExtraMetaCHAP *chap = obj;
701  av_freep(&chap->element_id);
702  av_dict_free(&chap->meta);
703 }
704 
706  const char *ttag, ExtraMetaList *extra_meta, int isv34)
707 {
708  int taglen;
709  char tag[5];
710  ID3v2ExtraMeta *new_extra = NULL;
711  ID3v2ExtraMetaCHAP *chap = NULL;
712 
713  new_extra = av_mallocz(sizeof(*new_extra));
714  if (!new_extra)
715  return;
716 
717  chap = &new_extra->data.chap;
718 
719  if (decode_str(s, pb, 0, &chap->element_id, &len) < 0)
720  goto fail;
721 
722  if (len < 16)
723  goto fail;
724 
725  chap->start = avio_rb32(pb);
726  chap->end = avio_rb32(pb);
727  avio_skip(pb, 8);
728 
729  len -= 16;
730  while (len > 10) {
731  if (avio_read(pb, tag, 4) < 4)
732  goto fail;
733  tag[4] = 0;
734  taglen = avio_rb32(pb);
735  avio_skip(pb, 2);
736  len -= 10;
737  if (taglen < 0 || taglen > len)
738  goto fail;
739  if (tag[0] == 'T')
740  read_ttag(s, pb, taglen, &chap->meta, tag);
741  else
742  avio_skip(pb, taglen);
743  len -= taglen;
744  }
745 
748 
749  new_extra->tag = "CHAP";
750  list_append(new_extra, extra_meta);
751 
752  return;
753 
754 fail:
755  free_chapter(chap);
756  av_freep(&new_extra);
757 }
758 
759 static void free_priv(void *obj)
760 {
761  ID3v2ExtraMetaPRIV *priv = obj;
762  av_freep(&priv->owner);
763  av_freep(&priv->data);
764 }
765 
766 static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen,
767  const char *tag, ExtraMetaList *extra_meta, int isv34)
768 {
769  ID3v2ExtraMeta *meta;
770  ID3v2ExtraMetaPRIV *priv;
771 
772  meta = av_mallocz(sizeof(*meta));
773  if (!meta)
774  return;
775 
776  priv = &meta->data.priv;
777 
778  if (decode_str(s, pb, ID3v2_ENCODING_ISO8859, &priv->owner, &taglen) < 0)
779  goto fail;
780 
781  priv->data = av_malloc(taglen);
782  if (!priv->data)
783  goto fail;
784 
785  priv->datasize = taglen;
786 
787  if (avio_read(pb, priv->data, priv->datasize) != priv->datasize)
788  goto fail;
789 
790  meta->tag = "PRIV";
791  list_append(meta, extra_meta);
792 
793  return;
794 
795 fail:
796  free_priv(priv);
797  av_freep(&meta);
798 }
799 
800 typedef struct ID3v2EMFunc {
801  const char *tag3;
802  const char *tag4;
803  void (*read)(AVFormatContext *s, AVIOContext *pb, int taglen,
804  const char *tag, ExtraMetaList *extra_meta,
805  int isv34);
806  void (*free)(void *obj);
807 } ID3v2EMFunc;
808 
810  { "GEO", "GEOB", read_geobtag, free_geobtag },
811  { "PIC", "APIC", read_apic, free_apic },
812  { "CHAP","CHAP", read_chapter, free_chapter },
813  { "PRIV","PRIV", read_priv, free_priv },
814  { NULL }
815 };
816 
817 /**
818  * Get the corresponding ID3v2EMFunc struct for a tag.
819  * @param isv34 Determines if v2.2 or v2.3/4 strings are used
820  * @return A pointer to the ID3v2EMFunc struct if found, NULL otherwise.
821  */
822 static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
823 {
824  int i = 0;
825  while (id3v2_extra_meta_funcs[i].tag3) {
826  if (tag && !memcmp(tag,
827  (isv34 ? id3v2_extra_meta_funcs[i].tag4 :
828  id3v2_extra_meta_funcs[i].tag3),
829  (isv34 ? 4 : 3)))
830  return &id3v2_extra_meta_funcs[i];
831  i++;
832  }
833  return NULL;
834 }
835 
837  AVFormatContext *s, int len, uint8_t version,
838  uint8_t flags, ExtraMetaList *extra_meta)
839 {
840  int isv34, unsync;
841  unsigned tlen;
842  char tag[5];
843  int64_t next, end = avio_tell(pb);
844  int taghdrlen;
845  const char *reason = NULL;
846  FFIOContext pb_local;
847  AVIOContext *pbx;
848  unsigned char *buffer = NULL;
849  int buffer_size = 0;
850  const ID3v2EMFunc *extra_func = NULL;
851  unsigned char *uncompressed_buffer = NULL;
852  av_unused int uncompressed_buffer_size = 0;
853  const char *comm_frame;
854 
855  if (end > INT64_MAX - len - 10)
856  return;
857  end += len;
858 
859  av_log(s, AV_LOG_DEBUG, "id3v2 ver:%d flags:%02X len:%d\n", version, flags, len);
860 
861  switch (version) {
862  case 2:
863  if (flags & 0x40) {
864  reason = "compression";
865  goto error;
866  }
867  isv34 = 0;
868  taghdrlen = 6;
869  comm_frame = "COM";
870  break;
871 
872  case 3:
873  case 4:
874  isv34 = 1;
875  taghdrlen = 10;
876  comm_frame = "COMM";
877  break;
878 
879  default:
880  reason = "version";
881  goto error;
882  }
883 
884  unsync = flags & 0x80;
885 
886  if (isv34 && flags & 0x40) { /* Extended header present, just skip over it */
887  int extlen = get_size(pb, 4);
888  if (version == 4)
889  /* In v2.4 the length includes the length field we just read. */
890  extlen -= 4;
891 
892  if (extlen < 0) {
893  reason = "invalid extended header length";
894  goto error;
895  }
896  avio_skip(pb, extlen);
897  len -= extlen + 4;
898  if (len < 0) {
899  reason = "extended header too long.";
900  goto error;
901  }
902  }
903 
904  while (len >= taghdrlen) {
905  unsigned int tflags = 0;
906  int tunsync = 0;
907  int tcomp = 0;
908  int tencr = 0;
909  av_unused unsigned long dlen;
910 
911  if (isv34) {
912  if (avio_read(pb, tag, 4) < 4)
913  break;
914  tag[4] = 0;
915  if (version == 3) {
916  tlen = avio_rb32(pb);
917  } else {
918  /* some encoders incorrectly uses v3 sizes instead of syncsafe ones
919  * so check the next tag to see which one to use */
920  tlen = avio_rb32(pb);
921  if (tlen > 0x7f) {
922  if (tlen < len) {
923  int64_t cur = avio_tell(pb);
924 
925  if (ffio_ensure_seekback(pb, 2 /* tflags */ + tlen + 4 /* next tag */))
926  break;
927 
928  if (check_tag(pb, cur + 2 + size_to_syncsafe(tlen), 4) == 1)
929  tlen = size_to_syncsafe(tlen);
930  else if (check_tag(pb, cur + 2 + tlen, 4) != 1)
931  break;
932  avio_seek(pb, cur, SEEK_SET);
933  } else
934  tlen = size_to_syncsafe(tlen);
935  }
936  }
937  tflags = avio_rb16(pb);
938  tunsync = tflags & ID3v2_FLAG_UNSYNCH;
939  } else {
940  if (avio_read(pb, tag, 3) < 3)
941  break;
942  tag[3] = 0;
943  tlen = avio_rb24(pb);
944  }
945  if (tlen > (1<<28))
946  break;
947  len -= taghdrlen + tlen;
948 
949  if (len < 0)
950  break;
951 
952  next = avio_tell(pb) + tlen;
953 
954  if (!tlen) {
955  if (tag[0])
956  av_log(s, AV_LOG_DEBUG, "Invalid empty frame %s, skipping.\n",
957  tag);
958  continue;
959  }
960 
961  if (tflags & ID3v2_FLAG_DATALEN) {
962  if (tlen < 4)
963  break;
964  dlen = avio_rb32(pb);
965  tlen -= 4;
966  } else
967  dlen = tlen;
968 
969  tcomp = tflags & ID3v2_FLAG_COMPRESSION;
970  tencr = tflags & ID3v2_FLAG_ENCRYPTION;
971 
972  /* skip encrypted tags and, if no zlib, compressed tags */
973  if (tencr || (!CONFIG_ZLIB && tcomp)) {
974  const char *type;
975  if (!tcomp)
976  type = "encrypted";
977  else if (!tencr)
978  type = "compressed";
979  else
980  type = "encrypted and compressed";
981 
982  av_log(s, AV_LOG_WARNING, "Skipping %s ID3v2 frame %s.\n", type, tag);
983  avio_skip(pb, tlen);
984  /* check for text tag or supported special meta tag */
985  } else if (tag[0] == 'T' ||
986  !memcmp(tag, "USLT", 4) ||
987  !strcmp(tag, comm_frame) ||
988  (extra_meta &&
989  (extra_func = get_extra_meta_func(tag, isv34)))) {
990  pbx = pb;
991 
992  if (unsync || tunsync || tcomp) {
993  av_fast_malloc(&buffer, &buffer_size, tlen);
994  if (!buffer) {
995  av_log(s, AV_LOG_ERROR, "Failed to alloc %d bytes\n", tlen);
996  goto seek;
997  }
998  }
999  if (unsync || tunsync) {
1000  uint8_t *b = buffer;
1001  uint8_t *t = buffer;
1002 
1003  if (avio_read(pb, buffer, tlen) != tlen) {
1004  av_log(s, AV_LOG_ERROR, "Failed to read tag data\n");
1005  goto seek;
1006  }
1007 
1008  const uint8_t *const buf_end = t + tlen;
1009  while (t != buf_end) {
1010  *b++ = *t++;
1011  if (t != buf_end && t[-1] == 0xff && !t[0])
1012  t++;
1013  }
1014 
1015  ffio_init_read_context(&pb_local, buffer, b - buffer);
1016  tlen = b - buffer;
1017  pbx = &pb_local.pub; // read from sync buffer
1018  }
1019 
1020 #if CONFIG_ZLIB
1021  if (tcomp) {
1022  int err;
1023 
1024  av_log(s, AV_LOG_DEBUG, "Compressed frame %s tlen=%d dlen=%ld\n", tag, tlen, dlen);
1025 
1026  if (tlen <= 0)
1027  goto seek;
1028  if (dlen / 32768 > tlen)
1029  goto seek;
1030 
1031  av_fast_malloc(&uncompressed_buffer, &uncompressed_buffer_size, dlen);
1032  if (!uncompressed_buffer) {
1033  av_log(s, AV_LOG_ERROR, "Failed to alloc %ld bytes\n", dlen);
1034  goto seek;
1035  }
1036 
1037  if (!(unsync || tunsync)) {
1038  err = avio_read(pb, buffer, tlen);
1039  if (err < 0) {
1040  av_log(s, AV_LOG_ERROR, "Failed to read compressed tag\n");
1041  goto seek;
1042  }
1043  tlen = err;
1044  }
1045 
1046  err = uncompress(uncompressed_buffer, &dlen, buffer, tlen);
1047  if (err != Z_OK) {
1048  av_log(s, AV_LOG_ERROR, "Failed to uncompress tag: %d\n", err);
1049  goto seek;
1050  }
1051  ffio_init_read_context(&pb_local, uncompressed_buffer, dlen);
1052  tlen = dlen;
1053  pbx = &pb_local.pub; // read from sync buffer
1054  }
1055 #endif
1056  if (tag[0] == 'T')
1057  /* parse text tag */
1058  read_ttag(s, pbx, tlen, metadata, tag);
1059  else if (!memcmp(tag, "USLT", 4))
1060  read_uslt(s, pbx, tlen, metadata);
1061  else if (!strcmp(tag, comm_frame))
1062  read_comment(s, pbx, tlen, metadata);
1063  else
1064  /* parse special meta tag */
1065  extra_func->read(s, pbx, tlen, tag, extra_meta, isv34);
1066  } else if (!tag[0]) {
1067  if (tag[1])
1068  av_log(s, AV_LOG_WARNING, "invalid frame id, assuming padding\n");
1069  avio_skip(pb, tlen);
1070  break;
1071  }
1072  /* Skip to end of tag */
1073 seek:
1074  avio_seek(pb, next, SEEK_SET);
1075  }
1076 
1077  /* Footer preset, always 10 bytes, skip over it */
1078  if (version == 4 && flags & 0x10)
1079  end += 10;
1080 
1081 error:
1082  if (reason)
1083  av_log(s, AV_LOG_INFO, "ID3v2.%d tag skipped, cannot handle %s\n",
1084  version, reason);
1085  avio_seek(pb, end, SEEK_SET);
1086  av_free(buffer);
1087  av_free(uncompressed_buffer);
1088  return;
1089 }
1090 
1092  AVFormatContext *s, const char *magic,
1093  ID3v2ExtraMeta **extra_metap, int64_t max_search_size)
1094 {
1095  int len, ret;
1096  uint8_t buf[ID3v2_HEADER_SIZE];
1097  ExtraMetaList extra_meta = { NULL };
1098  int found_header;
1099  int64_t start, off;
1100 
1101  if (extra_metap)
1102  *extra_metap = NULL;
1103 
1104  if (max_search_size && max_search_size < ID3v2_HEADER_SIZE)
1105  return;
1106 
1107  start = avio_tell(pb);
1108  do {
1109  /* save the current offset in case there's nothing to read/skip */
1110  off = avio_tell(pb);
1111  if (max_search_size && off - start >= max_search_size - ID3v2_HEADER_SIZE) {
1112  avio_seek(pb, off, SEEK_SET);
1113  break;
1114  }
1115 
1117  if (ret >= 0)
1118  ret = avio_read(pb, buf, ID3v2_HEADER_SIZE);
1119  if (ret != ID3v2_HEADER_SIZE) {
1120  avio_seek(pb, off, SEEK_SET);
1121  break;
1122  }
1123  found_header = ff_id3v2_match(buf, magic);
1124  if (found_header) {
1125  /* parse ID3v2 header */
1126  len = ((buf[6] & 0x7f) << 21) |
1127  ((buf[7] & 0x7f) << 14) |
1128  ((buf[8] & 0x7f) << 7) |
1129  (buf[9] & 0x7f);
1130  id3v2_parse(pb, metadata, s, len, buf[3], buf[5],
1131  extra_metap ? &extra_meta : NULL);
1132  } else {
1133  avio_seek(pb, off, SEEK_SET);
1134  }
1135  } while (found_header);
1140  if (extra_metap)
1141  *extra_metap = extra_meta.head;
1142 }
1143 
1145  const char *magic, ID3v2ExtraMeta **extra_meta)
1146 {
1147  id3v2_read_internal(pb, metadata, NULL, magic, extra_meta, 0);
1148 }
1149 
1150 void ff_id3v2_read(AVFormatContext *s, const char *magic,
1151  ID3v2ExtraMeta **extra_meta, unsigned int max_search_size)
1152 {
1153  id3v2_read_internal(s->pb, &s->metadata, s, magic, extra_meta, max_search_size);
1154 }
1155 
1157 {
1158  ID3v2ExtraMeta *current = *extra_meta, *next;
1159  const ID3v2EMFunc *extra_func;
1160 
1161  while (current) {
1162  if ((extra_func = get_extra_meta_func(current->tag, 1)))
1163  extra_func->free(&current->data);
1164  next = current->next;
1165  av_freep(&current);
1166  current = next;
1167  }
1168 
1169  *extra_meta = NULL;
1170 }
1171 
1173 {
1174  ID3v2ExtraMeta *cur;
1175 
1176  for (cur = extra_meta; cur; cur = cur->next) {
1177  ID3v2ExtraMetaAPIC *apic;
1178  AVStream *st;
1179  int ret;
1180 
1181  if (strcmp(cur->tag, "APIC"))
1182  continue;
1183  apic = &cur->data.apic;
1184 
1185  ret = ff_add_attached_pic(s, NULL, NULL, &apic->buf, 0);
1186  if (ret < 0)
1187  return ret;
1188  st = s->streams[s->nb_streams - 1];
1189  st->codecpar->codec_id = apic->id;
1190 
1191  if (AV_RB64(st->attached_pic.data) == PNGSIG)
1193 
1194  if (apic->description[0])
1195  av_dict_set(&st->metadata, "title", apic->description, 0);
1196 
1197  av_dict_set(&st->metadata, "comment", apic->type, 0);
1198  }
1199 
1200  return 0;
1201 }
1202 
1204 {
1205  AVRational time_base = {1, 1000};
1206  int ret;
1207 
1208  for (unsigned i = 0; cur; cur = cur->next) {
1209  ID3v2ExtraMetaCHAP *chap;
1210  AVChapter *chapter;
1211 
1212  if (strcmp(cur->tag, "CHAP"))
1213  continue;
1214 
1215  chap = &cur->data.chap;
1216  chapter = avpriv_new_chapter(s, i++, time_base, chap->start,
1217  chap->end, chap->element_id);
1218  if (!chapter)
1219  continue;
1220 
1221  if ((ret = av_dict_copy(&chapter->metadata, chap->meta, 0)) < 0)
1222  return ret;
1223  }
1224 
1225  return 0;
1226 }
1227 
1229 {
1230  ID3v2ExtraMeta *cur;
1232 
1233  for (cur = extra_meta; cur; cur = cur->next) {
1234  if (!strcmp(cur->tag, "PRIV")) {
1235  ID3v2ExtraMetaPRIV *priv = &cur->data.priv;
1236  AVBPrint bprint;
1237  char *escaped, *key;
1238  int i, ret;
1239 
1240  if ((key = av_asprintf(ID3v2_PRIV_METADATA_PREFIX "%s", priv->owner)) == NULL) {
1241  return AVERROR(ENOMEM);
1242  }
1243 
1244  av_bprint_init(&bprint, priv->datasize + 1, AV_BPRINT_SIZE_UNLIMITED);
1245 
1246  for (i = 0; i < priv->datasize; i++) {
1247  if (priv->data[i] < 32 || priv->data[i] > 126 || priv->data[i] == '\\') {
1248  av_bprintf(&bprint, "\\x%02x", priv->data[i]);
1249  } else {
1250  av_bprint_chars(&bprint, priv->data[i], 1);
1251  }
1252  }
1253 
1254  if ((ret = av_bprint_finalize(&bprint, &escaped)) < 0) {
1255  av_free(key);
1256  return ret;
1257  }
1258 
1259  if ((ret = av_dict_set(metadata, key, escaped, dict_flags)) < 0) {
1260  return ret;
1261  }
1262  }
1263  }
1264 
1265  return 0;
1266 }
1267 
1269 {
1270  return ff_id3v2_parse_priv_dict(&s->metadata, extra_meta);
1271 }
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:698
rstrip_spaces
static void rstrip_spaces(char *buf)
Definition: id3v2.c:602
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:226
size_to_syncsafe
static unsigned int size_to_syncsafe(unsigned int size)
Definition: id3v2.c:181
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:156
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:466
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:42
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:1150
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:609
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:335
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:247
ID3v2ExtraMetaGEOB
Definition: id3v2.h:57
free_apic
static void free_apic(void *obj)
Definition: id3v2.c:595
ExtraMetaList
Definition: id3v2.c:462
CodecMime
Definition: internal.h:47
ID3v2EMFunc::tag3
const char * tag3
Definition: id3v2.c:801
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:463
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:209
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:1203
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:554
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:705
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:423
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:99
ID3v2ExtraMetaAPIC::buf
AVBufferRef * buf
Definition: id3v2.h:66
free_priv
static void free_priv(void *obj)
Definition: id3v2.c:759
key
const char * key
Definition: hwcontext_opencl.c:189
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
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:1091
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:806
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:1172
ExtraMetaList::head
ID3v2ExtraMeta * head
Definition: id3v2.c:463
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:110
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:105
ff_id3v2_mime_tags
const CodecMime ff_id3v2_mime_tags[]
Definition: id3v2.c:134
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:173
is_number
static int is_number(const char *str)
Definition: id3v2.c:547
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:191
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:563
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:47
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
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:1144
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:836
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:822
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:161
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:91
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
id
enum AVCodecID id
Definition: dts2pts.c:549
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:66
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:478
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:766
ID3v2EMFunc
Definition: id3v2.c:800
id3v2_extra_meta_funcs
static const ID3v2EMFunc id3v2_extra_meta_funcs[]
Definition: id3v2.c:809
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:55
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:1156
ID3v2EMFunc::read
void(* read)(AVFormatContext *s, AVIOContext *pb, int taglen, const char *tag, ExtraMetaList *extra_meta, int isv34)
Definition: id3v2.c:803
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:1268
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:78
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:802
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:1228
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:148
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:374
ID3v2ExtraMetaAPIC::description
uint8_t * description
Definition: id3v2.h:68
ID3v2ExtraMeta::priv
ID3v2ExtraMetaPRIV priv
Definition: id3v2.h:91