diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c index a0aa112a8a..ea3203df36 100644 --- a/libavformat/aacdec.c +++ b/libavformat/aacdec.c @@ -136,7 +136,7 @@ static int handle_id3(AVFormatContext *s, AVPacket *pkt) { AVDictionary *metadata = NULL; AVIOContext ioctx; - ID3v2ExtraMeta *id3v2_extra_meta = NULL; + ID3v2ExtraMeta *id3v2_extra_meta; int ret; ret = av_append_packet(s->pb, pkt, ff_id3v2_tag_len(pkt->data) - pkt->size); diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c index dcaf1560b6..1b693b71a3 100644 --- a/libavformat/aiffdec.c +++ b/libavformat/aiffdec.c @@ -212,7 +212,7 @@ static int aiff_read_header(AVFormatContext *s) AVIOContext *pb = s->pb; AVStream * st; AIFFInputContext *aiff = s->priv_data; - ID3v2ExtraMeta *id3v2_extra_meta = NULL; + ID3v2ExtraMeta *id3v2_extra_meta; /* check FORM header */ filesize = get_tag(pb, &tag); diff --git a/libavformat/asf.c b/libavformat/asf.c index cef0f9f646..1ac8b5f078 100644 --- a/libavformat/asf.c +++ b/libavformat/asf.c @@ -255,7 +255,7 @@ fail: static int get_id3_tag(AVFormatContext *s, int len) { - ID3v2ExtraMeta *id3v2_extra_meta = NULL; + ID3v2ExtraMeta *id3v2_extra_meta; ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, len); if (id3v2_extra_meta) { diff --git a/libavformat/dsfdec.c b/libavformat/dsfdec.c index 1df163e114..2fca25ef32 100644 --- a/libavformat/dsfdec.c +++ b/libavformat/dsfdec.c @@ -50,7 +50,7 @@ static const uint64_t dsf_channel_layout[] = { static void read_id3(AVFormatContext *s, uint64_t id3pos) { - ID3v2ExtraMeta *id3v2_extra_meta = NULL; + ID3v2ExtraMeta *id3v2_extra_meta; if (avio_seek(s->pb, id3pos, SEEK_SET) < 0) return; diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 863709abbf..e0fef08789 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -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}; @@ -654,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; @@ -677,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]; @@ -721,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; @@ -739,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; @@ -763,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; @@ -777,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; @@ -811,7 +819,7 @@ 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; @@ -1063,13 +1071,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; @@ -1096,7 +1108,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); } @@ -1105,6 +1118,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, @@ -1166,55 +1181,29 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta *extra_meta) 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) { - ID3v2ExtraMetaCHAP *chap; - - 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++) { + for (unsigned i = 0; cur; cur = cur->next) { ID3v2ExtraMetaCHAP *chap; AVChapter *chapter; - chap = chapters[i]; - chapter = avpriv_new_chapter(s, i, time_base, chap->start, chap->end, chap->element_id); + if (strcmp(cur->tag, "CHAP")) + continue; + + 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) diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index a41fb271a4..9afa5a2ddc 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -111,7 +111,7 @@ int ff_id3v2_tag_len(const uint8_t *buf); * Read an ID3v2 tag into specified dictionary and retrieve supported extra metadata. * * @param metadata Parsed metadata is stored here - * @param extra_meta If not NULL, extra metadata is parsed into a list of + * @param[out] extra_meta If not NULL, extra metadata is parsed into a list of * ID3v2ExtraMeta structs and *extra_meta points to the head of the list */ void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, const char *magic, ID3v2ExtraMeta **extra_meta); @@ -121,7 +121,7 @@ void ff_id3v2_read_dict(AVIOContext *pb, AVDictionary **metadata, const char *ma * * Data is read from and stored to AVFormatContext. * - * @param extra_meta If not NULL, extra metadata is parsed into a list of + * @param[out] extra_meta If not NULL, extra metadata is parsed into a list of * ID3v2ExtraMeta structs and *extra_meta points to the head of the list * @param[opt] max_search_search restrict ID3 magic number search (bytes from start) */ diff --git a/libavformat/iff.c b/libavformat/iff.c index b07b6c8b18..27b5581cc3 100644 --- a/libavformat/iff.c +++ b/libavformat/iff.c @@ -315,7 +315,6 @@ static int parse_dsd_prop(AVFormatContext *s, AVStream *st, uint64_t eof) break; case MKTAG('I','D','3',' '): - id3v2_extra_meta = NULL; ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta, size); if (id3v2_extra_meta) { if ((ret = ff_id3v2_parse_apic(s, id3v2_extra_meta)) < 0 || diff --git a/libavformat/omadec.c b/libavformat/omadec.c index d31b475fd2..74b32db96d 100644 --- a/libavformat/omadec.c +++ b/libavformat/omadec.c @@ -413,7 +413,7 @@ static int oma_read_header(AVFormatContext *s) uint8_t buf[EA3_HEADER_SIZE]; uint8_t *edata; AVStream *st; - ID3v2ExtraMeta *extra_meta = NULL; + ID3v2ExtraMeta *extra_meta; OMAContext *oc = s->priv_data; ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta, 0); diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c index 8214ab8498..aca9a8382b 100644 --- a/libavformat/wavdec.c +++ b/libavformat/wavdec.c @@ -549,7 +549,7 @@ static int wav_read_header(AVFormatContext *s) break; case MKTAG('I', 'D', '3', ' '): case MKTAG('i', 'd', '3', ' '): { - ID3v2ExtraMeta *id3v2_extra_meta = NULL; + ID3v2ExtraMeta *id3v2_extra_meta; ff_id3v2_read_dict(pb, &s->internal->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); if (id3v2_extra_meta) { ff_id3v2_parse_apic(s, id3v2_extra_meta); diff --git a/tests/ref/fate/cover-art-aiff-id3v2-remux b/tests/ref/fate/cover-art-aiff-id3v2-remux index 207721fc71..c294c5013e 100644 --- a/tests/ref/fate/cover-art-aiff-id3v2-remux +++ b/tests/ref/fate/cover-art-aiff-id3v2-remux @@ -8,29 +8,29 @@ d4a9481090a8bab1a3f072a8108a1d6a *tests/data/fate/cover-art-aiff-id3v2-remux.aif #channel_layout_name 0: stereo #tb 1: 1/90000 #media_type 1: video -#codec_id 1: bmp +#codec_id 1: mjpeg #dimensions 1: 350x350 -#sar 1: 0/1 +#sar 1: 1/1 #tb 2: 1/90000 #media_type 2: video -#codec_id 2: png +#codec_id 2: mjpeg #dimensions 2: 350x350 #sar 2: 1/1 #tb 3: 1/90000 #media_type 3: video -#codec_id 3: mjpeg +#codec_id 3: png #dimensions 3: 350x350 #sar 3: 1/1 #tb 4: 1/90000 #media_type 4: video -#codec_id 4: mjpeg +#codec_id 4: bmp #dimensions 4: 350x350 -#sar 4: 1/1 +#sar 4: 0/1 0, 0, 0, 1024, 4096, 0xdac4695d -1, 0, 0, 0, 368254, 0xfa7f4bd8 -2, 0, 0, 0, 184497, 0xc33f8d44 -3, 0, 0, 0, 19650, 0xd5662610 -4, 0, 0, 0, 19650, 0xd5662610 +1, 0, 0, 0, 19650, 0xd5662610 +2, 0, 0, 0, 19650, 0xd5662610 +3, 0, 0, 0, 184497, 0xc33f8d44 +4, 0, 0, 0, 368254, 0xfa7f4bd8 0, 1024, 1024, 1024, 4096, 0xad05c909 0, 2048, 2048, 1024, 4096, 0x97e3b8f8 0, 3072, 3072, 1024, 4096, 0xb08180fa @@ -41,31 +41,31 @@ DISPOSITION:attached_pic=0 [/STREAM] [STREAM] index=1 -codec_name=bmp +codec_name=mjpeg DISPOSITION:attached_pic=1 -TAG:title=third -TAG:comment=Conductor +TAG:title=first +TAG:comment=Other [/STREAM] [STREAM] index=2 -codec_name=png -DISPOSITION:attached_pic=1 -TAG:title=second -TAG:comment=Illustration -[/STREAM] -[STREAM] -index=3 codec_name=mjpeg DISPOSITION:attached_pic=1 TAG:title=fourth TAG:comment=Composer [/STREAM] [STREAM] -index=4 -codec_name=mjpeg +index=3 +codec_name=png DISPOSITION:attached_pic=1 -TAG:title=first -TAG:comment=Other +TAG:title=second +TAG:comment=Illustration +[/STREAM] +[STREAM] +index=4 +codec_name=bmp +DISPOSITION:attached_pic=1 +TAG:title=third +TAG:comment=Conductor [/STREAM] [FORMAT] TAG:artist=Мельница diff --git a/tests/ref/fate/cover-art-mp3-id3v2-remux b/tests/ref/fate/cover-art-mp3-id3v2-remux index a3bc8c7891..713ca9e951 100644 --- a/tests/ref/fate/cover-art-mp3-id3v2-remux +++ b/tests/ref/fate/cover-art-mp3-id3v2-remux @@ -8,9 +8,9 @@ c1b55a9a92226cd72d3f53ccd830d127 *tests/data/fate/cover-art-mp3-id3v2-remux.mp3 #channel_layout_name 0: stereo #tb 1: 1/90000 #media_type 1: video -#codec_id 1: png +#codec_id 1: mjpeg #dimensions 1: 263x263 -#sar 1: 1/1 +#sar 1: 96/96 #tb 2: 1/90000 #media_type 2: video #codec_id 2: bmp @@ -18,13 +18,13 @@ c1b55a9a92226cd72d3f53ccd830d127 *tests/data/fate/cover-art-mp3-id3v2-remux.mp3 #sar 2: 0/1 #tb 3: 1/90000 #media_type 3: video -#codec_id 3: mjpeg +#codec_id 3: png #dimensions 3: 263x263 -#sar 3: 96/96 +#sar 3: 1/1 0, -353590, -353590, 368640, 417, 0x15848290, S=1, 10, 0x034e0055 -1, 0, 0, 0, 165671, 0x7c1c8070 +1, 0, 0, 0, 15760, 0x71d5c418 2, 0, 0, 0, 208350, 0x291b44d1 -3, 0, 0, 0, 15760, 0x71d5c418 +3, 0, 0, 0, 165671, 0x7c1c8070 0, 15050, 15050, 368640, 418, 0x46f684a4 0, 383690, 383690, 368640, 418, 0x46f684a4 0, 752330, 752330, 368640, 418, 0x46f684a4 @@ -37,7 +37,7 @@ TAG:encoder=Lavf [/STREAM] [STREAM] index=1 -codec_name=png +codec_name=mjpeg DISPOSITION:attached_pic=1 TAG:comment=Other [/STREAM] @@ -49,7 +49,7 @@ TAG:comment=Band/Orchestra [/STREAM] [STREAM] index=3 -codec_name=mjpeg +codec_name=png DISPOSITION:attached_pic=1 TAG:comment=Other [/STREAM] diff --git a/tests/ref/fate/id3v2-priv b/tests/ref/fate/id3v2-priv index 965c8695e8..8448495325 100644 --- a/tests/ref/fate/id3v2-priv +++ b/tests/ref/fate/id3v2-priv @@ -1,5 +1,5 @@ [FORMAT] TAG:title=id3v2-test -TAG:id3v2_priv.testowner=testdata TAG:id3v2_priv.testowner2=\x00\x01\x02 +TAG:id3v2_priv.testowner=testdata [/FORMAT] diff --git a/tests/ref/fate/id3v2-priv-remux b/tests/ref/fate/id3v2-priv-remux index 0fdd5d9d0a..6a8b58f27e 100644 --- a/tests/ref/fate/id3v2-priv-remux +++ b/tests/ref/fate/id3v2-priv-remux @@ -1,4 +1,4 @@ -3e99254aa892a9578ce31da17b012a44 *tests/data/fate/id3v2-priv-remux.mp3 +bb2816e3a05ce136e9ac14479c1ebe24 *tests/data/fate/id3v2-priv-remux.mp3 8542 tests/data/fate/id3v2-priv-remux.mp3 #tb 0: 1/14112000 #media_type 0: audio