Parse iinf boxes and its child infe boxes to get the actual codec used (AV1 for avif, HEVC for heic), and properly export extradata in a generic way.
The avif tests reference files are updated as the extradata is now exported. Signed-off-by: James Almer <jamr...@gmail.com> --- libavformat/isom.h | 3 +- libavformat/mov.c | 157 ++++++++++-------- .../fate/mov-avif-demux-still-image-1-item | 2 +- .../mov-avif-demux-still-image-multiple-items | 2 +- 4 files changed, 95 insertions(+), 69 deletions(-) diff --git a/libavformat/isom.h b/libavformat/isom.h index 90c4fb5530..107e2ce9bb 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -268,6 +268,7 @@ typedef struct MOVContext { int time_scale; int64_t duration; ///< duration of the longest track int found_moov; ///< 'moov' atom has been found + int found_iloc; ///< 'iloc' atom has been found int found_mdat; ///< 'mdat' atom has been found int found_hdlr_mdta; ///< 'hdlr' atom with type 'mdta' has been found int trak_index; ///< Index of the current 'trak' @@ -327,8 +328,6 @@ typedef struct MOVContext { int64_t extent_offset; } *heif_info; int heif_info_size; - int64_t hvcC_offset; - int hvcC_size; int interleaved_read; } MOVContext; diff --git a/libavformat/mov.c b/libavformat/mov.c index 12e82c66a9..47d0d41214 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -1233,8 +1233,6 @@ static int mov_read_ftyp(MOVContext *c, AVIOContext *pb, MOVAtom atom) c->isom = 1; av_log(c->fc, AV_LOG_DEBUG, "ISO: File Type Major Brand: %.4s\n",(char *)&type); av_dict_set(&c->fc->metadata, "major_brand", type, 0); - c->is_still_picture_avif = !strncmp(type, "avif", 4) || - !strncmp(type, "mif1", 4); minor_ver = avio_rb32(pb); /* minor version */ av_dict_set_int(&c->fc->metadata, "minor_version", minor_ver, 0); @@ -4641,10 +4639,6 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) MOVStreamContext *sc; int ret; - if (c->is_still_picture_avif) { - return AVERROR_INVALIDDATA; - } - st = avformat_new_stream(c->fc, NULL); if (!st) return AVERROR(ENOMEM); st->id = -1; @@ -4916,7 +4910,7 @@ static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom) return ret; } -static int heif_add_stream(MOVContext *c, int item_id) +static int heif_add_stream(MOVContext *c, int item_id, uint32_t item_type) { MOVStreamContext *sc; AVStream *st; @@ -4940,20 +4934,7 @@ static int heif_add_stream(MOVContext *c, int item_id) st->priv_data = sc; st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - st->codecpar->codec_id = AV_CODEC_ID_AV1; - if (c->hvcC_offset >= 0) { - int ret; - int64_t pos = avio_tell(c->fc->pb); - st->codecpar->codec_id = AV_CODEC_ID_HEVC; - if (avio_seek(c->fc->pb, c->hvcC_offset, SEEK_SET) != c->hvcC_offset) { - av_log(c->fc, AV_LOG_ERROR, "Failed to seek to hvcC data.\n"); - return AVERROR_UNKNOWN; - } - ret = ff_get_extradata(c->fc, st->codecpar, c->fc->pb, c->hvcC_size); - if (ret < 0) - return ret; - avio_seek(c->fc->pb, pos, SEEK_SET); - } + 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; @@ -4996,8 +4977,6 @@ static int heif_add_stream(MOVContext *c, int item_id) static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - c->hvcC_offset = -1; - c->hvcC_size = 0; while (atom.size > 8) { uint32_t tag; if (avio_feof(pb)) @@ -5005,23 +4984,9 @@ static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom) tag = avio_rl32(pb); atom.size -= 4; if (tag == MKTAG('h','d','l','r')) { - int ret; avio_seek(pb, -8, SEEK_CUR); atom.size += 8; - if ((ret = mov_read_default(c, pb, atom)) < 0) - return ret; - if (c->is_still_picture_avif) { - int ret; - // Add a stream for the YUV planes (primary item). - if ((ret = heif_add_stream(c, c->primary_item_id)) < 0) - return ret; - // For still AVIF images, the meta box contains all the - // necessary information that would generally be provided by the - // moov box. So simply mark that we have found the moov box so - // that parsing can continue. - c->found_moov = 1; - } - return ret; + return mov_read_default(c, pb, atom); } } return 0; @@ -7813,18 +7778,10 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) uint64_t base_offset, extent_offset, extent_length; uint8_t value; - if (!c->is_still_picture_avif) { - // * For non-avif, we simply ignore the iloc box. - // * For animated avif, we don't care about the iloc box as all the - // necessary information can be found in the moov box. - return 0; - } - - if (c->heif_info) { + if (c->found_iloc) { av_log(c->fc, AV_LOG_INFO, "Duplicate iloc box found\n"); return 0; } - av_assert0(!c->fc->nb_streams); version = avio_r8(pb); avio_rb24(pb); // flags. @@ -7872,29 +7829,98 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } + c->found_iloc = 1; return atom.size; } -static int mov_read_iprp(MOVContext *c, AVIOContext *pb, MOVAtom atom) +static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - int size = avio_rb32(pb); - if (avio_rl32(pb) != MKTAG('i','p','c','o')) - return AVERROR_INVALIDDATA; + char item_name[128]; + int64_t size = atom.size; + uint32_t item_type; + int item_id; + int version, ret; + + version = avio_r8(pb); + avio_rb24(pb); // flags. + size -= 4; + + if (version != 2) { + av_log(c->fc, AV_LOG_ERROR, "infe: version != 2 not supported.\n"); + return AVERROR_PATCHWELCOME; + } + + item_id = avio_rb16(pb); + avio_rb16(pb); // item_protection_index + item_type = avio_rl32(pb); size -= 8; - while (size > 0) { - int sub_size, sub_type; - sub_size = avio_rb32(pb); - sub_type = avio_rl32(pb); - sub_size -= 8; - size -= sub_size + 8; - if (sub_type == MKTAG('h','v','c','C')) { - c->hvcC_offset = avio_tell(pb); - c->hvcC_size = sub_size; - break; + size -= avio_get_str(pb, INT_MAX, item_name, sizeof(item_name)); + + // Skip all but the primary item until support is added + if (item_id != c->primary_item_id) + return 0; + + if (size > 0) + avio_skip(pb, size); + + switch (item_type) { + case MKTAG('a','v','0','1'): + case MKTAG('h','v','c','1'): + if (!c->heif_info) { + av_log(c->fc, AV_LOG_ERROR, "Missing iloc before iinf\n"); + return AVERROR_INVALIDDATA; } - avio_skip(pb, sub_size); + ret = heif_add_stream(c, item_id, item_type); + if (ret < 0) + return ret; + break; + default: + av_log(c->fc, AV_LOG_DEBUG, "infe: ignoring item_type %s.\n", av_fourcc2str(item_type)); + break; } - return atom.size; + + return 0; +} + +static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + int entry_count; + int version, ret; + + version = avio_r8(pb); + avio_rb24(pb); // flags. + entry_count = version ? avio_rb32(pb) : avio_rb16(pb); + + for (int i = 0; i < entry_count; i++) { + MOVAtom infe; + + infe.size = avio_rb32(pb) - 8; + infe.type = avio_rl32(pb); + ret = mov_read_infe(c, pb, infe); + if (ret < 0) + return ret; + } + + return 0; +} + +static int mov_read_iprp(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + MOVAtom ipco; + int ret; + + ipco.size = avio_rb32(pb) - 8; + ipco.type = avio_rl32(pb); + if (ipco.type != MKTAG('i','p','c','o')) + return AVERROR_INVALIDDATA; + if (avio_feof(pb)) + return AVERROR_INVALIDDATA; + + ret = mov_read_default(c, pb, ipco); + if (ret < 0) + return ret; + + return 0; } static const MOVParseTableEntry mov_default_parse_table[] = { @@ -8005,6 +8031,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('p','i','t','m'), mov_read_pitm }, { MKTAG('e','v','c','C'), mov_read_glbl }, { MKTAG('i','p','r','p'), mov_read_iprp }, +{ MKTAG('i','i','n','f'), mov_read_iinf }, { 0, NULL } }; @@ -8672,8 +8699,8 @@ static int mov_read_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "error reading header\n"); return err; } - } while ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mov->found_moov && !mov->moov_retry++); - if (!mov->found_moov) { + } while ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mov->found_moov && !mov->found_iloc && !mov->moov_retry++); + if (!mov->found_moov && !mov->found_iloc) { av_log(s, AV_LOG_ERROR, "moov atom not found\n"); return AVERROR_INVALIDDATA; } diff --git a/tests/ref/fate/mov-avif-demux-still-image-1-item b/tests/ref/fate/mov-avif-demux-still-image-1-item index 93773afd4e..770c98f868 100644 --- a/tests/ref/fate/mov-avif-demux-still-image-1-item +++ b/tests/ref/fate/mov-avif-demux-still-image-1-item @@ -1,7 +1,7 @@ #format: frame checksums #version: 2 #hash: MD5 -#extradata 0, 13, b52ae298d37128862ef1918cf916239c +#extradata 0, 4, b24b71499a8480fa4469bcbcba2140aa #tb 0: 1/1 #media_type 0: video #codec_id 0: av1 diff --git a/tests/ref/fate/mov-avif-demux-still-image-multiple-items b/tests/ref/fate/mov-avif-demux-still-image-multiple-items index 93773afd4e..770c98f868 100644 --- a/tests/ref/fate/mov-avif-demux-still-image-multiple-items +++ b/tests/ref/fate/mov-avif-demux-still-image-multiple-items @@ -1,7 +1,7 @@ #format: frame checksums #version: 2 #hash: MD5 -#extradata 0, 13, b52ae298d37128862ef1918cf916239c +#extradata 0, 4, b24b71499a8480fa4469bcbcba2140aa #tb 0: 1/1 #media_type 0: video #codec_id 0: av1 -- 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-requ...@ffmpeg.org with subject "unsubscribe".