| 2177 | } |
| 2178 | |
| 2179 | static avifResult avifEncoderWriteMediaDataBox(avifEncoder * encoder, |
| 2180 | avifRWStream * s, |
| 2181 | avifEncoderItemReferenceArray * layeredColorItems, |
| 2182 | avifEncoderItemReferenceArray * layeredAlphaItems) |
| 2183 | { |
| 2184 | encoder->ioStats.colorOBUSize = 0; |
| 2185 | encoder->ioStats.alphaOBUSize = 0; |
| 2186 | encoder->data->gainMapSizeBytes = 0; |
| 2187 | |
| 2188 | avifBoxMarker mdat; |
| 2189 | AVIF_CHECKRES(avifRWStreamWriteBox(s, "mdat", AVIF_BOX_SIZE_TBD, &mdat)); |
| 2190 | const size_t mdatStartOffset = avifRWStreamOffset(s); |
| 2191 | for (uint32_t itemPasses = 0; itemPasses < 3; ++itemPasses) { |
| 2192 | // Use multiple passes to pack in the following order: |
| 2193 | // * Pass 0: metadata (Exif/XMP/gain map metadata) |
| 2194 | // * Pass 1: alpha, gain map image (AV1) |
| 2195 | // * Pass 2: all other item data (AV1 color) |
| 2196 | // |
| 2197 | // See here for the discussion on alpha coming before color: |
| 2198 | // https://github.com/AOMediaCodec/libavif/issues/287 |
| 2199 | // |
| 2200 | // Exif and XMP are packed first as they're required to be fully available |
| 2201 | // by avifDecoderParse() before it returns AVIF_RESULT_OK, unless ignoreXMP |
| 2202 | // and ignoreExif are enabled. |
| 2203 | // |
| 2204 | const avifBool metadataPass = (itemPasses == 0); |
| 2205 | const avifBool alphaAndGainMapPass = (itemPasses == 1); |
| 2206 | |
| 2207 | for (uint32_t itemIndex = 0; itemIndex < encoder->data->items.count; ++itemIndex) { |
| 2208 | avifEncoderItem * item = &encoder->data->items.item[itemIndex]; |
| 2209 | if ((item->metadataPayload.size == 0) && (item->encodeOutput->samples.count == 0)) { |
| 2210 | // this item has nothing for the mdat box |
| 2211 | continue; |
| 2212 | } |
| 2213 | const avifBool isMetadata = !memcmp(item->type, "mime", 4) || !memcmp(item->type, "Exif", 4) || |
| 2214 | !memcmp(item->type, "tmap", 4); |
| 2215 | if (metadataPass != isMetadata) { |
| 2216 | // only process metadata (XMP/Exif) payloads when metadataPass is true |
| 2217 | continue; |
| 2218 | } |
| 2219 | const avifBool isAlpha = avifIsAlpha(item->itemCategory); |
| 2220 | const avifBool isAlphaOrGainMap = isAlpha || item->itemCategory == AVIF_ITEM_GAIN_MAP; |
| 2221 | if (alphaAndGainMapPass != isAlphaOrGainMap) { |
| 2222 | // only process alpha payloads when alphaPass is true |
| 2223 | continue; |
| 2224 | } |
| 2225 | |
| 2226 | if ((encoder->extraLayerCount > 0) && (item->encodeOutput->samples.count > 0)) { |
| 2227 | // Interleave - Pick out AV1 items and interleave them later. |
| 2228 | // We always interleave all AV1 items for layered images. |
| 2229 | AVIF_ASSERT_OR_RETURN(item->encodeOutput->samples.count == item->mdatFixups.count); |
| 2230 | |
| 2231 | avifEncoderItemReference * ref = |
| 2232 | (avifEncoderItemReference *)avifArrayPush(isAlpha ? layeredAlphaItems : layeredColorItems); |
| 2233 | AVIF_CHECKERR(ref != NULL, AVIF_RESULT_OUT_OF_MEMORY); |
| 2234 | *ref = item; |
| 2235 | continue; |
| 2236 | } |
no test coverage detected