@@ -197,6 +197,9 @@ AVIF_ARRAY_DECLARE(avifPropertyArray, avifProperty, prop);
197197// Finds the first property of a given type.
198198static const avifProperty * avifPropertyArrayFind (const avifPropertyArray * properties , const char * type )
199199{
200+ if (type == NULL ) {
201+ return NULL ;
202+ }
200203 for (uint32_t propertyIndex = 0 ; propertyIndex < properties -> count ; ++ propertyIndex ) {
201204 const avifProperty * prop = & properties -> prop [propertyIndex ];
202205 if (!memcmp (prop -> type , type , 4 )) {
@@ -2297,11 +2300,28 @@ static avifResult avifParseSampleTransformImageBox(const uint8_t * raw,
22972300 return AVIF_RESULT_OK ;
22982301}
22992302
2300- static avifResult avifDecoderSampleTransformItemValidateProperties ( const avifDecoderItem * item , avifDiagnostics * diag )
2303+ static const avifProperty * avifDecoderItemCodecConfigOrFirstChildCodecConfig ( const avifDecoderItem * item )
23012304{
2302- const avifProperty * pixiProp = avifPropertyArrayFind (& item -> properties , "pixi" );
2305+ if (!memcmp (item -> type , "grid" , 4 )) {
2306+ // In case of a grid, return the codec configuration property of the first cell.
2307+ // avifDecoderAdoptGridTileCodecType() copies that property from the first cell to the grid item anyway.
2308+ for (uint32_t i = 0 ; i < item -> meta -> items .count ; ++ i ) {
2309+ avifDecoderItem * inputImageItem = item -> meta -> items .item [i ];
2310+ if (inputImageItem -> dimgForID == item -> id ) {
2311+ return avifPropertyArrayFind (& inputImageItem -> properties ,
2312+ avifGetConfigurationPropertyName (avifGetCodecType (inputImageItem -> type )));
2313+ }
2314+ }
2315+ }
2316+ return avifPropertyArrayFind (& item -> properties , avifGetConfigurationPropertyName (avifGetCodecType (item -> type )));
2317+ }
2318+
2319+ static avifResult avifDecoderSampleTransformItemValidateProperties (const avifDecoderItem * satoItem , avifDiagnostics * diag )
2320+ {
2321+ AVIF_ASSERT_OR_RETURN (memcmp (satoItem -> type , "sato" , 4 ) == 0 );
2322+ const avifProperty * pixiProp = avifPropertyArrayFind (& satoItem -> properties , "pixi" );
23032323 if (!pixiProp ) {
2304- avifDiagnosticsPrintf (diag , "Item ID %u of type '%.4s ' is missing mandatory pixi property" , item -> id , ( const char * ) item -> type );
2324+ avifDiagnosticsPrintf (diag , "Item ID %u of type 'sato ' is missing mandatory pixi property" , satoItem -> id );
23052325 return AVIF_RESULT_BMFF_PARSE_FAILED ;
23062326 }
23072327 for (uint8_t i = 1 ; i < pixiProp -> u .pixi .planeCount ; ++ i ) {
@@ -2311,32 +2331,50 @@ static avifResult avifDecoderSampleTransformItemValidateProperties(const avifDec
23112331 AVIF_ASSERT_OR_RETURN (pixiProp -> u .pixi .planeCount >= 1 );
23122332 const uint8_t depth = pixiProp -> u .pixi .planeDepths [0 ];
23132333 if (depth != 8 && depth != 10 && depth != 12 && depth != 16 ) {
2314- avifDiagnosticsPrintf (diag , "Item ID %u depth specified by pixi property [%u] is not supported" , item -> id , depth );
2334+ avifDiagnosticsPrintf (diag , "Item ID %u depth specified by pixi property [%u] is not supported" , satoItem -> id , depth );
23152335 return AVIF_RESULT_NOT_IMPLEMENTED ;
23162336 }
23172337
2318- const avifProperty * ispeProp = avifPropertyArrayFind (& item -> properties , "ispe" );
2338+ const avifProperty * ispeProp = avifPropertyArrayFind (& satoItem -> properties , "ispe" );
23192339 if (!ispeProp ) {
2320- avifDiagnosticsPrintf (diag , "Item ID %u of type '%.4s ' is missing mandatory ispe property" , item -> id , ( const char * ) item -> type );
2340+ avifDiagnosticsPrintf (diag , "Item ID %u of type 'sato ' is missing mandatory ispe property" , satoItem -> id );
23212341 return AVIF_RESULT_BMFF_PARSE_FAILED ;
23222342 }
23232343
2324- // If item is a grid, check that its input image items share the same properties.
2325- for (uint32_t i = 0 ; i < item -> meta -> items .count ; ++ i ) {
2326- avifDecoderItem * inputImageItem = item -> meta -> items .item [i ];
2327- if (inputImageItem -> dimgForID != item -> id ) {
2344+ // Check that all input image items of the 'sato' derived image item share the same properties.
2345+ for (uint32_t i = 0 ; i < satoItem -> meta -> items .count ; ++ i ) {
2346+ avifDecoderItem * inputImageItem = satoItem -> meta -> items .item [i ];
2347+ if (inputImageItem -> dimgForID != satoItem -> id ) {
23282348 continue ;
23292349 }
2350+
2351+ // Require all input image items of the 'sato' derived image item to be associated with a SpatialExtentsProperty.
23302352 const avifProperty * inputImageItemIspeProp = avifPropertyArrayFind (& inputImageItem -> properties , "ispe" );
2331- AVIF_ASSERT_OR_RETURN (inputImageItemIspeProp != NULL );
2353+ if (inputImageItemIspeProp == NULL ) {
2354+ avifDiagnosticsPrintf (diag , "Item ID %u is missing mandatory ispe property" , inputImageItem -> id );
2355+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2356+ }
23322357
2333- for (uint32_t j = i + 1 ; j < item -> meta -> items .count ; ++ j ) {
2334- avifDecoderItem * otherInputImageItem = item -> meta -> items .item [j ];
2335- if (otherInputImageItem -> dimgForID != item -> id ) {
2358+ // The codec configuration property must be present, at least on the first child for a 'grid' item.
2359+ const avifProperty * inputImageItemCodecConfig = avifDecoderItemCodecConfigOrFirstChildCodecConfig (inputImageItem );
2360+ if (inputImageItemCodecConfig == NULL ) {
2361+ avifDiagnosticsPrintf (diag , "Item ID %u is missing mandatory codec configuration property" , inputImageItem -> id );
2362+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2363+ }
2364+
2365+ for (uint32_t j = i + 1 ; j < satoItem -> meta -> items .count ; ++ j ) {
2366+ avifDecoderItem * otherInputImageItem = satoItem -> meta -> items .item [j ];
2367+ if (otherInputImageItem -> dimgForID != satoItem -> id ) {
23362368 continue ;
23372369 }
2370+
2371+ // Require all input image items of the 'sato' derived image item to be associated with a SpatialExtentsProperty.
23382372 const avifProperty * otherInputImageItemIspeProp = avifPropertyArrayFind (& otherInputImageItem -> properties , "ispe" );
2339- AVIF_ASSERT_OR_RETURN (otherInputImageItemIspeProp != NULL );
2373+ if (otherInputImageItemIspeProp == NULL ) {
2374+ avifDiagnosticsPrintf (diag , "Item ID %u is missing mandatory ispe property" , otherInputImageItem -> id );
2375+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2376+ }
2377+
23402378 if (inputImageItemIspeProp -> u .ispe .width != otherInputImageItemIspeProp -> u .ispe .width ||
23412379 inputImageItemIspeProp -> u .ispe .height != otherInputImageItemIspeProp -> u .ispe .height ) {
23422380 avifDiagnosticsPrintf (diag ,
@@ -2347,12 +2385,32 @@ static avifResult avifDecoderSampleTransformItemValidateProperties(const avifDec
23472385 return AVIF_RESULT_BMFF_PARSE_FAILED ;
23482386 }
23492387
2350- // TODO(yguyon): Check that all input image items share the same codec config (except for the bit depth value).
2388+ // The codec configuration property must be present, at least on the first child for a 'grid' item.
2389+ const avifProperty * otherInputImageItemCodecConfig = avifDecoderItemCodecConfigOrFirstChildCodecConfig (otherInputImageItem );
2390+ if (otherInputImageItemCodecConfig == NULL ) {
2391+ avifDiagnosticsPrintf (diag , "Item ID %u is missing mandatory codec configuration property" , otherInputImageItem -> id );
2392+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2393+ }
2394+
2395+ if (inputImageItemCodecConfig -> u .av1C .monochrome != otherInputImageItemCodecConfig -> u .av1C .monochrome ||
2396+ inputImageItemCodecConfig -> u .av1C .chromaSubsamplingX != otherInputImageItemCodecConfig -> u .av1C .chromaSubsamplingX ||
2397+ inputImageItemCodecConfig -> u .av1C .chromaSubsamplingY != otherInputImageItemCodecConfig -> u .av1C .chromaSubsamplingY ||
2398+ inputImageItemCodecConfig -> u .av1C .chromaSamplePosition != otherInputImageItemCodecConfig -> u .av1C .chromaSamplePosition ) {
2399+ avifDiagnosticsPrintf (diag ,
2400+ "The plane count or subsampling in the codec configuration property of item ID %u of type '%.4s' differs from item ID %u" ,
2401+ inputImageItem -> id ,
2402+ (const char * )inputImageItem -> type ,
2403+ otherInputImageItem -> id );
2404+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2405+ }
2406+
2407+ // If the input image item of the 'sato' derived image item is itself a grid,
2408+ // its own input image items will be checked in avifDecoderItemValidateProperties().
23512409 }
23522410 break ;
23532411 }
23542412
2355- AVIF_CHECKERR (avifPropertyArrayFind (& item -> properties , "clap" ) == NULL , AVIF_RESULT_NOT_IMPLEMENTED );
2413+ AVIF_CHECKERR (avifPropertyArrayFind (& satoItem -> properties , "clap" ) == NULL , AVIF_RESULT_NOT_IMPLEMENTED );
23562414 return AVIF_RESULT_OK ;
23572415}
23582416
@@ -6419,7 +6477,7 @@ avifResult avifDecoderReset(avifDecoder * decoder)
64196477 AVIF_ASSERT_OR_RETURN (decoder -> image -> gainMap && decoder -> image -> gainMap -> image );
64206478 decoder -> image -> gainMap -> image -> width = mainItems [AVIF_ITEM_GAIN_MAP ]-> width ;
64216479 decoder -> image -> gainMap -> image -> height = mainItems [AVIF_ITEM_GAIN_MAP ]-> height ;
6422- // Must be called after avifDecoderGenerateImageTiles () which among other things copies the
6480+ // Must be called after avifDecoderAdoptGridTileCodecType () which among other things copies the
64236481 // codec config property from the first tile of a grid to the grid item (when grids are used).
64246482 AVIF_CHECKRES (avifReadCodecConfigProperty (decoder -> image -> gainMap -> image ,
64256483 & mainItems [AVIF_ITEM_GAIN_MAP ]-> properties ,
0 commit comments