]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/id3v2.c
avfilter/avfilter: Remove compatibility code for old filter options
[ffmpeg] / libavformat / id3v2.c
index 336a3964de91bd55a98d24690a3b077f75f90fe1..96226193c1dd74cd3cc7cb41acc87f3d47b89441 100644 (file)
@@ -443,12 +443,24 @@ static void read_comment(AVFormatContext *s, AVIOContext *pb, int taglen,
         av_dict_set(metadata, key, (const char *) dst, dict_flags);
 }
 
+typedef struct ExtraMetaList {
+    ID3v2ExtraMeta *head, *tail;
+} ExtraMetaList;
+
+static void list_append(ID3v2ExtraMeta *new_elem, ExtraMetaList *list)
+{
+    if (list->tail)
+        list->tail->next = new_elem;
+    else
+        list->head = new_elem;
+    list->tail = new_elem;
+}
+
 /**
  * Parse GEOB tag into a ID3v2ExtraMetaGEOB struct.
  */
 static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen,
-                         const char *tag, ID3v2ExtraMeta **extra_meta,
-                         int isv34)
+                         const char *tag, ExtraMetaList *extra_meta, int isv34)
 {
     ID3v2ExtraMetaGEOB *geob_data = NULL;
     ID3v2ExtraMeta *new_extra     = NULL;
@@ -505,8 +517,7 @@ static void read_geobtag(AVFormatContext *s, AVIOContext *pb, int taglen,
 
     /* add data to the list */
     new_extra->tag  = "GEOB";
-    new_extra->next = *extra_meta;
-    *extra_meta     = new_extra;
+    list_append(new_extra, extra_meta);
 
     return;
 
@@ -580,8 +591,7 @@ static void rstrip_spaces(char *buf)
 }
 
 static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
-                      const char *tag, ID3v2ExtraMeta **extra_meta,
-                      int isv34)
+                      const char *tag, ExtraMetaList *extra_meta, int isv34)
 {
     int enc, pic_type;
     char mimetype[64] = {0};
@@ -605,7 +615,10 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
 
     /* mimetype */
     if (isv34) {
-        taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
+        int ret = avio_get_str(pb, taglen, mimetype, sizeof(mimetype));
+        if (ret < 0 || ret >= taglen)
+            goto fail;
+        taglen -= ret;
     } else {
         if (avio_read(pb, mimetype, 3) < 0)
             goto fail;
@@ -651,12 +664,11 @@ static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen,
     memset(apic->buf->data + taglen, 0, AV_INPUT_BUFFER_PADDING_SIZE);
 
     new_extra->tag  = "APIC";
-    new_extra->next = *extra_meta;
-    *extra_meta     = new_extra;
 
     // The description must be unique, and some ID3v2 tag writers add spaces
     // to write several APIC entries with the same description.
     rstrip_spaces(apic->description);
+    list_append(new_extra, extra_meta);
 
     return;
 
@@ -674,7 +686,8 @@ static void free_chapter(void *obj)
     av_dict_free(&chap->meta);
 }
 
-static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, const char *ttag, ID3v2ExtraMeta **extra_meta, int isv34)
+static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len,
+                         const char *ttag, ExtraMetaList *extra_meta, int isv34)
 {
     int taglen;
     char tag[5];
@@ -718,8 +731,7 @@ static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, const cha
     ff_metadata_conv(&chap->meta, NULL, ff_id3v2_4_metadata_conv);
 
     new_extra->tag  = "CHAP";
-    new_extra->next = *extra_meta;
-    *extra_meta     = new_extra;
+    list_append(new_extra, extra_meta);
 
     return;
 
@@ -736,7 +748,7 @@ static void free_priv(void *obj)
 }
 
 static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen,
