@@ -56,6 +56,7 @@ static avifCodecType avifGetCodecType(const uint8_t * fourcc)
5656
5757static const char * avifGetConfigurationPropertyName (avifCodecType codecType )
5858{
59+ static const char kUnknown [] = "****" ;
5960 switch (codecType ) {
6061 case AVIF_CODEC_TYPE_AV1 :
6162 return "av1C" ;
@@ -65,7 +66,7 @@ static const char * avifGetConfigurationPropertyName(avifCodecType codecType)
6566#endif
6667 default :
6768 assert (AVIF_FALSE );
68- return NULL ;
69+ return kUnknown ; // Easier to deal with than NULL.
6970 }
7071}
7172
@@ -2297,11 +2298,30 @@ static avifResult avifParseSampleTransformImageBox(const uint8_t * raw,
22972298 return AVIF_RESULT_OK ;
22982299}
22992300
2300- static avifResult avifDecoderSampleTransformItemValidateProperties ( const avifDecoderItem * item , avifDiagnostics * diag )
2301+ static const avifProperty * avifDecoderItemCodecConfigOrFirstCellCodecConfig ( const avifDecoderItem * item )
23012302{
2302- const avifProperty * pixiProp = avifPropertyArrayFind (& item -> properties , "pixi" );
2303+ if (!memcmp (item -> type , "grid" , 4 )) {
2304+ // In case of a grid, return the codec configuration property of the first cell.
2305+ // avifDecoderAdoptGridTileCodecType() copies that property from the first cell to the grid item anyway.
2306+ for (uint32_t i = 0 ; i < item -> meta -> items .count ; ++ i ) {
2307+ avifDecoderItem * inputImageItem = item -> meta -> items .item [i ];
2308+ if (inputImageItem -> dimgForID == item -> id ) {
2309+ return avifPropertyArrayFind (& inputImageItem -> properties ,
2310+ avifGetConfigurationPropertyName (avifGetCodecType (inputImageItem -> type )));
2311+ }
2312+ }
2313+ // The number of tiles was verified in avifDecoderItemReadAndParse().
2314+ assert (AVIF_FALSE );
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,59 @@ 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 ,
2335+ "Item ID %u of type 'sato' with depth %u (specified by pixi property) is not supported" ,
2336+ satoItem -> id ,
2337+ depth );
23152338 return AVIF_RESULT_NOT_IMPLEMENTED ;
23162339 }
23172340
2318- const avifProperty * ispeProp = avifPropertyArrayFind (& item -> properties , "ispe" );
2341+ const avifProperty * ispeProp = avifPropertyArrayFind (& satoItem -> properties , "ispe" );
23192342 if (!ispeProp ) {
2320- avifDiagnosticsPrintf (diag , "Item ID %u of type '%.4s ' is missing mandatory ispe property" , item -> id , ( const char * ) item -> type );
2343+ avifDiagnosticsPrintf (diag , "Item ID %u of type 'sato ' is missing mandatory ispe property" , satoItem -> id );
23212344 return AVIF_RESULT_BMFF_PARSE_FAILED ;
23222345 }
23232346
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 ) {
2347+ // Check that all input image items of the 'sato' derived image item share the same properties.
2348+ for (uint32_t i = 0 ; i < satoItem -> meta -> items .count ; ++ i ) {
2349+ avifDecoderItem * inputImageItem = satoItem -> meta -> items .item [i ];
2350+ if (inputImageItem -> dimgForID != satoItem -> id ) {
23282351 continue ;
23292352 }
2353+
2354+ // Require all input image items of the 'sato' derived image item to be associated with a ImageSpatialExtentsProperty.
23302355 const avifProperty * inputImageItemIspeProp = avifPropertyArrayFind (& inputImageItem -> properties , "ispe" );
2331- AVIF_ASSERT_OR_RETURN (inputImageItemIspeProp != NULL );
2356+ if (inputImageItemIspeProp == NULL ) {
2357+ avifDiagnosticsPrintf (diag , "Item ID %u is missing mandatory ispe property" , inputImageItem -> id );
2358+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2359+ }
2360+
2361+ // The codec configuration property must be present, at least on the first cell for a 'grid' item.
2362+ const avifProperty * inputImageItemCodecConfig = avifDecoderItemCodecConfigOrFirstCellCodecConfig (inputImageItem );
2363+ if (inputImageItemCodecConfig == NULL ) {
2364+ avifDiagnosticsPrintf (diag ,
2365+ "Item ID %u of type '%.4s' is missing mandatory codec configuration property" ,
2366+ inputImageItem -> id ,
2367+ (const char * )inputImageItem -> type );
2368+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2369+ }
23322370
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 ) {
2371+ for (uint32_t j = i + 1 ; j < satoItem -> meta -> items .count ; ++ j ) {
2372+ avifDecoderItem * otherInputImageItem = satoItem -> meta -> items .item [j ];
2373+ if (otherInputImageItem -> dimgForID != satoItem -> id ) {
23362374 continue ;
23372375 }
2376+
2377+ // Require all input image items of the 'sato' derived image item to be associated with a ImageSpatialExtentsProperty.
23382378 const avifProperty * otherInputImageItemIspeProp = avifPropertyArrayFind (& otherInputImageItem -> properties , "ispe" );
2339- AVIF_ASSERT_OR_RETURN (otherInputImageItemIspeProp != NULL );
2379+ if (otherInputImageItemIspeProp == NULL ) {
2380+ avifDiagnosticsPrintf (diag ,
2381+ "Item ID %u of type '%.4s' is missing mandatory ispe property" ,
2382+ otherInputImageItem -> id ,
2383+ (const char * )otherInputImageItem -> type );
2384+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2385+ }
2386+
23402387 if (inputImageItemIspeProp -> u .ispe .width != otherInputImageItemIspeProp -> u .ispe .width ||
23412388 inputImageItemIspeProp -> u .ispe .height != otherInputImageItemIspeProp -> u .ispe .height ) {
23422389 avifDiagnosticsPrintf (diag ,
@@ -2347,12 +2394,35 @@ static avifResult avifDecoderSampleTransformItemValidateProperties(const avifDec
23472394 return AVIF_RESULT_BMFF_PARSE_FAILED ;
23482395 }
23492396
2350- // TODO(yguyon): Check that all input image items share the same codec config (except for the bit depth value).
2397+ // The codec configuration property must be present, at least on the first cell for a 'grid' item.
2398+ const avifProperty * otherInputImageItemCodecConfig = avifDecoderItemCodecConfigOrFirstCellCodecConfig (otherInputImageItem );
2399+ if (otherInputImageItemCodecConfig == NULL ) {
2400+ avifDiagnosticsPrintf (diag ,
2401+ "Item ID %u of type '%.4s' is missing mandatory codec configuration property" ,
2402+ otherInputImageItem -> id ,
2403+ (const char * )otherInputImageItem -> type );
2404+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2405+ }
2406+
2407+ if (inputImageItemCodecConfig -> u .av1C .monochrome != otherInputImageItemCodecConfig -> u .av1C .monochrome ||
2408+ inputImageItemCodecConfig -> u .av1C .chromaSubsamplingX != otherInputImageItemCodecConfig -> u .av1C .chromaSubsamplingX ||
2409+ inputImageItemCodecConfig -> u .av1C .chromaSubsamplingY != otherInputImageItemCodecConfig -> u .av1C .chromaSubsamplingY ||
2410+ inputImageItemCodecConfig -> u .av1C .chromaSamplePosition != otherInputImageItemCodecConfig -> u .av1C .chromaSamplePosition ) {
2411+ avifDiagnosticsPrintf (diag ,
2412+ "The plane count or subsampling in the codec configuration property of item ID %u of type '%.4s' differs from item ID %u" ,
2413+ inputImageItem -> id ,
2414+ (const char * )inputImageItem -> type ,
2415+ otherInputImageItem -> id );
2416+ return AVIF_RESULT_BMFF_PARSE_FAILED ;
2417+ }
2418+
2419+ // If the input image item of the 'sato' derived image item is itself a grid,
2420+ // its own input image items will be checked in avifDecoderItemValidateProperties().
23512421 }
23522422 break ;
23532423 }
23542424
2355- AVIF_CHECKERR (avifPropertyArrayFind (& item -> properties , "clap" ) == NULL , AVIF_RESULT_NOT_IMPLEMENTED );
2425+ AVIF_CHECKERR (avifPropertyArrayFind (& satoItem -> properties , "clap" ) == NULL , AVIF_RESULT_NOT_IMPLEMENTED );
23562426 return AVIF_RESULT_OK ;
23572427}
23582428
@@ -6419,7 +6489,7 @@ avifResult avifDecoderReset(avifDecoder * decoder)
64196489 AVIF_ASSERT_OR_RETURN (decoder -> image -> gainMap && decoder -> image -> gainMap -> image );
64206490 decoder -> image -> gainMap -> image -> width = mainItems [AVIF_ITEM_GAIN_MAP ]-> width ;
64216491 decoder -> image -> gainMap -> image -> height = mainItems [AVIF_ITEM_GAIN_MAP ]-> height ;
6422- // Must be called after avifDecoderGenerateImageTiles () which among other things copies the
6492+ // Must be called after avifDecoderAdoptGridTileCodecType () which among other things copies the
64236493 // codec config property from the first tile of a grid to the grid item (when grids are used).
64246494 AVIF_CHECKRES (avifReadCodecConfigProperty (decoder -> image -> gainMap -> image ,
64256495 & mainItems [AVIF_ITEM_GAIN_MAP ]-> properties ,
0 commit comments