Keep track of image timing (with a default/fallback) during encoding
diff --git a/src/write.c b/src/write.c
index 67aec96..2e6890c 100644
--- a/src/write.c
+++ b/src/write.c
@@ -86,17 +86,26 @@
 AVIF_ARRAY_DECLARE(avifEncoderItemArray, avifEncoderItem, item);
 
 // ---------------------------------------------------------------------------
+// avifEncoderFrame
+
+typedef struct avifEncoderFrame
+{
+    avifImageTiming timing;
+} avifEncoderFrame;
+AVIF_ARRAY_DECLARE(avifEncoderFrameArray, avifEncoderFrame, frame);
+
+// ---------------------------------------------------------------------------
 // avifEncoderData
 
 typedef struct avifEncoderData
 {
     avifEncoderItemArray items;
+    avifEncoderFrameArray frames;
     avifImage * imageMetadata;
     avifEncoderItem * colorItem;
     avifEncoderItem * alphaItem;
     uint16_t lastItemID;
     uint16_t primaryItemID;
-    uint32_t receivedFrameCount; // incremented on each call to avifEncoderAddImage()
 } avifEncoderData;
 
 static avifEncoderData * avifEncoderDataCreate()
@@ -105,6 +114,7 @@
     memset(data, 0, sizeof(avifEncoderData));
     data->imageMetadata = avifImageCreateEmpty();
     avifArrayCreate(&data->items, sizeof(avifEncoderItem), 8);
+    avifArrayCreate(&data->frames, sizeof(avifEncoderFrame), 1);
     return data;
 }
 
@@ -132,6 +142,7 @@
     }
     avifImageDestroy(data->imageMetadata);
     avifArrayDestroy(&data->items);
+    avifArrayDestroy(&data->frames);
     avifFree(data);
 }
 
@@ -150,6 +161,11 @@
     encoder->tileColsLog2 = 0;
     encoder->speed = AVIF_SPEED_DEFAULT;
     encoder->data = avifEncoderDataCreate();
+    encoder->imageTiming.timescale = 1;
+    encoder->imageTiming.pts = 0;
+    encoder->imageTiming.ptsInTimescales = 0;
+    encoder->imageTiming.duration = 1;
+    encoder->imageTiming.durationInTimescales = 1;
     return encoder;
 }
 
@@ -159,7 +175,7 @@
     avifFree(encoder);
 }
 
-static avifResult avifEncoderAddImage(avifEncoder * encoder, const avifImage * image)
+static avifResult avifEncoderAddImage(avifEncoder * encoder, const avifImage * image, const avifImageTiming * imageTiming)
 {
     // -----------------------------------------------------------------------
     // Validate image
@@ -178,6 +194,10 @@
 
     // -----------------------------------------------------------------------
 
+    if (imageTiming == NULL) {
+        imageTiming = &encoder->imageTiming;
+    }
+
     if (encoder->data->items.count == 0) {
         // Make a copy of the first image's metadata (sans pixels) for future writing/validation
         avifImageCopy(encoder->data->imageMetadata, image, 0);
@@ -278,7 +298,8 @@
         }
     }
 
-    ++encoder->data->receivedFrameCount;
+    avifEncoderFrame * frame = (avifEncoderFrame *)avifArrayPushPtr(&encoder->data->frames);
+    memcpy(&frame->timing, imageTiming, sizeof(avifImageTiming));
     return AVIF_RESULT_OK;
 }
 
@@ -298,7 +319,7 @@
                 return item->alpha ? AVIF_RESULT_ENCODE_ALPHA_FAILED : AVIF_RESULT_ENCODE_COLOR_FAILED;
             }
 
-            if (item->encodeOutput->samples.count != encoder->data->receivedFrameCount) {
+            if (item->encodeOutput->samples.count != encoder->data->frames.count) {
                 return item->alpha ? AVIF_RESULT_ENCODE_ALPHA_FAILED : AVIF_RESULT_ENCODE_COLOR_FAILED;
             }
 
@@ -322,7 +343,7 @@
         }
     }
 
-    if (encoder->data->receivedFrameCount > 1) {
+    if (encoder->data->frames.count > 1) {
         return avifEncoderWriteTracks(encoder, output);
     }
     return avifEncoderWriteItems(encoder, output);
@@ -619,7 +640,7 @@
 
 avifResult avifEncoderWrite(avifEncoder * encoder, const avifImage * image, avifRWData * output)
 {
-    avifResult addImageResult = avifEncoderAddImage(encoder, image);
+    avifResult addImageResult = avifEncoderAddImage(encoder, image, NULL);
     if (addImageResult != AVIF_RESULT_OK) {
         return addImageResult;
     }