Image Sequence Support
* BMFF parser now reads moov box and sample table (stbl), which hold avifs image sequences
* libavif now reads 'avis' brands
* Split avifDecoderRead() into components for image sequences:
* avifDecoderSetSource()
* avifDecoderParse()
* avifDecoderNextImage()
* avifImageCopy()
* avifDecoderReset()
* avifDecoderRead() still exists as a simple single-image path
* Added decoder and image timings for image sequences
* Refactored codec API to not require each codec to maintain per-plane decoder instances
* avifImage can now "not own" its planes and directly point at decoder planes to avoid copies
* aviffuzz attempts to decode all images in source material twice (using avifDecoderReset())
* Switch decoder->quality to explicit [minQuantizer, maxQuantizer], update assoc. constants
* Add examples to README
diff --git a/src/write.c b/src/write.c
index e24765b..8bfced6 100644
--- a/src/write.c
+++ b/src/write.c
@@ -28,7 +28,8 @@
avifEncoder * encoder = (avifEncoder *)avifAlloc(sizeof(avifEncoder));
memset(encoder, 0, sizeof(avifEncoder));
encoder->maxThreads = 1;
- encoder->quality = AVIF_BEST_QUALITY;
+ encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
+ encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
return encoder;
}
@@ -37,6 +38,15 @@
avifFree(encoder);
}
+static avifCodec * avifCodecCreateForEncode()
+{
+#ifdef AVIF_CODEC_AOM
+ return avifCodecCreateAOM();
+#else
+ return NULL;
+#endif
+}
+
avifResult avifEncoderWrite(avifEncoder * encoder, avifImage * image, avifRawData * output)
{
if ((image->depth != 8) && (image->depth != 10) && (image->depth != 12)) {
@@ -46,14 +56,20 @@
avifResult result = AVIF_RESULT_UNKNOWN_ERROR;
avifRawData colorOBU = AVIF_RAW_DATA_EMPTY;
avifRawData alphaOBU = AVIF_RAW_DATA_EMPTY;
- avifCodec * codec = NULL;
+ avifCodec * codec[AVIF_CODEC_PLANES_COUNT];
-#ifdef AVIF_CODEC_AOM
- codec = avifCodecCreateAOM();
-#else
- // Just bail out early, we're not surviving this function without an encoder compiled in
- return AVIF_RESULT_NO_CODEC_AVAILABLE;
-#endif
+ codec[AVIF_CODEC_PLANES_COLOR] = avifCodecCreateForEncode();
+ if (!codec[AVIF_CODEC_PLANES_COLOR]) {
+ // Just bail out early, we're not surviving this function without an encoder compiled in
+ return AVIF_RESULT_NO_CODEC_AVAILABLE;
+ }
+
+ avifBool imageIsOpaque = avifImageIsOpaque(image);
+ if (imageIsOpaque) {
+ codec[AVIF_CODEC_PLANES_ALPHA] = NULL;
+ } else {
+ codec[AVIF_CODEC_PLANES_ALPHA] = avifCodecCreateForEncode();
+ }
avifStream s;
avifStreamStart(&s, output);
@@ -84,16 +100,23 @@
// -----------------------------------------------------------------------
// Encode AV1 OBUs
- avifRawData * alphaOBUPtr = &alphaOBU;
- if (avifImageIsOpaque(image)) {
- alphaOBUPtr = NULL;
- }
+ // avifRawData * alphaOBUPtr = &alphaOBU;
+ // if (avifImageIsOpaque(image)) {
+ // alphaOBUPtr = NULL;
+ // }
- avifResult encodeResult = codec->encodeImage(codec, image, encoder, &colorOBU, alphaOBUPtr);
- if (encodeResult != AVIF_RESULT_OK) {
- result = encodeResult;
+ if (!codec[AVIF_CODEC_PLANES_COLOR]->encodeImage(codec[AVIF_CODEC_PLANES_COLOR], image, encoder, &colorOBU, AVIF_FALSE)) {
+ result = AVIF_RESULT_ENCODE_COLOR_FAILED;
goto writeCleanup;
}
+
+ if (!imageIsOpaque) {
+ if (!codec[AVIF_CODEC_PLANES_ALPHA]->encodeImage(codec[AVIF_CODEC_PLANES_ALPHA], image, encoder, &alphaOBU, AVIF_TRUE)) {
+ result = AVIF_RESULT_ENCODE_ALPHA_FAILED;
+ goto writeCleanup;
+ }
+ }
+
avifBool hasAlpha = (alphaOBU.size > 0) ? AVIF_TRUE : AVIF_FALSE;
// -----------------------------------------------------------------------
@@ -257,7 +280,7 @@
ipmaPush(&ipmaColor, ipcoIndex);
avifCodecConfigurationBox colorConfig;
- codec->getConfigurationBox(codec, AVIF_CODEC_PLANES_COLOR, &colorConfig);
+ codec[AVIF_CODEC_PLANES_COLOR]->getConfigurationBox(codec[AVIF_CODEC_PLANES_COLOR], &colorConfig);
writeConfigBox(&s, &colorConfig);
++ipcoIndex;
ipmaPush(&ipmaColor, ipcoIndex);
@@ -271,7 +294,7 @@
ipmaPush(&ipmaAlpha, ipcoIndex);
avifCodecConfigurationBox alphaConfig;
- codec->getConfigurationBox(codec, AVIF_CODEC_PLANES_ALPHA, &alphaConfig);
+ codec[AVIF_CODEC_PLANES_ALPHA]->getConfigurationBox(codec[AVIF_CODEC_PLANES_ALPHA], &alphaConfig);
writeConfigBox(&s, &alphaConfig);
++ipcoIndex;
ipmaPush(&ipmaAlpha, ipcoIndex);
@@ -353,8 +376,11 @@
result = AVIF_RESULT_OK;
writeCleanup:
- if (codec) {
- avifCodecDestroy(codec);
+ if (codec[AVIF_CODEC_PLANES_COLOR]) {
+ avifCodecDestroy(codec[AVIF_CODEC_PLANES_COLOR]);
+ }
+ if (codec[AVIF_CODEC_PLANES_ALPHA]) {
+ avifCodecDestroy(codec[AVIF_CODEC_PLANES_ALPHA]);
}
avifRawDataFree(&colorOBU);
avifRawDataFree(&alphaOBU);