Store all alpha payloads before color payloads in mdat
Fixes: #287
diff --git a/src/write.c b/src/write.c
index 412d35c..ac7f234 100644
--- a/src/write.c
+++ b/src/write.c
@@ -962,28 +962,40 @@
// Write mdat
avifBoxMarker mdat = avifRWStreamWriteBox(&s, "mdat", AVIF_BOX_SIZE_TBD);
- for (uint32_t itemIndex = 0; itemIndex < encoder->data->items.count; ++itemIndex) {
- avifEncoderItem * item = &encoder->data->items.item[itemIndex];
- if ((item->metadataPayload.size == 0) && (item->encodeOutput->samples.count == 0)) {
- continue;
- }
+ for (uint32_t itemPasses = 0; itemPasses < 2; ++itemPasses) {
+ // Use multiple passes to pack all alpha mdat payloads before color payloads.
+ // See here for the discussion:
+ //
+ // https://github.com/AOMediaCodec/libavif/issues/287
+ //
+ const avifBool alphaPass = (itemPasses == 0);
- uint32_t chunkOffset = (uint32_t)avifRWStreamOffset(&s);
- if (item->encodeOutput->samples.count > 0) {
- for (uint32_t sampleIndex = 0; sampleIndex < item->encodeOutput->samples.count; ++sampleIndex) {
- avifEncodeSample * sample = &item->encodeOutput->samples.sample[sampleIndex];
- avifRWStreamWrite(&s, sample->data.data, sample->data.size);
+ for (uint32_t itemIndex = 0; itemIndex < encoder->data->items.count; ++itemIndex) {
+ avifEncoderItem * item = &encoder->data->items.item[itemIndex];
+ if ((item->metadataPayload.size == 0) && (item->encodeOutput->samples.count == 0)) {
+ continue;
}
- } else {
- avifRWStreamWrite(&s, item->metadataPayload.data, item->metadataPayload.size);
- }
+ if (!alphaPass != !item->alpha) {
+ continue;
+ }
- for (uint32_t fixupIndex = 0; fixupIndex < item->mdatFixups.count; ++fixupIndex) {
- avifOffsetFixup * fixup = &item->mdatFixups.fixup[fixupIndex];
- size_t prevOffset = avifRWStreamOffset(&s);
- avifRWStreamSetOffset(&s, fixup->offset);
- avifRWStreamWriteU32(&s, chunkOffset);
- avifRWStreamSetOffset(&s, prevOffset);
+ uint32_t chunkOffset = (uint32_t)avifRWStreamOffset(&s);
+ if (item->encodeOutput->samples.count > 0) {
+ for (uint32_t sampleIndex = 0; sampleIndex < item->encodeOutput->samples.count; ++sampleIndex) {
+ avifEncodeSample * sample = &item->encodeOutput->samples.sample[sampleIndex];
+ avifRWStreamWrite(&s, sample->data.data, sample->data.size);
+ }
+ } else {
+ avifRWStreamWrite(&s, item->metadataPayload.data, item->metadataPayload.size);
+ }
+
+ for (uint32_t fixupIndex = 0; fixupIndex < item->mdatFixups.count; ++fixupIndex) {
+ avifOffsetFixup * fixup = &item->mdatFixups.fixup[fixupIndex];
+ size_t prevOffset = avifRWStreamOffset(&s);
+ avifRWStreamSetOffset(&s, fixup->offset);
+ avifRWStreamWriteU32(&s, chunkOffset);
+ avifRWStreamSetOffset(&s, prevOffset);
+ }
}
}
avifRWStreamFinishBox(&s, mdat);