Skip to content

Commit

Permalink
Redesign AVIF_DECODER_SOURCE_AUTO to honor the FileTypeBox's major brand
Browse files Browse the repository at this point in the history
When using AVIF_DECODER_SOURCE_AUTO, use the major_brand field in the FileTypeBox ('ftyp') in the
beginning of the file as a hint to whether or not to treat this file as an AVIF sequence or an
items-based single image.

In practice (and currently in the field), this won't change pre-existing behavior as the vast
majority of AVIFs in existence right now are single images and signal the major brand 'avif'
anyway, and sequences generated by avifenc have always used the major brand 'avis'.

This design is more in the spirit of ISO-BMFF Section 4.3's explanation of major_brand:

    Files would normally be externally identified (e.g. with a file extension or mime type) that
    identifies the ‘best use’ (major brand), or the brand that the author believes will provide the
    greatest compatibility.

This also would allow for currently unexercised use-cases such as "live photos", where an AVIF can
internally hold an image sequence recorded by a camera, but suggest (via the major brand) to only
display it as a single image, specifying one of the frame samples as an item.
  • Loading branch information
Joe Drago authored and joedrago committed Sep 23, 2021
1 parent a4b47bb commit f131b78
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 2 deletions.
4 changes: 3 additions & 1 deletion include/avif/avif.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,9 @@ struct avifDecoderData;

typedef enum avifDecoderSource
{
// If a moov box is present in the .avif(s), use the tracks in it, otherwise decode the primary item.
// Honor the major brand signaled in the beginning of the file to pick between an AVIF sequence
// ('avis', tracks-based) or a single image ('avif', item-based). If the major brand is neither
// of these, prefer the AVIF sequence ('avis', tracks-based), if present.
AVIF_DECODER_SOURCE_AUTO = 0,

// Use the primary item and the aux (alpha) item in the avif(s).
Expand Down
9 changes: 8 additions & 1 deletion src/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,7 @@ typedef struct avifDecoderData
avifImageGrid colorGrid;
avifImageGrid alphaGrid;
avifDecoderSource source;
uint8_t majorBrand[4]; // From the file's ftyp, used by AVIF_DECODER_SOURCE_AUTO
avifDiagnostics * diag; // Shallow copy; owned by avifDecoder
const avifSampleTable * sourceSampleTable; // NULL unless (source == AVIF_DECODER_SOURCE_TRACKS), owned by an avifTrack
avifBool cicpSet; // True if avifDecoder's image has had its CICP set correctly yet.
Expand Down Expand Up @@ -2761,6 +2762,7 @@ static avifResult avifParse(avifDecoder * decoder)
return AVIF_RESULT_INVALID_FTYP;
}
ftypSeen = AVIF_TRUE;
memcpy(data->majorBrand, ftyp.majorBrand, 4); // Remember the major brand for future AVIF_DECODER_SOURCE_AUTO decisions
needsMeta = avifFileTypeHasBrand(&ftyp, "avif");
needsMoov = avifFileTypeHasBrand(&ftyp, "avis");
} else if (!memcmp(header.type, "meta", 4)) {
Expand Down Expand Up @@ -3146,7 +3148,12 @@ avifResult avifDecoderReset(avifDecoder * decoder)

data->sourceSampleTable = NULL; // Reset
if (decoder->requestedSource == AVIF_DECODER_SOURCE_AUTO) {
if (data->tracks.count > 0) {
// Honor the major brand (avif or avis) if present, otherwise prefer avis (tracks) if possible.
if (!memcmp(data->majorBrand, "avis", 4)) {
data->source = AVIF_DECODER_SOURCE_TRACKS;
} else if (!memcmp(data->majorBrand, "avif", 4)) {
data->source = AVIF_DECODER_SOURCE_PRIMARY_ITEM;
} else if (data->tracks.count > 0) {
data->source = AVIF_DECODER_SOURCE_TRACKS;
} else {
data->source = AVIF_DECODER_SOURCE_PRIMARY_ITEM;
Expand Down

0 comments on commit f131b78

Please sign in to comment.