Make avifEncoder.headerFormat a flag combination (#2612)
Rename AVIF_HEADER_FULL to AVIF_HEADER_DEFAULT.
Deprecate AVIF_HEADER_FULL.
Rename AVIF_HEADER_REDUCED to AVIF_HEADER_MINI.
Rename AVIF_HEADER_FULL_WITH_EXTENDED_PIXI to
AVIF_HEADER_EXTENDED_PIXI.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8893cd4..1454271 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -32,7 +32,7 @@
is specified. https://github.com/AOMediaCodec/libavif/issues/2365.
* Rename AVIF_ENABLE_EXPERIMENTAL_METAV1 to AVIF_ENABLE_EXPERIMENTAL_MINI and
update the experimental reduced header feature to the latest specification
- draft.
+ draft. Rename AVIF_HEADER_REDUCED to AVIF_HEADER_MINI.
* Update the experimental Sample Transform feature behind the
AVIF_ENABLE_EXPERIMENTAL_SAMPLE_TRANSFORM CMake flag to the latest
specification draft.
@@ -76,6 +76,8 @@
* android_jni: Set threads to 2 instead of CPU count
* Fix overflows when dealing with alpha during YUV/RGB conversions and in
avifRGBImageAllocatePixels().
+* Make avifEncoder.headerFormat a flag combination for future features.
+* Rename AVIF_HEADER_FULL to AVIF_HEADER_DEFAULT. Deprecate AVIF_HEADER_FULL.
## [1.1.1] - 2024-07-30
diff --git a/apps/avifenc.c b/apps/avifenc.c
index e1fba28..2511826 100644
--- a/apps/avifenc.c
+++ b/apps/avifenc.c
@@ -40,7 +40,7 @@
avifBool layered; // manual layered encoding by specifying each layer
int layers;
int speed;
- avifHeaderFormat headerFormat;
+ avifHeaderFormatFlags headerFormat;
avifBool paspPresent;
uint32_t paspValues[2];
@@ -1452,7 +1452,7 @@
settings.layered = AVIF_FALSE;
settings.layers = 0;
settings.speed = 6;
- settings.headerFormat = AVIF_HEADER_FULL;
+ settings.headerFormat = AVIF_HEADER_DEFAULT;
settings.repetitionCount = AVIF_REPETITION_COUNT_INFINITE;
settings.keyframeInterval = 0;
settings.ignoreExif = AVIF_FALSE;
@@ -1558,7 +1558,7 @@
outputFilename = arg;
#if defined(AVIF_ENABLE_EXPERIMENTAL_MINI)
} else if (!strcmp(arg, "--mini")) {
- settings.headerFormat = AVIF_HEADER_REDUCED;
+ settings.headerFormat |= AVIF_HEADER_MINI;
#endif // AVIF_ENABLE_EXPERIMENTAL_MINI
} else if (!strcmp(arg, "-d") || !strcmp(arg, "--depth")) {
NEXTARG();
diff --git a/include/avif/avif.h b/include/avif/avif.h
index c0cc018..7f0f101 100644
--- a/include/avif/avif.h
+++ b/include/avif/avif.h
@@ -210,22 +210,29 @@
// ---------------------------------------------------------------------------
// avifHeaderFormat
+// Bit flag for selecting container strategies when encoding an image.
typedef enum avifHeaderFormat
{
- // AVIF file with an "avif" brand, a MetaBox and all its required boxes for maximum compatibility.
- AVIF_HEADER_FULL,
+ AVIF_HEADER_DEFAULT = 0x0,
#if defined(AVIF_ENABLE_EXPERIMENTAL_MINI)
// AVIF file with a "mif3" brand and a MinimizedImageBox to reduce the encoded file size.
// This is based on the w24144 "Low-overhead image file format" MPEG proposal for HEIF.
// WARNING: Experimental feature. Produces files that are incompatible with older decoders.
- AVIF_HEADER_REDUCED,
+ // If this flag is omitted or if MinimizedImageBox cannot be used at encoding, falls back to an
+ // AVIF file with an "avif" brand, a MetaBox and all its required boxes for maximum compatibility.
+ AVIF_HEADER_MINI = 0x1,
#endif
#if defined(AVIF_ENABLE_EXPERIMENTAL_EXTENDED_PIXI)
// Use the full syntax of the PixelInformationProperty from HEIF 3rd edition Amendment 2.
// WARNING: Experimental feature. Produces files that may be incompatible with older decoders.
- AVIF_HEADER_FULL_WITH_EXTENDED_PIXI,
+ // Only relevant if a MetaBox is used. No effect if a MinimizedImageBox is used.
+ AVIF_HEADER_EXTENDED_PIXI = 0x2,
#endif
+
+ // Deprecated.
+ AVIF_HEADER_FULL = AVIF_HEADER_DEFAULT,
} avifHeaderFormat;
+typedef int avifHeaderFormatFlags;
// ---------------------------------------------------------------------------
// avifROData/avifRWData: Generic raw memory storage
@@ -1571,8 +1578,8 @@
// Version 1.0.0 ends here.
// --------------------------------------------------------------------------------------------
- // Defaults to AVIF_HEADER_FULL
- avifHeaderFormat headerFormat; // Changeable encoder setting.
+ // Defaults to AVIF_HEADER_DEFAULT
+ avifHeaderFormatFlags headerFormat; // Changeable encoder setting.
// Version 1.1.0 ends here.
// --------------------------------------------------------------------------------------------
diff --git a/src/write.c b/src/write.c
index ed85927..346634e 100644
--- a/src/write.c
+++ b/src/write.c
@@ -493,7 +493,7 @@
avifEncoderDestroy(encoder);
return NULL;
}
- encoder->headerFormat = AVIF_HEADER_FULL;
+ encoder->headerFormat = AVIF_HEADER_DEFAULT;
#if defined(AVIF_ENABLE_EXPERIMENTAL_SAMPLE_TRANSFORM)
encoder->sampleTransformRecipe = AVIF_SAMPLE_TRANSFORM_NONE;
#endif
@@ -2986,7 +2986,7 @@
avifBoxMarker pixi;
uint32_t flags = 0;
#if defined(AVIF_ENABLE_EXPERIMENTAL_EXTENDED_PIXI)
- if (encoder->headerFormat == AVIF_HEADER_FULL_WITH_EXTENDED_PIXI) {
+ if (encoder->headerFormat & AVIF_HEADER_EXTENDED_PIXI) {
flags |= 1;
}
#endif // AVIF_ENABLE_EXPERIMENTAL_EXTENDED_PIXI
@@ -3209,7 +3209,7 @@
#if defined(AVIF_ENABLE_EXPERIMENTAL_MINI)
// Decide whether to go for a reduced MinimizedImageBox or a full regular MetaBox.
- if ((encoder->headerFormat == AVIF_HEADER_REDUCED) && avifEncoderIsMiniCompatible(encoder)) {
+ if ((encoder->headerFormat & AVIF_HEADER_MINI) && avifEncoderIsMiniCompatible(encoder)) {
AVIF_CHECKRES(avifEncoderWriteFileTypeBoxAndMiniBox(encoder, output));
return AVIF_RESULT_OK;
}
diff --git a/tests/gtest/avifavmminitest.cc b/tests/gtest/avifavmminitest.cc
index 5972c53..e2a11ce 100644
--- a/tests/gtest/avifavmminitest.cc
+++ b/tests/gtest/avifavmminitest.cc
@@ -30,7 +30,7 @@
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
encoder->codecChoice = AVIF_CODEC_CHOICE_AVM;
- encoder->headerFormat = AVIF_HEADER_REDUCED;
+ encoder->headerFormat = AVIF_HEADER_MINI;
testutil::AvifRwData encoded;
ASSERT_EQ(avifEncoderWrite(encoder.get(), image.get(), &encoded),
AVIF_RESULT_OK);
@@ -99,7 +99,7 @@
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
- encoder->headerFormat = AVIF_HEADER_REDUCED;
+ encoder->headerFormat = AVIF_HEADER_MINI;
testutil::AvifRwData encoded;
ASSERT_EQ(avifEncoderWrite(encoder.get(), image.get(), &encoded),
AVIF_RESULT_OK);
diff --git a/tests/gtest/avifminitest.cc b/tests/gtest/avifminitest.cc
index 777a1f0..32e4620 100644
--- a/tests/gtest/avifminitest.cc
+++ b/tests/gtest/avifminitest.cc
@@ -82,7 +82,7 @@
EncoderPtr encoder(avifEncoderCreate());
ASSERT_NE(encoder, nullptr);
encoder->speed = AVIF_SPEED_FASTEST;
- encoder->headerFormat = AVIF_HEADER_REDUCED;
+ encoder->headerFormat = AVIF_HEADER_MINI;
ASSERT_EQ(avifEncoderWrite(encoder.get(), image.get(), &encoded_mini),
AVIF_RESULT_OK);
diff --git a/tests/gtest/avifpixitest.cc b/tests/gtest/avifpixitest.cc
index 3c1169d..4e94caf 100644
--- a/tests/gtest/avifpixitest.cc
+++ b/tests/gtest/avifpixitest.cc
@@ -31,7 +31,7 @@
EncoderPtr encoder_regular_pixi(avifEncoderCreate());
ASSERT_NE(encoder_regular_pixi, nullptr);
encoder_regular_pixi->speed = AVIF_SPEED_FASTEST;
- encoder_regular_pixi->headerFormat = AVIF_HEADER_FULL;
+ encoder_regular_pixi->headerFormat = AVIF_HEADER_DEFAULT;
ASSERT_EQ(avifEncoderWrite(encoder_regular_pixi.get(), image.get(),
&encoded_regular_pixi),
AVIF_RESULT_OK);
@@ -40,7 +40,7 @@
EncoderPtr encoder_extended_pixi(avifEncoderCreate());
ASSERT_NE(encoder_extended_pixi, nullptr);
encoder_extended_pixi->speed = AVIF_SPEED_FASTEST;
- encoder_extended_pixi->headerFormat = AVIF_HEADER_FULL_WITH_EXTENDED_PIXI;
+ encoder_extended_pixi->headerFormat = AVIF_HEADER_EXTENDED_PIXI;
ASSERT_EQ(avifEncoderWrite(encoder_extended_pixi.get(), image.get(),
&encoded_extended_pixi),
AVIF_RESULT_OK);
@@ -89,6 +89,24 @@
AVIF_CHROMA_SAMPLE_POSITION_VERTICAL);
}
+TEST(AvifHeaderFormatTest, ABI) {
+ // avifEncoder::headerFormat was of type avifHeaderFormat in libavif
+ // version 1.1.1:
+ // https://github.com/AOMediaCodec/libavif/blob/v1.1.1/include/avif/avif.h#L1498
+ // It was later changed to avifHeaderFormatFlags to be able to combine
+ // multiple avifHeaderFormat features. Check that it was not an ABI
+ // incompatible change.
+ EXPECT_EQ(sizeof(avifEncoder::headerFormat), sizeof(avifHeaderFormat));
+
+#if defined(AVIF_ENABLE_EXPERIMENTAL_EXTENDED_PIXI)
+ // Check that the field can be assigned with a combination of flags without
+ // compile errors:
+ EncoderPtr encoder(avifEncoderCreate());
+ ASSERT_NE(encoder, nullptr);
+ encoder->headerFormat = AVIF_HEADER_DEFAULT | AVIF_HEADER_EXTENDED_PIXI;
+#endif // AVIF_ENABLE_EXPERIMENTAL_EXTENDED_PIXI
+}
+
//------------------------------------------------------------------------------
} // namespace