From 127bd7ef4ce5757da23c293fe2aa835534b8cc21 Mon Sep 17 00:00:00 2001 From: Yannis Guyon Date: Thu, 3 Aug 2023 18:51:14 +0200 Subject: [PATCH] Split and document avifParseCodecConfiguration() Mirror the changes of read.c to write.c too. --- src/read.c | 55 +++++++++++++++++++++++++++++++++++++---------------- src/write.c | 34 +++++++++++++++++++++++++++++---- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/read.c b/src/read.c index 8645d3125a..f63de3c243 100644 --- a/src/read.c +++ b/src/read.c @@ -1862,24 +1862,16 @@ static avifBool avifParseContentLightLevelInformationBox(avifProperty * prop, co return AVIF_TRUE; } -static avifBool avifParseCodecConfigurationBoxProperty(avifProperty * prop, - const uint8_t * raw, - size_t rawLen, - const char * configPropName, - avifDiagnostics * diag) +// Implementation of section 2.3.3. of AV1 Codec ISO Media File Format Binding specification v1.2.0. +// See https://aomediacodec.github.io/av1-isobmff/v1.2.0.html#av1codecconfigurationbox-syntax. +static avifBool avifParseCodecConfiguration(avifROStream * s, avifCodecConfigurationBox * config, const char * configPropName, avifDiagnostics * diag) { - char diagContext[] = "Box[....]"; - snprintf(diagContext, sizeof(diagContext), "Box[%.4s]", configPropName); // "Box[av1C]" or "Box[av2C]" - BEGIN_STREAM(s, raw, rawLen, diag, diagContext); - - avifCodecConfigurationBox * config = &prop->u.av1C; - uint8_t markerAndVersion = 0; - AVIF_CHECK(avifROStreamRead(&s, &markerAndVersion, 1)); + AVIF_CHECK(avifROStreamRead(s, &markerAndVersion, 1)); uint8_t seqProfileAndIndex = 0; - AVIF_CHECK(avifROStreamRead(&s, &seqProfileAndIndex, 1)); + AVIF_CHECK(avifROStreamRead(s, &seqProfileAndIndex, 1)); uint8_t rawFlags = 0; - AVIF_CHECK(avifROStreamRead(&s, &rawFlags, 1)); + AVIF_CHECK(avifROStreamRead(s, &rawFlags, 1)); if (markerAndVersion != 0x81) { // Marker and version must both == 1 @@ -1896,9 +1888,41 @@ static avifBool avifParseCodecConfigurationBoxProperty(avifProperty * prop, config->chromaSubsamplingX = (rawFlags >> 3) & 0x1; // unsigned int (1) chroma_subsampling_x; config->chromaSubsamplingY = (rawFlags >> 2) & 0x1; // unsigned int (1) chroma_subsampling_y; config->chromaSamplePosition = (rawFlags >> 0) & 0x3; // unsigned int (2) chroma_sample_position; + + // unsigned int (3) reserved = 0; + // unsigned int (1) initial_presentation_delay_present; + // if (initial_presentation_delay_present) { + // unsigned int (4) initial_presentation_delay_minus_one; + // } else { + // unsigned int (4) reserved = 0; + // } + AVIF_CHECK(avifROStreamSkip(s, 1)); + + // According to section 2.2.1. of AV1 Image File Format specification v1.1.0: + // "- Sequence Header OBUs should not be present in the AV1CodecConfigurationBox." + // "- If a Sequence Header OBU is present in the AV1CodecConfigurationBox, + // it shall match the Sequence Header OBU in the AV1 Image Item Data." + // "- Metadata OBUs, if present, shall match the values given in other item properties, + // such as the PixelInformationProperty or ColourInformationBox." + // See https://aomediacodec.github.io/av1-avif/v1.1.0.html#av1-configuration-item-property. + // For simplicity, the constraints above are not enforced. + // The following is skipped by avifParseItemPropertyContainerBox(). + // unsigned int (8) configOBUs[]; return AVIF_TRUE; } +static avifBool avifParseCodecConfigurationBoxProperty(avifProperty * prop, + const uint8_t * raw, + size_t rawLen, + const char * configPropName, + avifDiagnostics * diag) +{ + char diagContext[] = "Box[....]"; + snprintf(diagContext, sizeof(diagContext), "Box[%.4s]", configPropName); // "Box[av1C]" or "Box[av2C]" + BEGIN_STREAM(s, raw, rawLen, diag, diagContext); + return avifParseCodecConfiguration(&s, &prop->u.av1C, configPropName, diag); +} + static avifBool avifParsePixelAspectRatioBoxProperty(avifProperty * prop, const uint8_t * raw, size_t rawLen, avifDiagnostics * diag) { BEGIN_STREAM(s, raw, rawLen, diag, "Box[pasp]"); @@ -2386,7 +2410,7 @@ static avifBool avifParseItemInfoEntry(avifMeta * meta, const uint8_t * raw, siz avifDecoderItem * item = avifMetaFindItem(meta, itemID); if (!item) { - avifDiagnosticsPrintf(diag, "Box[infe] has an invalid item ID [%u]", itemID); + avifDiagnosticsPrintf(diag, "%s: Box[infe] of type %.4s has an invalid item ID [%u]", s.diagContext, itemType, itemID); return AVIF_FALSE; } @@ -4120,7 +4144,6 @@ avifResult avifDecoderReset(avifDecoder * decoder) decoder->image->yuvFormat = AVIF_PIXEL_FORMAT_YUV420; } else if (configProp->u.av1C.chromaSubsamplingX) { decoder->image->yuvFormat = AVIF_PIXEL_FORMAT_YUV422; - } else { decoder->image->yuvFormat = AVIF_PIXEL_FORMAT_YUV444; } diff --git a/src/write.c b/src/write.c index 70a2914bab..c569d15c77 100644 --- a/src/write.c +++ b/src/write.c @@ -36,7 +36,7 @@ static const size_t alphaURNSize = sizeof(alphaURN); static const char xmpContentType[] = AVIF_CONTENT_TYPE_XMP; static const size_t xmpContentTypeSize = sizeof(xmpContentType); -static void writeConfigBox(avifRWStream * s, avifCodecConfigurationBox * cfg, const char * configPropName); +static void writeConfigBox(avifRWStream * s, const avifCodecConfigurationBox * cfg, const char * configPropName); // --------------------------------------------------------------------------- // avifSetTileConfiguration @@ -417,6 +417,7 @@ avifEncoder * avifEncoderCreate(void) return NULL; } memset(encoder, 0, sizeof(avifEncoder)); + encoder->codecChoice = AVIF_CODEC_CHOICE_AUTO; encoder->maxThreads = 1; encoder->speed = AVIF_SPEED_DEFAULT; encoder->keyframeInterval = 0; @@ -536,6 +537,12 @@ static avifBool avifEncoderDetectChanges(const avifEncoder * encoder, avifEncode return AVIF_TRUE; } +// Subset of avifEncoderWriteColorProperties() for the properties clli, pasp, clap, irot, imir. +static void avifEncoderWriteExtendedColorProperties(avifRWStream * outputStream, + const avifImage * imageMetadata, + struct ipmaArray * ipma, + avifItemPropertyDedup * dedup); + // This function is used in two codepaths: // * writing color *item* properties // * writing color *track* properties @@ -590,6 +597,15 @@ static void avifEncoderWriteColorProperties(avifRWStream * outputStream, ipmaPush(ipma, avifItemPropertyDedupFinish(dedup, outputStream), AVIF_FALSE); } + avifEncoderWriteExtendedColorProperties(outputStream, imageMetadata, ipma, dedup); +} + +static void avifEncoderWriteExtendedColorProperties(avifRWStream * outputStream, + const avifImage * imageMetadata, + struct ipmaArray * ipma, + avifItemPropertyDedup * dedup) +{ + avifRWStream * s = dedup ? &dedup->s : outputStream; // Write Content Light Level Information, if present if (imageMetadata->clli.maxCLL || imageMetadata->clli.maxPALL) { if (dedup) { @@ -2174,10 +2190,10 @@ avifResult avifEncoderWrite(avifEncoder * encoder, const avifImage * image, avif return avifEncoderFinish(encoder, output); } -static void writeConfigBox(avifRWStream * s, avifCodecConfigurationBox * cfg, const char * configPropName) +// Implementation of section 2.3.3. of AV1 Codec ISO Media File Format Binding specification v1.2.0. +// See https://aomediacodec.github.io/av1-isobmff/v1.2.0.html#av1codecconfigurationbox-syntax. +static void writeCodecConfig(avifRWStream * s, const avifCodecConfigurationBox * cfg) { - avifBoxMarker configBox = avifRWStreamWriteBox(s, configPropName, AVIF_BOX_SIZE_TBD); - // unsigned int (1) marker = 1; // unsigned int (7) version = 1; avifRWStreamWriteU8(s, 0x80 | 0x1); @@ -2205,5 +2221,15 @@ static void writeConfigBox(avifRWStream * s, avifCodecConfigurationBox * cfg, co // } avifRWStreamWriteU8(s, 0); + // According to section 2.2.1. of AV1 Image File Format specification v1.1.0, + // there is no need to write any OBU here. + // See https://aomediacodec.github.io/av1-avif/v1.1.0.html#av1-configuration-item-property. + // unsigned int (8) configOBUs[]; +} + +static void writeConfigBox(avifRWStream * s, const avifCodecConfigurationBox * cfg, const char * configPropName) +{ + avifBoxMarker configBox = avifRWStreamWriteBox(s, configPropName, AVIF_BOX_SIZE_TBD); + writeCodecConfig(s, cfg); avifRWStreamFinishBox(s, configBox); }