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