From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 914AD4844F for ; Sun, 4 Feb 2024 02:29:36 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id F0B0968D150; Sun, 4 Feb 2024 04:29:25 +0200 (EET) Received: from mail-oo1-f44.google.com (mail-oo1-f44.google.com [209.85.161.44]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 21BBE68D125 for ; Sun, 4 Feb 2024 04:29:20 +0200 (EET) Received: by mail-oo1-f44.google.com with SMTP id 006d021491bc7-59a87156cb8so1487276eaf.2 for ; Sat, 03 Feb 2024 18:29:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1707013757; x=1707618557; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=DwDNG1GwCQe0TgDZ+LeFJokdO462TWJ8Om8IvHQ0Ols=; b=Rs8P7ZzhLxihLvUOhlSy1rXUNbgR1+4rrD3YhTMKW1gRsOanG46ED1/Gj4oBBKuvs2 Ok7pbDW1Qo2a2BpU7YaEYbgkeShYzAeEudTA41/Ssx4rs4eRYrjZ8fRKBQOMujx/8IYS +ctVjha9LZNcbICZyGAkway0vjjVINebyEG2TGpY/bMViSF7lD4JKbYGFlu1pQ7Sajuk jFwbgwE0d0w20KV5NXC1e8GXpWw6zmEG+nC6fvebYnc3kPtlY18IKvbVtZGFz9+V/39M TGezY83w+EzYnf5/bZI6rGd/YeYnieXKNqt9dgIP7V7/AliKC/ovGeaoeAj+oW6GwneO /ebg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1707013757; x=1707618557; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=DwDNG1GwCQe0TgDZ+LeFJokdO462TWJ8Om8IvHQ0Ols=; b=VsostXF5fopLL5a1OFHQ22Em7+xqteEimaKEVb9Ona6/rQa72mJJT24feyhVSVeH5y 6jOMwKG58ZR6llgzRVmjklNEDVOsvuWL1oB586zHoe9JUA26PVaPpa8Y5X4Kby0TeBa8 m0ALboUEqR4XL6i3Pk2fLDGwtBOXGisxpbDigSVsm5NbUTxbLfXlVAh2O7sDrAccJ0Ee Pd88WHNtfrBPVS9HWTHuKiLFSf6sFVtFuUUYDJOvzfD3vDJ94iDvHixjOCwROITZuu5E Zl5IoXjpjak8TIFxrhZjYdyA5l78sJxVs9hOfZWFNBva7N1Ks7dfaGM2uZW+h/dRkzGM iM3g== X-Gm-Message-State: AOJu0Yyf5U65VEf1r9d1LF3qyBBqrE0veUfIHAi9J4QS3HYyqYl9QYyk 3+9CNdgtKm/u4JSDc72z0D9JJPxTEvHLIkVYQI+U1n4JzX4xK/EZ+sVzzz5C X-Google-Smtp-Source: AGHT+IHsVNAlrADK5NsiZX1s/MKsJ5y9PCH5x73ZfKGCRKewk62AvPaIKll8M4zUwF+wLs3yETFFbA== X-Received: by 2002:a05:6359:4112:b0:178:7568:3b57 with SMTP id kh18-20020a056359411200b0017875683b57mr9320392rwc.30.1707013756857; Sat, 03 Feb 2024 18:29:16 -0800 (PST) Received: from localhost.localdomain (host197.190-225-105.telecom.net.ar. [190.225.105.197]) by smtp.gmail.com with ESMTPSA id k5-20020a170902e90500b001d7907eb711sm3785965pld.182.2024.02.03.18.29.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 03 Feb 2024 18:29:16 -0800 (PST) From: James Almer To: ffmpeg-devel@ffmpeg.org Date: Sat, 3 Feb 2024 23:29:28 -0300 Message-ID: <20240204022930.14007-2-jamrial@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240204022930.14007-1-jamrial@gmail.com> References: <20240204022930.14007-1-jamrial@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/3 v5] avformat/mov: add support for tile HEIF still images X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: Export each tile as its own stream, and the grid information as a Stream Group of type TILE_GRID. This also enables exporting other stream items like thumbnails, which may be present in non tiled HEIF images too. For those, the primary stream will be tagged with the default disposition. Based on a patch by Swaraj Hota Signed-off-by: James Almer --- Now supports exporting more than one grid if present, as well as the item name for the grid as stream group metadata. libavformat/avformat.h | 6 + libavformat/dump.c | 2 + libavformat/isom.h | 15 +- libavformat/mov.c | 343 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 339 insertions(+), 27 deletions(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 0b1c2e46b5..ad95306efb 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -811,6 +811,12 @@ typedef struct AVIndexEntry { * The video stream contains still images. */ #define AV_DISPOSITION_STILL_IMAGE (1 << 20) +/** + * The video stream is intended to be merged with another stream before + * presentation. + * Used for example to signal the stream contains a tile from a HEIF grid. + */ +#define AV_DISPOSITION_TILE (1 << 21) /** * @return The AV_DISPOSITION_* flag corresponding to disp or a negative error diff --git a/libavformat/dump.c b/libavformat/dump.c index c9b7369bcd..de0e1d8b39 100644 --- a/libavformat/dump.c +++ b/libavformat/dump.c @@ -640,6 +640,8 @@ static void dump_stream_format(const AVFormatContext *ic, int i, av_log(NULL, log_level, " (still image)"); if (st->disposition & AV_DISPOSITION_NON_DIEGETIC) av_log(NULL, log_level, " (non-diegetic)"); + if (st->disposition & AV_DISPOSITION_TILE) + av_log(NULL, log_level, " (tile)"); av_log(NULL, log_level, "\n"); dump_metadata(NULL, st->metadata, extra_indent, log_level); diff --git a/libavformat/isom.h b/libavformat/isom.h index 77221d06e4..cedbd237d6 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -264,15 +264,24 @@ typedef struct MOVStreamContext { typedef struct HEIFItem { AVStream *st; + char *name; int item_id; int64_t extent_length; int64_t extent_offset; - int64_t size; + int tile_rows; + int tile_cols; int width; int height; int type; + int is_idat_relative; } HEIFItem; +typedef struct HEIFGrid { + HEIFItem *item; + int16_t *tile_id_list; + int nb_tiles; +} HEIFGrid; + typedef struct MOVContext { const AVClass *class; ///< class for private options AVFormatContext *fc; @@ -336,6 +345,10 @@ typedef struct MOVContext { int cur_item_id; HEIFItem *heif_item; int nb_heif_item; + HEIFGrid *heif_grid; + int nb_heif_grid; + int thmb_item_id; + int64_t idat_offset; int interleaved_read; } MOVContext; diff --git a/libavformat/mov.c b/libavformat/mov.c index 5fae777adb..237516ed0a 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -185,6 +185,30 @@ static int mov_read_mac_string(MOVContext *c, AVIOContext *pb, int len, return p - dst; } +static AVStream *get_curr_st(MOVContext *c) +{ + AVStream *st = NULL; + + if (c->fc->nb_streams < 1) + return NULL; + + for (int i = 0; i < c->nb_heif_item; i++) { + HEIFItem *item = &c->heif_item[i]; + + if (!item->st) + continue; + if (item->st->id != c->cur_item_id) + continue; + + st = item->st; + break; + } + if (!st) + st = c->fc->streams[c->fc->nb_streams-1]; + + return st; +} + static int mov_read_covr(MOVContext *c, AVIOContext *pb, int type, int len) { AVStream *st; @@ -1767,9 +1791,9 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom) uint16_t color_primaries, color_trc, color_matrix; int ret; - if (c->fc->nb_streams < 1) + st = get_curr_st(c); + if (!st) return 0; - st = c->fc->streams[c->fc->nb_streams - 1]; ret = ffio_read_size(pb, color_parameter_type, 4); if (ret < 0) @@ -2117,9 +2141,9 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *st; int ret; - if (c->fc->nb_streams < 1) + st = get_curr_st(c); + if (!st) return 0; - st = c->fc->streams[c->fc->nb_streams-1]; if ((uint64_t)atom.size > (1<<30)) return AVERROR_INVALIDDATA; @@ -4951,12 +4975,10 @@ static int heif_add_stream(MOVContext *c, HEIFItem *item) st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; st->codecpar->codec_id = mov_codec_id(st, item->type); sc->ffindex = st->index; - c->trak_index = st->index; st->avg_frame_rate.num = st->avg_frame_rate.den = 1; st->time_base.num = st->time_base.den = 1; st->nb_frames = 1; sc->time_scale = 1; - sc = st->priv_data; sc->pb = c->fc->pb; sc->pb_is_copied = 1; @@ -7784,11 +7806,55 @@ static int mov_read_pitm(MOVContext *c, AVIOContext *pb, MOVAtom atom) return atom.size; } +static int mov_read_idat(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + c->idat_offset = avio_tell(pb); + return 0; +} + +static int read_image_grid(AVFormatContext *s, AVStreamGroupTileGrid *tile_grid, + HEIFItem *item) +{ + MOVContext *c = s->priv_data; + int64_t offset = 0, pos = avio_tell(s->pb); + uint8_t flags; + + if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) { + av_log(c->fc, AV_LOG_INFO, "grid box with non seekable input\n"); + return AVERROR_PATCHWELCOME; + } + if (item->is_idat_relative) { + if (!c->idat_offset) { + av_log(c->fc, AV_LOG_ERROR, "missing idat box required by the image grid\n"); + return AVERROR_INVALIDDATA; + } + offset = c->idat_offset; + } + + avio_seek(s->pb, item->extent_offset + offset, SEEK_SET); + + avio_r8(s->pb); /* version */ + flags = avio_r8(s->pb); + + item->tile_rows = avio_r8(s->pb) + 1; + item->tile_cols = avio_r8(s->pb) + 1; + /* actual width and height of output image */ + tile_grid->width = (flags & 1) ? avio_rb32(s->pb) : avio_rb16(s->pb); + tile_grid->height = (flags & 1) ? avio_rb32(s->pb) : avio_rb16(s->pb); + + av_log(c->fc, AV_LOG_TRACE, "grid: grid_rows %d grid_cols %d output_width %d output_height %d\n", + item->tile_rows, item->tile_cols, tile_grid->width, tile_grid->height); + + avio_seek(s->pb, pos, SEEK_SET); + + return 0; +} + static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) { int version, offset_size, length_size, base_offset_size, index_size; int item_count, extent_count; - uint64_t base_offset, extent_offset, extent_length; + int64_t base_offset, extent_offset, extent_length; uint8_t value; if (c->found_moov) { @@ -7845,6 +7911,8 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (rb_size(pb, &extent_offset, offset_size) < 0 || rb_size(pb, &extent_length, length_size) < 0) return AVERROR_INVALIDDATA; + if (offset_type == 1) + c->heif_item[i].is_idat_relative = 1; c->heif_item[i].extent_length = extent_length; c->heif_item[i].extent_offset = base_offset + extent_offset; av_log(c->fc, AV_LOG_TRACE, "iloc: item_idx %d, offset_type %d, " @@ -7859,7 +7927,7 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - char item_name[128]; + AVBPrint item_name; int64_t size = atom.size; uint32_t item_type; int item_id; @@ -7869,27 +7937,32 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb24(pb); // flags. size -= 4; - if (version != 2) { - av_log(c->fc, AV_LOG_ERROR, "infe: version != 2 not supported\n"); + if (version < 2) { + av_log(c->fc, AV_LOG_ERROR, "infe: version < 2 not supported\n"); return AVERROR_PATCHWELCOME; } - item_id = avio_rb16(pb); + item_id = version > 2 ? avio_rb32(pb) : avio_rb16(pb); avio_rb16(pb); // item_protection_index item_type = avio_rl32(pb); size -= 8; - size -= avio_get_str(pb, INT_MAX, item_name, sizeof(item_name)); - av_log(c->fc, AV_LOG_TRACE, "infe: item_id %d, item_type %s, item_name %s\n", - item_id, av_fourcc2str(item_type), item_name); + av_bprint_init(&item_name, 0, AV_BPRINT_SIZE_UNLIMITED); + ret = ff_read_string_to_bprint_overwrite(pb, &item_name, size); + if (ret < 0) { + av_bprint_finalize(&item_name, NULL); + return ret; + } - // Skip all but the primary item until support is added - if (item_id != c->primary_item_id) - return 0; + av_log(c->fc, AV_LOG_TRACE, "infe: item_id %d, item_type %s, item_name %s\n", + item_id, av_fourcc2str(item_type), item_name.str); + size -= ret + 1; if (size > 0) avio_skip(pb, size); + if (ret) + av_bprint_finalize(&item_name, &c->heif_item[c->cur_item_id].name); c->heif_item[c->cur_item_id].item_id = item_id; c->heif_item[c->cur_item_id].type = item_type; @@ -7900,9 +7973,6 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (ret < 0) return ret; break; - default: - av_log(c->fc, AV_LOG_TRACE, "infe: ignoring item_type %s\n", av_fourcc2str(item_type)); - break; } c->cur_item_id++; @@ -7959,6 +8029,81 @@ static int mov_read_iref(MOVContext *c, AVIOContext *pb, MOVAtom atom) return mov_read_default(c, pb, atom); } +static int mov_read_dimg(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + HEIFItem *item = NULL; + HEIFGrid *grid; + int entries, i; + int from_item_id = avio_rb16(pb); + + for (int i = 0; i < c->nb_heif_grid; i++) { + if (c->heif_grid[i].item->item_id == from_item_id) { + av_log(c->fc, AV_LOG_ERROR, "More than one 'dimg' box referencing the same 'grid'\n"); + return AVERROR_INVALIDDATA; + } + } + for (int i = 0; i < c->nb_heif_item; i++) { + if (c->heif_item[i].item_id != from_item_id) + continue; + item = &c->heif_item[i]; + if (item->type != MKTAG('g','r','i','d')) { + avpriv_report_missing_feature(c->fc, "Derived item of type %s", av_fourcc2str(item->type)); + return 0; + } + break; + } + if (!item) { + av_log(c->fc, AV_LOG_ERROR, "Missing grid information\n"); + return AVERROR_INVALIDDATA; + } + + grid = av_realloc_array(c->heif_grid, c->nb_heif_grid + 1U, + sizeof(*c->heif_grid)); + if (!grid) + return AVERROR(ENOMEM); + c->heif_grid = grid; + grid = &grid[c->nb_heif_grid++]; + + entries = avio_rb16(pb); + grid->tile_id_list = av_malloc_array(entries, sizeof(*grid->tile_id_list)); + if (!grid->tile_id_list) + return AVERROR(ENOMEM); + /* 'to' item ids */ + for (i = 0; i < entries; i++) + grid->tile_id_list[i] = avio_rb16(pb); + grid->nb_tiles = entries; + grid->item = item; + + av_log(c->fc, AV_LOG_TRACE, "dimg: from_item_id %d, entries %d\n", + from_item_id, entries); + + return 0; +} + +static int mov_read_thmb(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + int entries; + int to_item_id, from_item_id = avio_rb16(pb); + + entries = avio_rb16(pb); + if (entries > 1) { + avpriv_request_sample(c->fc, "More than one thmb entry"); + return AVERROR_PATCHWELCOME; + } + /* 'to' item ids */ + to_item_id = avio_rb16(pb); + + if (to_item_id != c->primary_item_id) + return 0; + + c->thmb_item_id = from_item_id; + + av_log(c->fc, AV_LOG_TRACE, "thmb: from_item_id %d, entries %d\n", + from_item_id, entries); + + return 0; +} + static int mov_read_ispe(MOVContext *c, AVIOContext *pb, MOVAtom atom) { uint32_t width, height; @@ -8079,10 +8224,6 @@ static int mov_read_iprp(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "ipma: property_index %d, item_id %d, item_type %s\n", index + 1, item_id, av_fourcc2str(ref->type)); - // Skip properties referencing items other than the primary item until support is added - if (item_id != c->primary_item_id) - continue; - c->cur_item_id = item_id; ret = mov_read_default(c, &ref->b.pub, @@ -8211,6 +8352,9 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('p','c','m','C'), mov_read_pcmc }, /* PCM configuration box */ { MKTAG('p','i','t','m'), mov_read_pitm }, { MKTAG('e','v','c','C'), mov_read_glbl }, +{ MKTAG('d','i','m','g'), mov_read_dimg }, +{ MKTAG('t','h','m','b'), mov_read_thmb }, +{ MKTAG('i','d','a','t'), mov_read_idat }, { MKTAG('i','r','e','f'), mov_read_iref }, { MKTAG('i','s','p','e'), mov_read_ispe }, { MKTAG('i','p','r','p'), mov_read_iprp }, @@ -8718,7 +8862,12 @@ static int mov_read_close(AVFormatContext *s) av_freep(&mov->aes_decrypt); av_freep(&mov->chapter_tracks); + for (i = 0; i < mov->nb_heif_item; i++) + av_freep(&mov->heif_item[i].name); av_freep(&mov->heif_item); + for (i = 0; i < mov->nb_heif_grid; i++) + av_freep(&mov->heif_grid[i].tile_id_list); + av_freep(&mov->heif_grid); return 0; } @@ -8858,6 +9007,123 @@ fail: return ret; } +static int mov_set_tile_grid_offsets(AVFormatContext *s, AVStreamGroup *stg, + const HEIFGrid *grid) +{ + AVStreamGroupTileGrid *tile_grid = stg->params.tile_grid; + int ret, x = 0, y = 0, i = 0; + + tile_grid->offsets = av_calloc(grid->nb_tiles, sizeof(*tile_grid->offsets)); + if (!tile_grid->offsets) + return AVERROR(ENOMEM); + + while (y < tile_grid->coded_height) { + int left_col = i; + + while (x < tile_grid->coded_width) { + if (i == grid->nb_tiles) { + ret = AVERROR(EINVAL); + goto fail; + } + + tile_grid->offsets[i].x = x; + tile_grid->offsets[i].y = y; + + x += stg->streams[i++]->codecpar->width; + } + + if (x > tile_grid->coded_width) { + avpriv_request_sample(s, "Non uniform HEIF tiles"); + ret = AVERROR_PATCHWELCOME; + goto fail; + } + + x = 0; + y += stg->streams[left_col]->codecpar->height; + } + + if (y > tile_grid->coded_height || i != grid->nb_tiles) { + avpriv_request_sample(s, "Non uniform HEIF tiles"); + ret = AVERROR_PATCHWELCOME; + goto fail; + } + + return 0; +fail: + av_freep(&tile_grid->offsets); + + return ret; +} + +static int mov_parse_tiles(AVFormatContext *s) +{ + MOVContext *mov = s->priv_data; + int err; + + for (int i = 0; i < mov->nb_heif_grid; i++) { + AVStreamGroup *stg = avformat_stream_group_create(s, AV_STREAM_GROUP_PARAMS_TILE_GRID, NULL); + AVStreamGroupTileGrid *tile_grid; + HEIFGrid *grid = &mov->heif_grid[i]; + int coded_width = 0, coded_height = 0; + int size; + + if (!stg) + return AVERROR(ENOMEM); + + tile_grid = stg->params.tile_grid; + err = read_image_grid(s, tile_grid, grid->item); + if (err < 0) + return err; + + for (int j = 0; j < grid->nb_tiles; j++) { + int tile_id = grid->tile_id_list[j]; + + for (int k = 0; k < mov->nb_heif_item; k++) { + const HEIFItem *item = &mov->heif_item[k]; + AVStream *st = item->st; + + if (item->item_id != tile_id) + continue; + if (!st) { + av_log(s, AV_LOG_ERROR, "HEIF tile %d doesn't reference a stream\n", tile_id); + return AVERROR_INVALIDDATA; + } + + st->codecpar->width = item->width; + st->codecpar->height = item->height; + + err = avformat_stream_group_add_stream(stg, st); + if (err == AVERROR(EEXIST)) + return AVERROR_INVALIDDATA; + else if (err < 0) + return err; + + st->disposition |= AV_DISPOSITION_TILE; + break; + } + } + + size = grid->item->tile_rows * grid->item->tile_cols; + for (int i = 0; i < grid->item->tile_cols; i++) + coded_width += stg->streams[i]->codecpar->width; + for (int i = 0; i < size; i += grid->item->tile_cols) + coded_height += stg->streams[i]->codecpar->height; + + tile_grid->coded_width = coded_width; + tile_grid->coded_height = coded_height; + + err = mov_set_tile_grid_offsets(s, stg, grid); + if (err < 0) + return AVERROR_INVALIDDATA; + + if (grid->item->name) + av_dict_set(&stg->metadata, "title", grid->item->name, 0); + } + + + return 0; +} + static int mov_read_header(AVFormatContext *s) { MOVContext *mov = s->priv_data; @@ -8874,6 +9140,8 @@ static int mov_read_header(AVFormatContext *s) mov->fc = s; mov->trak_index = -1; + mov->thmb_item_id = -1; + mov->primary_item_id = -1; /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ if (pb->seekable & AVIO_SEEKABLE_NORMAL) atom.size = avio_size(pb); @@ -8896,20 +9164,43 @@ static int mov_read_header(AVFormatContext *s) av_log(mov->fc, AV_LOG_TRACE, "on_parse_exit_offset=%"PRId64"\n", avio_tell(pb)); if (mov->found_iloc) { + if (mov->nb_heif_grid) { + err = mov_parse_tiles(s); + if (err < 0) + return err; + } + for (i = 0; i < mov->nb_heif_item; i++) { HEIFItem *item = &mov->heif_item[i]; MOVStreamContext *sc; AVStream *st; + int64_t offset = 0; - if (!item->st) + if (!item->st) { + if (item->item_id == mov->thmb_item_id) { + av_log(s, AV_LOG_ERROR, "HEIF thumbnail doesn't reference a stream\n"); + return AVERROR_INVALIDDATA; + } continue; + } + if (item->is_idat_relative) { + if (!mov->idat_offset) { + av_log(s, AV_LOG_ERROR, "Missing idat box for item %d\n", item->item_id); + return AVERROR_INVALIDDATA; + } + offset = mov->idat_offset; + } st = item->st; sc = st->priv_data; st->codecpar->width = item->width; st->codecpar->height = item->height; + sc->sample_sizes[0] = item->extent_length; - sc->chunk_offsets[0] = item->extent_offset; + sc->chunk_offsets[0] = item->extent_offset + offset; + + if (item->item_id == mov->primary_item_id) + st->disposition |= AV_DISPOSITION_DEFAULT; mov_build_index(mov, st); } -- 2.43.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".