-                      const char *tag, ID3v2ExtraMeta **extra_meta, int isv34)
+                      const char *tag, ExtraMetaList *extra_meta, int isv34)
 {
     ID3v2ExtraMeta *meta;
     ID3v2ExtraMetaPRIV *priv;
@@ -760,8 +772,7 @@ static void read_priv(AVFormatContext *s, AVIOContext *pb, int taglen,
         goto fail;
 
     meta->tag   = "PRIV";
-    meta->next  = *extra_meta;
-    *extra_meta = meta;
+    list_append(meta, extra_meta);
 
     return;
 
@@ -774,7 +785,7 @@ typedef struct ID3v2EMFunc {
     const char *tag3;
     const char *tag4;
     void (*read)(AVFormatContext *s, AVIOContext *pb, int taglen,
-                 const char *tag, ID3v2ExtraMeta **extra_meta,
+                 const char *tag, ExtraMetaList *extra_meta,
                  int isv34);
     void (*free)(void *obj);
 } ID3v2EMFunc;
@@ -808,12 +819,12 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
 
 static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
                         AVFormatContext *s, int len, uint8_t version,
-                        uint8_t flags, ID3v2ExtraMeta **extra_meta)
+                        uint8_t flags, ExtraMetaList *extra_meta)
 {
     int isv34, unsync;
     unsigned tlen;
     char tag[5];
-    int64_t next, end = avio_tell(pb) + len;
+    int64_t next, end = avio_tell(pb);
     int taghdrlen;
     const char *reason = NULL;
     AVIOContext pb_local;
@@ -825,6 +836,10 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
     av_unused int uncompressed_buffer_size = 0;
     const char *comm_frame;
 
+    if (end > INT64_MAX - len - 10)
+        return;
+    end += len;
+
     av_log(s, AV_LOG_DEBUG, "id3v2 ver:%d flags:%02X len:%d\n", version, flags, len);
 
     switch (version) {
@@ -995,6 +1010,8 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata,
 
                     if (tlen <= 0)
                         goto seek;
+                    if (dlen / 32768 > tlen)
+                        goto seek;
 
                     av_fast_malloc(&uncompressed_buffer, &uncompressed_buffer_size, dlen);
                     if (!uncompressed_buffer) {
@@ -1058,13 +1075,17 @@ error:
 
 static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata,
                                 AVFormatContext *s, const char *magic,
-                                ID3v2ExtraMeta **extra_meta, int64_t max_search_size)
+                                ID3v2ExtraMeta **extra_metap, int64_t max_search_size)
 {
     int len, ret;
     uint8_t buf[ID3v2_HEADER_SIZE];
+    ExtraMetaList extra_meta = { NULL };
     int found_header;
     int64_t start, off;
 
+    if (extra_metap)
+        *extra_metap = NULL;
+
     if (max_search_size && max_search_size < ID3v2_HEADER_SIZE)
         return;
 
@@ -1091,7 +1112,8 @@ static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata,
                   ((buf[7] & 0x7f) << 14) |
                   ((buf[8] & 0x7f) << 7) |
                    (buf[9] & 0x7f);
-            id3v2_parse(pb, metadata, s, len, buf[3], buf[5], extra_meta);
+            id3v2_parse(pb, metadata, s, len, buf[3], buf[5],
+                        extra_metap ? &extra_meta : NULL);
         } else {
             avio_seek(pb, off, SEEK_SET);
         }
@@ -1100,6 +1122,8 @@ static void id3v2_read_internal(AVIOContext *pb, AVDictionary **metadata,
     ff_metadata_conv(metadata, NULL, id3v2_2_metadata_conv);
     ff_metadata_conv(metadata, NULL, ff_id3v2_4_metadata_conv);
     merge_date(metadata);
+    if (extra_metap)
+        *extra_metap = extra_meta.head;
 }
 
 void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata,
@@ -1137,88 +1161,53 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta *extra_meta)
     for (cur = extra_meta; cur; cur = cur->next) {
         ID3v2ExtraMetaAPIC *apic;
         AVStream *st;
+        int ret;
 
         if (strcmp(cur->tag, "APIC"))
             continue;
         apic = &cur->data.apic;
 
-        if (!(st = avformat_new_stream(s, NULL)))
-            return AVERROR(ENOMEM);
-
-        st->disposition      |= AV_DISPOSITION_ATTACHED_PIC;
-        st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+        ret = ff_add_attached_pic(s, NULL, NULL, &apic->buf, 0);
+        if (ret < 0)
+            return ret;
+        st  = s->streams[s->nb_streams - 1];
         st->codecpar->codec_id   = apic->id;
 
-        if (AV_RB64(apic->buf->data) == PNGSIG)
+        if (AV_RB64(st->attached_pic.data) == PNGSIG)
             st->codecpar->codec_id = AV_CODEC_ID_PNG;
 
         if (apic->description[0])
             av_dict_set(&st->metadata, "title", apic->description, 0);
 
         av_dict_set(&st->metadata, "comment", apic->type, 0);
-
-        av_init_packet(&st->attached_pic);
-        st->attached_pic.buf          = apic->buf;
-        st->attached_pic.data         = apic->buf->data;
-        st->attached_pic.size         = apic->buf->size - AV_INPUT_BUFFER_PADDING_SIZE;
-        st->attached_pic.stream_index = st->index;
-        st->attached_pic.flags       |= AV_PKT_FLAG_KEY;
-
-        apic->buf = NULL;
     }
 
     return 0;
 }
 
-int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta *extra_meta)
+int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta *cur)
 {
-    int ret = 0;
-    ID3v2ExtraMeta *cur;
     AVRational time_base = {1, 1000};
-    ID3v2ExtraMetaCHAP **chapters = NULL;
-    int num_chapters = 0;
-    int i;
+    int ret;
 
-    // since extra_meta is a linked list where elements are prepended,
-    // we need to reverse the order of chapters
-    for (cur = extra_meta; cur; cur = cur->next) {
+    for (unsigned i = 0; cur; cur = cur->next) {
         ID3v2ExtraMetaCHAP *chap;
+        AVChapter *chapter;
 
         if (strcmp(cur->tag, "CHAP"))
             continue;
-        chap = &cur->data.chap;
-
-        if ((ret = av_dynarray_add_nofree(&chapters, &num_chapters, chap)) < 0)
-            goto end;
-    }
-
-    for (i = 0; i < (num_chapters / 2); i++) {
-        ID3v2ExtraMetaCHAP *right;
-        int right_index;
-
-        right_index = (num_chapters - 1) - i;
-        right = chapters[right_index];
 
-        chapters[right_index] = chapters[i];
-        chapters[i] = right;
-    }
-
-    for (i = 0; i < num_chapters; i++) {
-        ID3v2ExtraMetaCHAP *chap;
-        AVChapter *chapter;
-
-        chap = chapters[i];
-        chapter = avpriv_new_chapter(s, i, time_base, chap->start, chap->end, chap->element_id);
+        chap = &cur->data.chap;
+        chapter = avpriv_new_chapter(s, i++, time_base, chap->start,
+                                     chap->end, chap->element_id);
         if (!chapter)
             continue;
 
         if ((ret = av_dict_copy(&chapter->metadata, chap->meta, 0)) < 0)
-            goto end;
+            return ret;
     }
 
-end:
-    av_freep(&chapters);
-    return ret;
+    return 0;
 }
 
 int ff_id3v2_parse_priv_dict(AVDictionary **metadata, ID3v2ExtraMeta *extra_meta)