Distribute out and share code populating av01 config box across codecs
diff --git a/src/write.c b/src/write.c
index 23774a1..b9c6447 100644
--- a/src/write.c
+++ b/src/write.c
@@ -21,6 +21,7 @@
 static const size_t alphaURNSize = sizeof(alphaURN);
 
 static avifBool avifImageIsOpaque(avifImage * image);
+static void fillConfigBox(avifCodec * codec, avifImage * image, avifBool alpha);
 static void writeConfigBox(avifRWStream * s, avifCodecConfigurationBox * cfg);
 
 avifEncoder * avifEncoderCreate(void)
@@ -65,6 +66,17 @@
         }
     }
 
+    // -----------------------------------------------------------------------
+    // Pre-fill config boxes based on image (codec can query/update later)
+
+    fillConfigBox(codec[AVIF_CODEC_PLANES_COLOR], image, AVIF_FALSE);
+    if (codec[AVIF_CODEC_PLANES_ALPHA]) {
+        fillConfigBox(codec[AVIF_CODEC_PLANES_ALPHA], image, AVIF_TRUE);
+    }
+
+    // -----------------------------------------------------------------------
+    // Begin write stream
+
     avifRWStream s;
     avifRWStreamStart(&s, output);
 
@@ -273,9 +285,7 @@
             ++ipcoIndex;
             ipmaPush(&ipmaColor, ipcoIndex);
 
-            avifCodecConfigurationBox colorConfig;
-            codec[AVIF_CODEC_PLANES_COLOR]->getConfigurationBox(codec[AVIF_CODEC_PLANES_COLOR], &colorConfig);
-            writeConfigBox(&s, &colorConfig);
+            writeConfigBox(&s, &codec[AVIF_CODEC_PLANES_COLOR]->configBox);
             ++ipcoIndex;
             ipmaPush(&ipmaColor, ipcoIndex);
 
@@ -287,9 +297,7 @@
                 ++ipcoIndex;
                 ipmaPush(&ipmaAlpha, ipcoIndex);
 
-                avifCodecConfigurationBox alphaConfig;
-                codec[AVIF_CODEC_PLANES_ALPHA]->getConfigurationBox(codec[AVIF_CODEC_PLANES_ALPHA], &alphaConfig);
-                writeConfigBox(&s, &alphaConfig);
+                writeConfigBox(&s, &codec[AVIF_CODEC_PLANES_ALPHA]->configBox);
                 ++ipcoIndex;
                 ipmaPush(&ipmaAlpha, ipcoIndex);
 
@@ -409,6 +417,70 @@
     return AVIF_TRUE;
 }
 
+static void fillConfigBox(avifCodec * codec, avifImage * image, avifBool alpha)
+{
+    avifPixelFormatInfo formatInfo;
+    avifGetPixelFormatInfo(image->yuvFormat, &formatInfo);
+
+    // Profile 0.  8-bit and 10-bit 4:2:0 and 4:0:0 only.
+    // Profile 1.  8-bit and 10-bit 4:4:4
+    // Profile 2.  8-bit and 10-bit 4:2:2
+    //            12-bit  4:0:0, 4:2:2 and 4:4:4
+    uint8_t seqProfile = 0;
+    if (image->depth == 12) {
+        // Only seqProfile 2 can handle 12 bit
+        seqProfile = 2;
+    } else {
+        // 8-bit or 10-bit
+
+        if (alpha) {
+            seqProfile = 0;
+        } else {
+            switch (image->yuvFormat) {
+                case AVIF_PIXEL_FORMAT_YUV444:
+                    seqProfile = 1;
+                    break;
+                case AVIF_PIXEL_FORMAT_YUV422:
+                    seqProfile = 2;
+                    break;
+                case AVIF_PIXEL_FORMAT_YUV420:
+                    seqProfile = 0;
+                    break;
+                case AVIF_PIXEL_FORMAT_YV12:
+                    seqProfile = 0;
+                    break;
+                case AVIF_PIXEL_FORMAT_NONE:
+                default:
+                    break;
+            }
+        }
+    }
+
+    // TODO: Choose correct value from Annex A.3 table: https://aomediacodec.github.io/av1-spec/av1-spec.pdf
+    uint8_t seqLevelIdx0 = 31;
+    if ((image->width <= 8192) && (image->height <= 4352) && ((image->width * image->height) <= 8912896)) {
+        // Image is 5.1 compatible
+        seqLevelIdx0 = 13; // 5.1
+    }
+
+    memset(&codec->configBox, 0, sizeof(avifCodecConfigurationBox));
+    codec->configBox.seqProfile = seqProfile;
+    codec->configBox.seqLevelIdx0 = seqLevelIdx0;
+    codec->configBox.seqTier0 = 0;
+    codec->configBox.highBitdepth = (image->depth > 8) ? 1 : 0;
+    codec->configBox.twelveBit = (image->depth == 12) ? 1 : 0;
+    codec->configBox.monochrome = alpha ? 1 : 0;
+    codec->configBox.chromaSubsamplingX = (uint8_t)formatInfo.chromaShiftX;
+    codec->configBox.chromaSubsamplingY = (uint8_t)formatInfo.chromaShiftY;
+
+    // TODO: choose the correct one from below:
+    //   * 0 - CSP_UNKNOWN   Unknown (in this case the source video transfer function must be signaled outside the AV1 bitstream)
+    //   * 1 - CSP_VERTICAL  Horizontally co-located with (0, 0) luma sample, vertical position in the middle between two luma samples
+    //   * 2 - CSP_COLOCATED co-located with (0, 0) luma sample
+    //   * 3 - CSP_RESERVED
+    codec->configBox.chromaSamplePosition = 0;
+}
+
 static void writeConfigBox(avifRWStream * s, avifCodecConfigurationBox * cfg)
 {
     avifBoxMarker av1C = avifRWStreamWriteBox(s, "av1C", -1, 0);