Prevents ffmpeg/ffprobe from erroring out when reading an HEIF that contains multiple hvcC thumbnails (e.g. from a Nikon Z6III camera). Before, move_read_iref_thmb() would always override the stored thmb_item_id in the MOVContext with each new read thumbnail, causing a stream and item_id mismatch later in mov_parse_heif_items(), resulting in the "HEIF thumbnail doesn't reference a stream" error message. To solve this, - Turn thmb_item_id into an array of IDs because multiple thumbnails can exist - Change check in mov_parse_heif_items() to compare against all stored thumbnail IDs to see if any item missing a stream is in the list of thumbnail IDs.
Unified · Split
| @@ -376,7 +376,8 @@ typedef struct MOVContext { · 375 unmodified lines | ||
| 376 | 376 | int nb_heif_item; |
| 377 | 377 | HEIFGrid *heif_grid; |
| 378 | 378 | int nb_heif_grid; |
| 379 | − int thmb_item_id; | |
| 379 | + int* thmb_item_id; | |
| 380 | + int nb_thmb_item; | |
| 380 | 381 | int64_t idat_offset; |
| 381 | 382 | int interleaved_read; |
| 382 | 383 | } MOVContext; |
| @@ -8972,6 +8972,7 @@ static int mov_read_iref_dimg(MOVContext *c, AVIOContext *pb, int version) · 8971 unmodified lines | ||
| 8972 | 8972 | |
| 8973 | 8973 | static int mov_read_iref_thmb(MOVContext *c, AVIOContext *pb, int version) |
| 8974 | 8974 | { |
| 8975 | + int *thmb_item_id; | |
| 8975 | 8976 | int entries; |
| 8976 | 8977 | int to_item_id, from_item_id = version ? avio_rb32(pb) : avio_rb16(pb); |
| 8977 | 8978 | |
| @@ -8986,10 +8987,15 @@ static int mov_read_iref_thmb(MOVContext *c, AVIOContext *pb, int version) · 8 unmodified lines | ||
| 8986 | 8987 | if (to_item_id != c->primary_item_id) |
| 8987 | 8988 | return 0; |
| 8988 | 8989 | |
| 8989 | − c->thmb_item_id = from_item_id; | |
| 8990 | + /* Put thumnbail IDs into an array */ | |
| 8991 | + thmb_item_id = av_dynarray2_add((void **)&c->thmb_item_id, &c->nb_thmb_item, | |
| 8992 | + sizeof(*c->thmb_item_id), | |
| 8993 | + (const void *)&from_item_id); | |
| 8994 | + if (!thmb_item_id) | |
| 8995 | + return AVERROR(ENOMEM); | |
| 8990 | 8996 | |
| 8991 | − av_log(c->fc, AV_LOG_TRACE, "thmb: from_item_id %d, entries %d\n", | |
| 8992 | − from_item_id, entries); | |
| 8997 | + av_log(c->fc, AV_LOG_TRACE, "thmb: from_item_id %d, entries %d, nb_thmb: %d\n", | |
| 8998 | + from_item_id, entries, c->nb_thmb_item); | |
| 8993 | 8999 | |
| 8994 | 9000 | return 0; |
| 8995 | 9001 | } |
| @@ -9859,6 +9865,7 @@ static int mov_read_close(AVFormatContext *s) · 863 unmodified lines | ||
| 9859 | 9865 | av_freep(&mov->heif_grid[i].tile_item_list); |
| 9860 | 9866 | } |
| 9861 | 9867 | av_freep(&mov->heif_grid); |
| 9868 | + av_freep(&mov->thmb_item_id); | |
| 9862 | 9869 | |
| 9863 | 9870 | return 0; |
| 9864 | 9871 | } |
| @@ -10323,9 +10330,12 @@ static int mov_parse_heif_items(AVFormatContext *s) · 458 unmodified lines | ||
| 10323 | 10330 | if (!item) |
| 10324 | 10331 | continue; |
| 10325 | 10332 | if (!item->st) { |
| 10326 | − if (item->item_id == mov->thmb_item_id) { | |
| 10327 | − av_log(s, AV_LOG_ERROR, "HEIF thumbnail doesn't reference a stream\n"); | |
| 10328 | − return AVERROR_INVALIDDATA; | |
| 10333 | + for (int j = 0; j < mov->nb_thmb_item; j++) { | |
| 10334 | + if (item->item_id == mov->thmb_item_id[j]) { | |
| 10335 | + av_log(s, AV_LOG_ERROR, "HEIF thumbnail ID %d doesn't reference a stream\n", | |
| 10336 | + item->item_id); | |
| 10337 | + return AVERROR_INVALIDDATA; | |
| 10338 | + } | |
| 10329 | 10339 | } |
| 10330 | 10340 | continue; |
| 10331 | 10341 | } |
| @@ -10476,7 +10486,7 @@ static int mov_read_header(AVFormatContext *s) · 144 unmodified lines | ||
| 10476 | 10486 | |
| 10477 | 10487 | mov->fc = s; |
| 10478 | 10488 | mov->trak_index = -1; |
| 10479 | − mov->thmb_item_id = -1; | |
| 10489 | + mov->thmb_item_id = NULL; | |
| 10480 | 10490 | mov->primary_item_id = -1; |
| 10481 | 10491 | mov->cur_item_id = -1; |
| 10482 | 10492 | /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ |