Skip to content

Commit

Permalink
Split and document avifParseCodecConfiguration()
Browse files Browse the repository at this point in the history
The related AV1-ISOBMFF section also uses two function bodies.
Mirror the changes of read.c to write.c.
  • Loading branch information
y-guyon authored Aug 11, 2023
1 parent 9d81bcd commit fa11395
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 44 deletions.
55 changes: 39 additions & 16 deletions src/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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[10];
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]");
Expand Down Expand Up @@ -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] with item_type %.4s has an invalid item ID [%u]", s.diagContext, itemType, itemID);
return AVIF_FALSE;
}

Expand Down Expand Up @@ -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;
}
Expand Down
83 changes: 55 additions & 28 deletions src/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -536,6 +537,13 @@ 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 * dedupStream,
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
Expand Down Expand Up @@ -590,15 +598,24 @@ static void avifEncoderWriteColorProperties(avifRWStream * outputStream,
ipmaPush(ipma, avifItemPropertyDedupFinish(dedup, outputStream), AVIF_FALSE);
}

avifEncoderWriteExtendedColorProperties(s, outputStream, imageMetadata, ipma, dedup);
}

static void avifEncoderWriteExtendedColorProperties(avifRWStream * dedupStream,
avifRWStream * outputStream,
const avifImage * imageMetadata,
struct ipmaArray * ipma,
avifItemPropertyDedup * dedup)
{
// Write Content Light Level Information, if present
if (imageMetadata->clli.maxCLL || imageMetadata->clli.maxPALL) {
if (dedup) {
avifItemPropertyDedupStart(dedup);
}
avifBoxMarker clli = avifRWStreamWriteBox(s, "clli", AVIF_BOX_SIZE_TBD);
avifRWStreamWriteU16(s, imageMetadata->clli.maxCLL); // unsigned int(16) max_content_light_level;
avifRWStreamWriteU16(s, imageMetadata->clli.maxPALL); // unsigned int(16) max_pic_average_light_level;
avifRWStreamFinishBox(s, clli);
avifBoxMarker clli = avifRWStreamWriteBox(dedupStream, "clli", AVIF_BOX_SIZE_TBD);
avifRWStreamWriteU16(dedupStream, imageMetadata->clli.maxCLL); // unsigned int(16) max_content_light_level;
avifRWStreamWriteU16(dedupStream, imageMetadata->clli.maxPALL); // unsigned int(16) max_pic_average_light_level;
avifRWStreamFinishBox(dedupStream, clli);
if (dedup) {
ipmaPush(ipma, avifItemPropertyDedupFinish(dedup, outputStream), AVIF_FALSE);
}
Expand All @@ -609,10 +626,10 @@ static void avifEncoderWriteColorProperties(avifRWStream * outputStream,
if (dedup) {
avifItemPropertyDedupStart(dedup);
}
avifBoxMarker pasp = avifRWStreamWriteBox(s, "pasp", AVIF_BOX_SIZE_TBD);
avifRWStreamWriteU32(s, imageMetadata->pasp.hSpacing); // unsigned int(32) hSpacing;
avifRWStreamWriteU32(s, imageMetadata->pasp.vSpacing); // unsigned int(32) vSpacing;
avifRWStreamFinishBox(s, pasp);
avifBoxMarker pasp = avifRWStreamWriteBox(dedupStream, "pasp", AVIF_BOX_SIZE_TBD);
avifRWStreamWriteU32(dedupStream, imageMetadata->pasp.hSpacing); // unsigned int(32) hSpacing;
avifRWStreamWriteU32(dedupStream, imageMetadata->pasp.vSpacing); // unsigned int(32) vSpacing;
avifRWStreamFinishBox(dedupStream, pasp);
if (dedup) {
ipmaPush(ipma, avifItemPropertyDedupFinish(dedup, outputStream), AVIF_FALSE);
}
Expand All @@ -621,16 +638,16 @@ static void avifEncoderWriteColorProperties(avifRWStream * outputStream,
if (dedup) {
avifItemPropertyDedupStart(dedup);
}
avifBoxMarker clap = avifRWStreamWriteBox(s, "clap", AVIF_BOX_SIZE_TBD);
avifRWStreamWriteU32(s, imageMetadata->clap.widthN); // unsigned int(32) cleanApertureWidthN;
avifRWStreamWriteU32(s, imageMetadata->clap.widthD); // unsigned int(32) cleanApertureWidthD;
avifRWStreamWriteU32(s, imageMetadata->clap.heightN); // unsigned int(32) cleanApertureHeightN;
avifRWStreamWriteU32(s, imageMetadata->clap.heightD); // unsigned int(32) cleanApertureHeightD;
avifRWStreamWriteU32(s, imageMetadata->clap.horizOffN); // unsigned int(32) horizOffN;
avifRWStreamWriteU32(s, imageMetadata->clap.horizOffD); // unsigned int(32) horizOffD;
avifRWStreamWriteU32(s, imageMetadata->clap.vertOffN); // unsigned int(32) vertOffN;
avifRWStreamWriteU32(s, imageMetadata->clap.vertOffD); // unsigned int(32) vertOffD;
avifRWStreamFinishBox(s, clap);
avifBoxMarker clap = avifRWStreamWriteBox(dedupStream, "clap", AVIF_BOX_SIZE_TBD);
avifRWStreamWriteU32(dedupStream, imageMetadata->clap.widthN); // unsigned int(32) cleanApertureWidthN;
avifRWStreamWriteU32(dedupStream, imageMetadata->clap.widthD); // unsigned int(32) cleanApertureWidthD;
avifRWStreamWriteU32(dedupStream, imageMetadata->clap.heightN); // unsigned int(32) cleanApertureHeightN;
avifRWStreamWriteU32(dedupStream, imageMetadata->clap.heightD); // unsigned int(32) cleanApertureHeightD;
avifRWStreamWriteU32(dedupStream, imageMetadata->clap.horizOffN); // unsigned int(32) horizOffN;
avifRWStreamWriteU32(dedupStream, imageMetadata->clap.horizOffD); // unsigned int(32) horizOffD;
avifRWStreamWriteU32(dedupStream, imageMetadata->clap.vertOffN); // unsigned int(32) vertOffN;
avifRWStreamWriteU32(dedupStream, imageMetadata->clap.vertOffD); // unsigned int(32) vertOffD;
avifRWStreamFinishBox(dedupStream, clap);
if (dedup) {
ipmaPush(ipma, avifItemPropertyDedupFinish(dedup, outputStream), AVIF_TRUE);
}
Expand All @@ -639,10 +656,10 @@ static void avifEncoderWriteColorProperties(avifRWStream * outputStream,
if (dedup) {
avifItemPropertyDedupStart(dedup);
}
avifBoxMarker irot = avifRWStreamWriteBox(s, "irot", AVIF_BOX_SIZE_TBD);
avifBoxMarker irot = avifRWStreamWriteBox(dedupStream, "irot", AVIF_BOX_SIZE_TBD);
uint8_t angle = imageMetadata->irot.angle & 0x3;
avifRWStreamWrite(s, &angle, 1); // unsigned int (6) reserved = 0; unsigned int (2) angle;
avifRWStreamFinishBox(s, irot);
avifRWStreamWrite(dedupStream, &angle, 1); // unsigned int (6) reserved = 0; unsigned int (2) angle;
avifRWStreamFinishBox(dedupStream, irot);
if (dedup) {
ipmaPush(ipma, avifItemPropertyDedupFinish(dedup, outputStream), AVIF_TRUE);
}
Expand All @@ -651,10 +668,10 @@ static void avifEncoderWriteColorProperties(avifRWStream * outputStream,
if (dedup) {
avifItemPropertyDedupStart(dedup);
}
avifBoxMarker imir = avifRWStreamWriteBox(s, "imir", AVIF_BOX_SIZE_TBD);
avifBoxMarker imir = avifRWStreamWriteBox(dedupStream, "imir", AVIF_BOX_SIZE_TBD);
uint8_t mode = imageMetadata->imir.mode & 0x1;
avifRWStreamWrite(s, &mode, 1); // unsigned int (7) reserved = 0; unsigned int (1) mode;
avifRWStreamFinishBox(s, imir);
avifRWStreamWrite(dedupStream, &mode, 1); // unsigned int (7) reserved = 0; unsigned int (1) mode;
avifRWStreamFinishBox(dedupStream, imir);
if (dedup) {
ipmaPush(ipma, avifItemPropertyDedupFinish(dedup, outputStream), AVIF_TRUE);
}
Expand Down Expand Up @@ -2174,10 +2191,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);
Expand Down Expand Up @@ -2205,5 +2222,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);
}

0 comments on commit fa11395

Please sign in to comment.