@@ -75,7 +75,7 @@ static const char * avifGetConfigurationPropertyName(avifCodecType codecType)
7575typedef struct avifFileType
7676{
7777 uint8_t majorBrand [4 ];
78- uint32_t minorVersion ;
78+ uint8_t minorVersion [ 4 ] ;
7979 // If not null, points to a memory block of 4 * compatibleBrandsCount bytes.
8080 const uint8_t * compatibleBrands ;
8181 int compatibleBrandsCount ;
@@ -2254,6 +2254,8 @@ static avifBool avifParseContentLightLevelInformationBox(avifProperty * prop, co
22542254// See https://aomediacodec.github.io/av1-isobmff/v1.2.0.html#av1codecconfigurationbox-syntax.
22552255static avifBool avifParseCodecConfiguration (avifROStream * s , avifCodecConfigurationBox * config , const char * configPropName , avifDiagnostics * diag )
22562256{
2257+ const size_t av1COffset = s -> offset ;
2258+
22572259 uint32_t marker , version ;
22582260 AVIF_CHECK (avifROStreamReadBits (s , & marker , /*bitCount=*/ 1 )); // unsigned int (1) marker = 1;
22592261 if (!marker ) {
@@ -2295,6 +2297,8 @@ static avifBool avifParseCodecConfiguration(avifROStream * s, avifCodecConfigura
22952297 // For simplicity, the constraints above are not enforced.
22962298 // The following is skipped by avifParseItemPropertyContainerBox().
22972299 // unsigned int (8) configOBUs[];
2300+
2301+ AVIF_CHECK (s -> offset - av1COffset == 4 ); // Make sure avifParseCodecConfiguration() reads exactly 4 bytes.
22982302 return AVIF_TRUE ;
22992303}
23002304
@@ -3565,7 +3569,12 @@ static avifProperty * avifDecoderItemAddProperty(avifDecoderItem * item, const a
35653569 return itemProperty ;
35663570}
35673571
3568- static avifResult avifParseMinimizedImageBox (avifMeta * meta , uint64_t rawOffset , const uint8_t * raw , size_t rawLen , avifDiagnostics * diag )
3572+ static avifResult avifParseMinimizedImageBox (avifMeta * meta ,
3573+ uint64_t rawOffset ,
3574+ const uint8_t * raw ,
3575+ size_t rawLen ,
3576+ avifBool isAvifAccordingToMinorVersion ,
3577+ avifDiagnostics * diag )
35693578{
35703579 BEGIN_STREAM (s , raw , rawLen , diag , "Box[mini]" );
35713580
@@ -3614,7 +3623,7 @@ static avifResult avifParseMinimizedImageBox(avifMeta * meta, uint64_t rawOffset
36143623 uint32_t bitDepth ;
36153624 if (floatFlag ) {
36163625 // bit(2) bit_depth_log2_minus4;
3617- return AVIF_RESULT_NOT_IMPLEMENTED ;
3626+ return AVIF_RESULT_BMFF_PARSE_FAILED ; // Either invalid AVIF or unsupported non-AVIF.
36183627 } else {
36193628 uint32_t highBitDepthFlag ;
36203629 AVIF_CHECKERR (avifROStreamReadBits (& s , & highBitDepthFlag , 1 ), AVIF_RESULT_BMFF_PARSE_FAILED ); // bit(1) high_bit_depth_flag;
@@ -3652,7 +3661,6 @@ static avifResult avifParseMinimizedImageBox(avifMeta * meta, uint64_t rawOffset
36523661 : AVIF_MATRIX_COEFFICIENTS_BT601 ; // 6
36533662 }
36543663
3655- // Optional unless minor_version of FileTypeBox is a brand defining these
36563664 uint8_t infeType [4 ];
36573665 uint8_t codecConfigType [4 ];
36583666 if (hasExplicitCodecTypes ) {
@@ -3669,9 +3677,9 @@ static avifResult avifParseMinimizedImageBox(avifMeta * meta, uint64_t rawOffset
36693677 return AVIF_RESULT_NOT_IMPLEMENTED ;
36703678 }
36713679#endif
3672- AVIF_CHECKERR (!memcmp (infeType , "av01" , 4 ), AVIF_RESULT_BMFF_PARSE_FAILED );
3673- AVIF_CHECKERR (!memcmp (codecConfigType , "av1C" , 4 ), AVIF_RESULT_BMFF_PARSE_FAILED );
3680+ AVIF_CHECKERR (!memcmp (infeType , "av01" , 4 ) && !memcmp (codecConfigType , "av1C" , 4 ), AVIF_RESULT_BMFF_PARSE_FAILED );
36743681 } else {
3682+ AVIF_CHECKERR (isAvifAccordingToMinorVersion , AVIF_RESULT_BMFF_PARSE_FAILED );
36753683 memcpy (infeType , "av01" , 4 );
36763684 memcpy (codecConfigType , "av1C" , 4 );
36773685 }
@@ -3825,7 +3833,7 @@ static avifResult avifParseMinimizedImageBox(avifMeta * meta, uint64_t rawOffset
38253833 }
38263834 // if (hdr_flag && gainmap_flag && gainmap_item_codec_config_size > 0)
38273835 // unsigned int(8) gainmap_item_codec_config[gainmap_item_codec_config_size];
3828- avifCodecConfigurationBox mainItemCodecConfig = { 0 } ;
3836+ avifCodecConfigurationBox mainItemCodecConfig ;
38293837 // 'av1C' always uses 4 bytes.
38303838 AVIF_CHECKERR (mainItemCodecConfigSize == 4 , AVIF_RESULT_BMFF_PARSE_FAILED );
38313839 AVIF_CHECKERR (avifParseCodecConfiguration (& s , & mainItemCodecConfig , (const char * )codecConfigType , diag ),
@@ -4051,7 +4059,7 @@ static avifBool avifParseFileTypeBox(avifFileType * ftyp, const uint8_t * raw, s
40514059 BEGIN_STREAM (s , raw , rawLen , diag , "Box[ftyp]" );
40524060
40534061 AVIF_CHECK (avifROStreamRead (& s , ftyp -> majorBrand , 4 ));
4054- AVIF_CHECK (avifROStreamReadU32 (& s , & ftyp -> minorVersion ));
4062+ AVIF_CHECK (avifROStreamRead (& s , ftyp -> minorVersion , 4 ));
40554063
40564064 size_t compatibleBrandsBytes = avifROStreamRemainingBytes (& s );
40574065 if ((compatibleBrandsBytes % 4 ) != 0 ) {
@@ -4085,6 +4093,7 @@ static avifResult avifParse(avifDecoder * decoder)
40854093 avifBool miniSeen = AVIF_FALSE ;
40864094 avifBool needsMini = AVIF_FALSE ;
40874095#endif
4096+ avifFileType ftyp = {};
40884097
40894098 for (;;) {
40904099 // Read just enough to get the next box header (a max of 32 bytes)
@@ -4173,19 +4182,25 @@ static avifResult avifParse(avifDecoder * decoder)
41734182
41744183 if (isFtyp ) {
41754184 AVIF_CHECKERR (!ftypSeen , AVIF_RESULT_BMFF_PARSE_FAILED );
4176- avifFileType ftyp ;
41774185 AVIF_CHECKERR (avifParseFileTypeBox (& ftyp , boxContents .data , boxContents .size , data -> diag ), AVIF_RESULT_BMFF_PARSE_FAILED );
4178- if (!avifFileTypeIsCompatible (& ftyp )) {
4179- return AVIF_RESULT_INVALID_FTYP ;
4180- }
4186+ AVIF_CHECKERR (avifFileTypeIsCompatible (& ftyp ), AVIF_RESULT_INVALID_FTYP );
41814187 ftypSeen = AVIF_TRUE ;
41824188 memcpy (data -> majorBrand , ftyp .majorBrand , 4 ); // Remember the major brand for future AVIF_DECODER_SOURCE_AUTO decisions
41834189 needsMeta = avifFileTypeHasBrand (& ftyp , "avif" );
41844190 needsMoov = avifFileTypeHasBrand (& ftyp , "avis" );
41854191#if defined(AVIF_ENABLE_EXPERIMENTAL_MINI )
41864192 needsMini = avifFileTypeHasBrand (& ftyp , "mif3" );
4187- if (needsMini && needsMeta ) {
4188- return AVIF_RESULT_INVALID_FTYP ;
4193+ if (needsMini ) {
4194+ AVIF_CHECKERR (!needsMeta , AVIF_RESULT_INVALID_FTYP );
4195+ // Section O.2.1.2 of ISO/IEC 23008-12:2014, CDAM 2:
4196+ // When the 'mif3' brand is present as the major_brand of the FileTypeBox,
4197+ // the minor_version of the FileTypeBox shall be 0 or a brand that is either
4198+ // structurally compatible with the 'mif3' brand, such as a codec brand
4199+ // complying with the 'mif3' structural brand, or a brand to which the file
4200+ // conforms after the equivalent MetaBox has been transformed from
4201+ // MinimizedImageBox as specified in Clause O.4.
4202+ AVIF_CHECKERR (!memcmp (ftyp .minorVersion , "\0\0\0\0" , 4 ) || !memcmp (ftyp .minorVersion , "avif" , 4 ),
4203+ AVIF_RESULT_BMFF_PARSE_FAILED );
41894204 }
41904205#endif // AVIF_ENABLE_EXPERIMENTAL_MINI
41914206 } else if (isMeta ) {
@@ -4199,7 +4214,9 @@ static avifResult avifParse(avifDecoder * decoder)
41994214 } else if (isMini ) {
42004215 AVIF_CHECKERR (!metaSeen , AVIF_RESULT_BMFF_PARSE_FAILED );
42014216 AVIF_CHECKERR (!miniSeen , AVIF_RESULT_BMFF_PARSE_FAILED );
4202- AVIF_CHECKRES (avifParseMinimizedImageBox (data -> meta , boxOffset , boxContents .data , boxContents .size , data -> diag ));
4217+ const avifBool isAvifAccordingToMinorVersion = !memcmp (ftyp .minorVersion , "avif" , 4 );
4218+ AVIF_CHECKRES (
4219+ avifParseMinimizedImageBox (data -> meta , boxOffset , boxContents .data , boxContents .size , isAvifAccordingToMinorVersion , data -> diag ));
42034220 miniSeen = AVIF_TRUE ;
42044221#endif
42054222 } else if (isMoov ) {
0 commit comments