From 72ed871e2570b85b1026212379f48c7b8e3ceea4 Mon Sep 17 00:00:00 2001 From: Yannis Guyon Date: Thu, 18 Jan 2024 16:35:44 +0000 Subject: [PATCH] Update reduced header experiment syntax (#1952) Support 4:2:2 subsampling. Strip matrix coefficients for monochrome images. --- src/read.c | 106 +++++++++++++++++++++++++----------- src/write.c | 71 ++++++++++++++---------- tests/gtest/avifconitest.cc | 4 +- 3 files changed, 116 insertions(+), 65 deletions(-) diff --git a/src/read.c b/src/read.c index 2bb1abcb25..5c16132dba 100644 --- a/src/read.c +++ b/src/read.c @@ -211,6 +211,7 @@ typedef struct avifDecoderItem avifBool progressive; // if true, this item has progressive layers (a1lx), but does not select a specific layer (the layer_id value in lsel is set to 0xFFFF) #if defined(AVIF_ENABLE_EXPERIMENTAL_AVIR) avifPixelFormat coniPixelFormat; // Set from the CondensedImageBox, if present (AVIF_PIXEL_FORMAT_NONE otherwise) + avifChromaSamplePosition coniChromaSamplePosition; // Set from the CondensedImageBox, if present (AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN otherwise) #endif } avifDecoderItem; AVIF_ARRAY_DECLARE(avifDecoderItemArray, avifDecoderItem *, item); @@ -1191,15 +1192,34 @@ static avifResult avifDecoderItemValidateProperties(const avifDecoderItem * item } #if defined(AVIF_ENABLE_EXPERIMENTAL_AVIR) - if ((item->coniPixelFormat != AVIF_PIXEL_FORMAT_NONE) && - (item->coniPixelFormat != avifCodecConfigurationBoxGetFormat(&configProp->u.av1C))) { - avifDiagnosticsPrintf(diag, - "Item ID %u format [%s] specified by coni box does not match %s property format [%s]", - item->id, - avifPixelFormatToString(item->coniPixelFormat), - configPropName, - avifPixelFormatToString(avifCodecConfigurationBoxGetFormat(&configProp->u.av1C))); - return AVIF_RESULT_BMFF_PARSE_FAILED; + if (item->coniPixelFormat != AVIF_PIXEL_FORMAT_NONE) { + // This is a 'coni' box. + + if (item->coniPixelFormat != avifCodecConfigurationBoxGetFormat(&configProp->u.av1C)) { + avifDiagnosticsPrintf(diag, + "Item ID %u format [%s] specified by coni box does not match %s property format [%s]", + item->id, + avifPixelFormatToString(item->coniPixelFormat), + configPropName, + avifPixelFormatToString(avifCodecConfigurationBoxGetFormat(&configProp->u.av1C))); + return AVIF_RESULT_BMFF_PARSE_FAILED; + } + + if (configProp->u.av1C.chromaSamplePosition == /*CSP_UNKNOWN=*/0) { + // Section 6.4.2. Color config semantics of AV1 specification says: + // CSP_UNKNOWN - the source video transfer function must be signaled outside the AV1 bitstream + // See https://aomediacodec.github.io/av1-spec/#color-config-semantics + + // So item->coniChromaSamplePosition can differ and will override the AV1 value. + } else if ((uint8_t)item->coniChromaSamplePosition != configProp->u.av1C.chromaSamplePosition) { + avifDiagnosticsPrintf(diag, + "Item ID %u chroma sample position [%u] specified by coni box does not match %s property chroma sample position [%u]", + item->id, + (uint32_t)item->coniChromaSamplePosition, + configPropName, + configProp->u.av1C.chromaSamplePosition); + return AVIF_RESULT_BMFF_PARSE_FAILED; + } } #endif // AVIF_ENABLE_EXPERIMENTAL_AVIR @@ -3395,25 +3415,33 @@ static avifResult avifParseCondensedImageBox(avifMeta * meta, uint64_t rawOffset AVIF_CHECKERR(version == 0, AVIF_RESULT_NOT_IMPLEMENTED); uint32_t width, height; - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &width), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) width_minus_one; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &width), AVIF_RESULT_BMFF_PARSE_FAILED); // varint width_minus_one; AVIF_CHECKERR(width != UINT32_MAX, AVIF_RESULT_BMFF_PARSE_FAILED); ++width; - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &height), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) height_minus_one; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &height), AVIF_RESULT_BMFF_PARSE_FAILED); // varint height_minus_one; AVIF_CHECKERR(height != UINT32_MAX, AVIF_RESULT_BMFF_PARSE_FAILED); ++height; uint32_t isFloat; AVIF_CHECKERR(avifROStreamReadBits(&s, &isFloat, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) is_float; - AVIF_CHECKERR(!isFloat, AVIF_RESULT_NOT_IMPLEMENTED); + if (isFloat) { + // unsigned int(2) float_precision; + return AVIF_RESULT_NOT_IMPLEMENTED; + } uint32_t bitDepth; AVIF_CHECKERR(avifROStreamReadBits(&s, &bitDepth, 4), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) bit_depth_minus_one; ++bitDepth; AVIF_CHECKERR((bitDepth == 8) || (bitDepth == 10) || (bitDepth == 12), AVIF_RESULT_UNSUPPORTED_DEPTH); - uint32_t isMonochrome; - AVIF_CHECKERR(avifROStreamReadBits(&s, &isMonochrome, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) is_monochrome; - uint32_t isSubsampled = AVIF_FALSE; - if (!isMonochrome) { - AVIF_CHECKERR(avifROStreamReadBits(&s, &isSubsampled, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) is_subsampled; + uint32_t subsampling; + AVIF_CHECKERR(avifROStreamReadBits(&s, &subsampling, 2), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(2) subsampling; + const avifPixelFormat yuvFormat = subsampling == 0 ? AVIF_PIXEL_FORMAT_YUV400 : (avifPixelFormat)subsampling; + const avifBool isMonochrome = yuvFormat == AVIF_PIXEL_FORMAT_YUV400; + const avifBool isSubsampled = yuvFormat == AVIF_PIXEL_FORMAT_YUV422 || yuvFormat == AVIF_PIXEL_FORMAT_YUV420; + avifChromaSamplePosition yuvChromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN; + if (isSubsampled) { + uint32_t isCentered; + AVIF_CHECKERR(avifROStreamReadBits(&s, &isCentered, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) is_centered; + yuvChromaSamplePosition = isCentered ? AVIF_CHROMA_SAMPLE_POSITION_VERTICAL : AVIF_CHROMA_SAMPLE_POSITION_COLOCATED; } uint32_t fullRange; AVIF_CHECKERR(avifROStreamReadBits(&s, &fullRange, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) full_range; @@ -3426,15 +3454,19 @@ static avifResult avifParseCondensedImageBox(avifMeta * meta, uint64_t rawOffset if (colorType == AVIF_CONI_COLOR_TYPE_ICC) { colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; - AVIF_CHECKERR(avifROStreamReadBits(&s, &matrixCoefficients, 8), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(8) matrix_coefficients; - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &iccDataSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) icc_data_size_minus_one; + if (isMonochrome) { + matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED; + } else { + AVIF_CHECKERR(avifROStreamReadBits(&s, &matrixCoefficients, 8), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(8) matrix_coefficients; + } + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &iccDataSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint icc_data_size_minus_one; AVIF_CHECKERR(iccDataSize != UINT32_MAX, AVIF_RESULT_BMFF_PARSE_FAILED); ++iccDataSize; } else if (colorType == AVIF_CONI_COLOR_TYPE_SRGB) { // sRGB colorPrimaries = AVIF_COLOR_PRIMARIES_SRGB; transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; - matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601; + matrixCoefficients = isMonochrome ? AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED : AVIF_MATRIX_COEFFICIENTS_BT601; iccDataSize = 0; } else { const uint32_t numBitsPerComponent = (colorType == AVIF_CONI_COLOR_TYPE_NCLX_5BIT) ? 5 : 8; @@ -3442,18 +3474,26 @@ static avifResult avifParseCondensedImageBox(avifMeta * meta, uint64_t rawOffset AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(5/8) color_primaries; AVIF_CHECKERR(avifROStreamReadBits(&s, &transferCharacteristics, numBitsPerComponent), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(5/8) transfer_characteristics; - AVIF_CHECKERR(avifROStreamReadBits(&s, &matrixCoefficients, numBitsPerComponent), - AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(5/8) matrix_coefficients; + if (isMonochrome) { + matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED; + } else { + AVIF_CHECKERR(avifROStreamReadBits(&s, &matrixCoefficients, numBitsPerComponent), + AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(5/8) matrix_coefficients; + } iccDataSize = 0; } uint32_t hasExplicitCodecTypes; AVIF_CHECKERR(avifROStreamReadBits(&s, &hasExplicitCodecTypes, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) has_explicit_codec_types; - AVIF_CHECKERR(!hasExplicitCodecTypes, AVIF_RESULT_NOT_IMPLEMENTED); + if (hasExplicitCodecTypes) { + // unsigned int(32) infe_type; + // unsigned int(32) codec_config_type; + return AVIF_RESULT_NOT_IMPLEMENTED; + } uint32_t colorItemCodecConfigSize, colorItemDataSize; - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &colorItemCodecConfigSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) main_item_codec_config_size; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &colorItemCodecConfigSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint main_item_codec_config_size; AVIF_CHECKERR(colorItemCodecConfigSize == 4, AVIF_RESULT_NOT_IMPLEMENTED); - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &colorItemDataSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) main_item_data_size_minus_one; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &colorItemDataSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint main_item_data_size_minus_one; AVIF_CHECKERR(colorItemDataSize != UINT32_MAX, AVIF_RESULT_BMFF_PARSE_FAILED); ++colorItemDataSize; @@ -3464,28 +3504,28 @@ static avifResult avifParseCondensedImageBox(avifMeta * meta, uint64_t rawOffset if (hasAlpha) { AVIF_CHECKERR(avifROStreamReadBits(&s, &alphaIsPremultiplied, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) alpha_is_premultiplied; uint32_t alphaItemCodecConfigSize; - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &alphaItemCodecConfigSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) alpha_item_codec_config_size; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &alphaItemCodecConfigSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint alpha_item_codec_config_size; AVIF_CHECKERR(alphaItemCodecConfigSize == 4, AVIF_RESULT_NOT_IMPLEMENTED); - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &alphaItemDataSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) alpha_item_data_size; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &alphaItemDataSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint alpha_item_data_size; } uint32_t hasExtendedMeta, hasExif, hasXMP; uint32_t extendedMetaSize = 0, exifSize = 0, xmpSize = 0; AVIF_CHECKERR(avifROStreamReadBits(&s, &hasExtendedMeta, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) has_extended_meta; if (hasExtendedMeta) { - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &extendedMetaSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) extended_meta_size_minus_one; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &extendedMetaSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint extended_meta_size_minus_one; AVIF_CHECKERR(extendedMetaSize != UINT32_MAX, AVIF_RESULT_BMFF_PARSE_FAILED); ++extendedMetaSize; } AVIF_CHECKERR(avifROStreamReadBits(&s, &hasExif, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) has_exif; if (hasExif) { - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &exifSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) exif_data_size_minus_one; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &exifSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint exif_data_size_minus_one; AVIF_CHECKERR(exifSize != UINT32_MAX, AVIF_RESULT_BMFF_PARSE_FAILED); ++exifSize; } AVIF_CHECKERR(avifROStreamReadBits(&s, &hasXMP, 1), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(1) has_xmp; if (hasXMP) { - AVIF_CHECKERR(avifROStreamReadVarInt(&s, &xmpSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint(32) xmp_data_size_minus_one; + AVIF_CHECKERR(avifROStreamReadVarInt(&s, &xmpSize), AVIF_RESULT_BMFF_PARSE_FAILED); // varint xmp_data_size_minus_one; AVIF_CHECKERR(xmpSize != UINT32_MAX, AVIF_RESULT_BMFF_PARSE_FAILED); ++xmpSize; } @@ -3529,9 +3569,8 @@ static avifResult avifParseCondensedImageBox(avifMeta * meta, uint64_t rawOffset memcpy(colorItem->type, "av01", 4); colorItem->width = width; colorItem->height = height; - colorItem->coniPixelFormat = isMonochrome ? AVIF_PIXEL_FORMAT_YUV400 - : isSubsampled ? AVIF_PIXEL_FORMAT_YUV420 - : AVIF_PIXEL_FORMAT_YUV444; + colorItem->coniPixelFormat = yuvFormat; + colorItem->coniChromaSamplePosition = yuvChromaSamplePosition; avifDecoderItem * alphaItem = NULL; if (hasAlpha) { @@ -3540,6 +3579,7 @@ static avifResult avifParseCondensedImageBox(avifMeta * meta, uint64_t rawOffset alphaItem->width = width; alphaItem->height = height; alphaItem->coniPixelFormat = AVIF_PIXEL_FORMAT_YUV400; + alphaItem->coniChromaSamplePosition = AVIF_CHROMA_SAMPLE_POSITION_UNKNOWN; } // Property with fixed index 1. diff --git a/src/write.c b/src/write.c index 39dcc410e0..bf9a78d73f 100644 --- a/src/write.c +++ b/src/write.c @@ -1993,10 +1993,8 @@ static avifBool avifEncoderIsCondensedImageBoxCompatible(const avifEncoder * enc return AVIF_FALSE; } - // Only 4:4:4, 4:2:0 and 4:0:0 are supported by a CondensedImageBox. - if ((encoder->data->imageMetadata->yuvFormat != AVIF_PIXEL_FORMAT_YUV444) && - (encoder->data->imageMetadata->yuvFormat != AVIF_PIXEL_FORMAT_YUV420) && - (encoder->data->imageMetadata->yuvFormat != AVIF_PIXEL_FORMAT_YUV400)) { + // 4:4:4, 4:2:2, 4:2:0 and 4:0:0 are supported by a CondensedImageBox. + if (encoder->data->imageMetadata->yuvFormat == AVIF_PIXEL_FORMAT_NONE) { return AVIF_FALSE; } @@ -2090,33 +2088,41 @@ static avifResult avifEncoderWriteCondensedImageBox(avifEncoder * encoder, avifR const avifImage * const image = encoder->data->imageMetadata; const avifBool isMonochrome = image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400; - const avifBool isSubsampled = image->yuvFormat == AVIF_PIXEL_FORMAT_YUV420; + const avifBool isSubsampled = image->yuvFormat == AVIF_PIXEL_FORMAT_YUV422 || image->yuvFormat == AVIF_PIXEL_FORMAT_YUV420; const avifBool fullRange = image->yuvRange == AVIF_RANGE_FULL; avifBoxMarker coni; AVIF_CHECKRES(avifRWStreamWriteBox(s, "coni", AVIF_BOX_SIZE_TBD, &coni)); AVIF_CHECKRES(avifRWStreamWriteBits(s, 0, 2)); // unsigned int(2) version; - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, image->width - 1)); // varint(32) width_minus_one; - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, image->height - 1)); // varint(32) height_minus_one; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, image->width - 1)); // varint width_minus_one; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, image->height - 1)); // varint height_minus_one; AVIF_CHECKRES(avifRWStreamWriteBits(s, 0, 1)); // unsigned int(1) is_float; + // unsigned int(2) float_precision; AVIF_CHECKRES(avifRWStreamWriteBits(s, image->depth - 1, 4)); // unsigned int(4) bit_depth_minus_one; - AVIF_CHECKRES(avifRWStreamWriteBits(s, isMonochrome, 1)); // unsigned int(1) is_monochrome; - if (!isMonochrome) { - AVIF_CHECKRES(avifRWStreamWriteBits(s, isSubsampled, 1)); // unsigned int(1) is_subsampled; + if (isMonochrome) { + AVIF_CHECKRES(avifRWStreamWriteBits(s, 0, 2)); // unsigned int(2) subsampling; + } else { + AVIF_CHECKRES(avifRWStreamWriteBits(s, (uint32_t)image->yuvFormat, 2)); // unsigned int(2) subsampling; + } + if (isSubsampled) { + AVIF_CHECKRES(avifRWStreamWriteBits(s, image->yuvChromaSamplePosition == AVIF_CHROMA_SAMPLE_POSITION_VERTICAL ? 1 : 0, 1)); // unsigned int(1) is_centered; } AVIF_CHECKRES(avifRWStreamWriteBits(s, fullRange, 1)); // unsigned int(1) full_range; if (image->icc.size) { - AVIF_CHECKRES(avifRWStreamWriteBits(s, AVIF_CONI_COLOR_TYPE_ICC, 2)); // unsigned int(2) color_type; - AVIF_CHECKRES(avifRWStreamWriteBits(s, image->matrixCoefficients, 8)); // unsigned int(8) matrix_coefficients; - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)image->icc.size - 1)); // varint(32) icc_data_size; + AVIF_CHECKRES(avifRWStreamWriteBits(s, AVIF_CONI_COLOR_TYPE_ICC, 2)); // unsigned int(2) color_type; + AVIF_CHECKERR(image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED, AVIF_RESULT_INVALID_ARGUMENT); + AVIF_CHECKERR(image->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED, AVIF_RESULT_INVALID_ARGUMENT); + if (isMonochrome) { + AVIF_CHECKERR(image->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED, AVIF_RESULT_INVALID_ARGUMENT); + } else { + AVIF_CHECKRES(avifRWStreamWriteBits(s, image->matrixCoefficients, 8)); // unsigned int(8) matrix_coefficients; + } + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)image->icc.size - 1)); // varint icc_data_size_minus_one; } else { - if (((image->colorPrimaries == AVIF_COLOR_PRIMARIES_SRGB) && (image->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_SRGB) && - (image->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_BT601)) || - ((image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED) && - (image->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED) && - (image->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED))) { + if (image->colorPrimaries == AVIF_COLOR_PRIMARIES_SRGB && image->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_SRGB && + (image->matrixCoefficients == (isMonochrome ? AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED : AVIF_MATRIX_COEFFICIENTS_BT601))) { AVIF_CHECKRES(avifRWStreamWriteBits(s, AVIF_CONI_COLOR_TYPE_SRGB, 2)); // unsigned int(2) color_type; } else { const avifConiColorType colorType = ((image->colorPrimaries >> 5 == 0) && (image->transferCharacteristics >> 5 == 0) && @@ -2125,22 +2131,28 @@ static avifResult avifEncoderWriteCondensedImageBox(avifEncoder * encoder, avifR : AVIF_CONI_COLOR_TYPE_NCLX_8BIT; const uint32_t numBitsPerComponent = (colorType == AVIF_CONI_COLOR_TYPE_NCLX_5BIT) ? 5 : 8; AVIF_CHECKRES(avifRWStreamWriteBits(s, colorType, 2)); // unsigned int(2) color_type; - AVIF_CHECKRES(avifRWStreamWriteBits(s, image->colorPrimaries, numBitsPerComponent)); // unsigned int(5) color_primaries; - AVIF_CHECKRES(avifRWStreamWriteBits(s, image->transferCharacteristics, numBitsPerComponent)); // unsigned int(5) transfer_characteristics; - AVIF_CHECKRES(avifRWStreamWriteBits(s, image->matrixCoefficients, numBitsPerComponent)); // unsigned int(5) matrix_coefficients; + AVIF_CHECKRES(avifRWStreamWriteBits(s, image->colorPrimaries, numBitsPerComponent)); // unsigned int(5/8) color_primaries; + AVIF_CHECKRES(avifRWStreamWriteBits(s, image->transferCharacteristics, numBitsPerComponent)); // unsigned int(5/8) transfer_characteristics; + if (isMonochrome) { + AVIF_CHECKERR(image->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED, AVIF_RESULT_INVALID_ARGUMENT); + } else { + AVIF_CHECKRES(avifRWStreamWriteBits(s, image->matrixCoefficients, numBitsPerComponent)); // unsigned int(5/8) matrix_coefficients; + } } } AVIF_CHECKRES(avifRWStreamWriteBits(s, 0, 1)); // unsigned int(1) has_explicit_codec_types; - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, 4)); // varint(32) main_item_codec_config_size; + // unsigned int(32) infe_type; + // unsigned int(32) codec_config_type; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, 4)); // varint main_item_codec_config_size; assert(colorData->size >= 1); - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)colorData->size - 1)); // varint(32) main_item_data_size; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)colorData->size - 1)); // varint main_item_data_size_minus_one; AVIF_CHECKRES(avifRWStreamWriteBits(s, alphaItem ? 1 : 0, 1)); // unsigned int(1) has_alpha; if (alphaItem) { AVIF_CHECKRES(avifRWStreamWriteBits(s, image->alphaPremultiplied, 1)); // unsigned int(1) alpha_is_premultiplied; - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, 4)); // varint(32) alpha_item_codec_config_size; - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)alphaData->size)); // varint(32) alpha_item_data_size; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, 4)); // varint alpha_item_codec_config_size; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)alphaData->size)); // varint alpha_item_data_size; } if (image->clli.maxCLL || image->clli.maxPALL || (image->transformFlags != AVIF_TRANSFORM_NONE)) { @@ -2151,16 +2163,16 @@ static avifResult avifEncoderWriteCondensedImageBox(avifEncoder * encoder, avifR } AVIF_CHECKRES(avifRWStreamWriteBits(s, extendedMeta->size ? 1 : 0, 1)); // unsigned int(1) has_extended_meta; if (extendedMeta->size) { - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)extendedMeta->size - 1)); // varint(32) extended_meta_size; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)extendedMeta->size - 1)); // varint extended_meta_size_minus_one; } AVIF_CHECKRES(avifRWStreamWriteBits(s, image->exif.size ? 1 : 0, 1)); // unsigned int(1) has_exif; if (image->exif.size) { - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)image->exif.size - 1)); // varint(32) exif_data_size; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)image->exif.size - 1)); // varint exif_data_size_minus_one; } AVIF_CHECKRES(avifRWStreamWriteBits(s, image->xmp.size ? 1 : 0, 1)); // unsigned int(1) has_xmp; if (image->xmp.size) { - AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)image->xmp.size - 1)); // varint(32) xmp_data_size; + AVIF_CHECKRES(avifRWStreamWriteVarInt(s, (uint32_t)image->xmp.size - 1)); // varint xmp_data_size_minus_one; } // Padding to align with whole bytes if necessary. @@ -2169,8 +2181,7 @@ static avifResult avifEncoderWriteCondensedImageBox(avifEncoder * encoder, avifR } if (alphaItem) { - AVIF_CHECKRES(writeCodecConfig(s, - &alphaItem->av1C)); // unsigned int(8) alpha_item_codec_config[]; + AVIF_CHECKRES(writeCodecConfig(s, &alphaItem->av1C)); // unsigned int(8) alpha_item_codec_config[]; } AVIF_CHECKRES(writeCodecConfig(s, &colorItem->av1C)); // unsigned int(8) main_item_codec_config[]; diff --git a/tests/gtest/avifconitest.cc b/tests/gtest/avifconitest.cc index a4079fa54f..913547f1b9 100644 --- a/tests/gtest/avifconitest.cc +++ b/tests/gtest/avifconitest.cc @@ -130,8 +130,8 @@ INSTANTIATE_TEST_SUITE_P( DepthsSubsamplings, AvifCondensedImageBoxTest, Combine(/*width=*/Values(12), /*height=*/Values(34), /*depth=*/Values(8, 10, 12), - Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV420, - AVIF_PIXEL_FORMAT_YUV400), + Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422, + AVIF_PIXEL_FORMAT_YUV420, AVIF_PIXEL_FORMAT_YUV400), Values(AVIF_PLANES_ALL), Values(AVIF_RANGE_FULL), /*create_icc=*/Values(false), /*create_exif=*/Values(false), /*create_xmp=*/Values(false), /*create_clli=*/Values(false),