More codec API tuning to allow multiple frame samples to be emitted during encoding
diff --git a/src/write.c b/src/write.c
index 434e95d..989dfe0 100644
--- a/src/write.c
+++ b/src/write.c
@@ -37,8 +37,9 @@
{
uint16_t id;
uint8_t type[4];
- avifCodec * codec; // only present on type==av01
- avifRWData content; // OBU data on av01, metadata payload for Exif/XMP
+ avifCodec * codec; // only present on type==av01
+ avifRWDataArray samples; // AV1 sample data for image sequences
+ avifRWData content; // OBU data on av01 items-based image, metadata payload for Exif/XMP
avifBool alpha;
const char * infeName;
@@ -65,6 +66,7 @@
avifEncoderItem * alphaItem;
uint16_t lastItemID;
uint16_t primaryItemID;
+ uint32_t receivedFrameCount; // incremented on each call to avifEncoderAddImage()
} avifEncoderData;
static avifEncoderData * avifEncoderDataCreate()
@@ -84,6 +86,7 @@
memcpy(item->type, type, sizeof(item->type));
item->infeName = infeName;
item->infeNameSize = infeNameSize;
+ avifArrayCreate(&item->samples, sizeof(avifRWData), 1);
return item;
}
@@ -94,6 +97,10 @@
if (item->codec) {
avifCodecDestroy(item->codec);
}
+ for (uint32_t sampleIndex = 0; sampleIndex < item->samples.count; ++sampleIndex) {
+ avifRWDataFree(&item->samples.raw[sampleIndex]);
+ }
+ avifArrayDestroy(&item->samples);
avifRWDataFree(&item->content);
}
avifImageDestroy(data->imageMetadata);
@@ -238,11 +245,18 @@
for (uint32_t itemIndex = 0; itemIndex < encoder->data->items.count; ++itemIndex) {
avifEncoderItem * item = &encoder->data->items.item[itemIndex];
if (item->codec) {
- if (!item->codec->encodeImage(item->codec, image, encoder, item->alpha)) {
+ avifRWData tmpSampleData = AVIF_DATA_EMPTY;
+ if (!item->codec->encodeImage(item->codec, image, encoder, item->alpha, &tmpSampleData)) {
return item->alpha ? AVIF_RESULT_ENCODE_ALPHA_FAILED : AVIF_RESULT_ENCODE_COLOR_FAILED;
}
+ if (tmpSampleData.data && tmpSampleData.size) {
+ avifRWData * sampleData = (avifRWData *)avifArrayPushPtr(&item->samples);
+ memcpy(sampleData, &tmpSampleData, sizeof(avifRWData));
+ }
}
}
+
+ ++encoder->data->receivedFrameCount;
return AVIF_RESULT_OK;
}
@@ -258,18 +272,41 @@
for (uint32_t itemIndex = 0; itemIndex < encoder->data->items.count; ++itemIndex) {
avifEncoderItem * item = &encoder->data->items.item[itemIndex];
if (item->codec) {
- if (!item->codec->encodeFinish(item->codec, &item->content)) {
+ avifRWData tmpSampleData = AVIF_DATA_EMPTY;
+ if (!item->codec->encodeFinish(item->codec, &tmpSampleData)) {
+ return item->alpha ? AVIF_RESULT_ENCODE_ALPHA_FAILED : AVIF_RESULT_ENCODE_COLOR_FAILED;
+ }
+ if (tmpSampleData.data && tmpSampleData.size) {
+ avifRWData * sampleData = (avifRWData *)avifArrayPushPtr(&item->samples);
+ memcpy(sampleData, &tmpSampleData, sizeof(avifRWData));
+ }
+
+ if (item->samples.count != encoder->data->receivedFrameCount) {
return item->alpha ? AVIF_RESULT_ENCODE_ALPHA_FAILED : AVIF_RESULT_ENCODE_COLOR_FAILED;
}
+ size_t obuSize = 0;
+ for (uint32_t sampleIndex = 0; sampleIndex < item->samples.count; ++sampleIndex) {
+ obuSize += item->samples.raw[sampleIndex].size;
+ }
if (item->alpha) {
- encoder->ioStats.alphaOBUSize = item->content.size;
+ encoder->ioStats.alphaOBUSize = obuSize;
} else {
- encoder->ioStats.colorOBUSize = item->content.size;
+ encoder->ioStats.colorOBUSize = obuSize;
+ }
+
+ if (item->samples.count == 1) {
+ // Detected a single image (non-sequence). Hand over the only sample to item->content
+ // so that the image is encoded with items instead of tracks.
+ memcpy(&item->content, &item->samples.raw[0], sizeof(avifRWData));
+ memset(&item->samples.raw[0], 0, sizeof(avifRWData));
+ item->samples.count = 0;
}
}
}
+ // TODO: If encoder->data->receivedFrameCount > 1, encode with tracks instead of items
+
// -----------------------------------------------------------------------
// Begin write stream