Lots of fixes to ftyp, swapping meta and mdat ordering on write for streaming friendliness
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9baf838..1b1f59f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md
@@ -5,6 +5,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- `ftyp` - Change `major_brand` to `avif` +- `ftyp` - Reorder `compatible_brands`, add `MA1A` or `MA1B` when appropriate +- Write `meta` box before `mdat` box for streaming friendliness ## [0.1.2] - 2019-04-18 ### Added
diff --git a/include/avif/internal.h b/include/avif/internal.h index fe45bf4..d2cdd5f 100644 --- a/include/avif/internal.h +++ b/include/avif/internal.h
@@ -129,6 +129,8 @@ // Read avifBool avifStreamHasBytesLeft(avifStream * stream, size_t byteCount); size_t avifStreamRemainingBytes(avifStream * stream); +size_t avifStreamOffset(avifStream * stream); +void avifStreamSetOffset(avifStream * stream, size_t offset); avifBool avifStreamSkip(avifStream * stream, size_t byteCount); avifBool avifStreamRead(avifStream * stream, uint8_t * data, size_t size); avifBool avifStreamReadU16(avifStream * stream, uint16_t * v);
diff --git a/src/stream.c b/src/stream.c index 0908c8f..52a22ae 100644 --- a/src/stream.c +++ b/src/stream.c
@@ -29,6 +29,19 @@ return stream->raw->size - stream->offset; } +size_t avifStreamOffset(avifStream * stream) +{ + return stream->offset; +} + +void avifStreamSetOffset(avifStream * stream, size_t offset) +{ + stream->offset = offset; + if (stream->offset > stream->raw->size) { + stream->offset = stream->raw->size; + } +} + avifBool avifStreamSkip(avifStream * stream, size_t byteCount) { if (!avifStreamHasBytesLeft(stream, byteCount)) {
diff --git a/src/write.c b/src/write.c index 700867e..0d9eeab 100644 --- a/src/write.c +++ b/src/write.c
@@ -78,24 +78,21 @@ // Write ftyp avifBoxMarker ftyp = avifStreamWriteBox(&s, "ftyp", -1, 0); - avifStreamWriteChars(&s, "mif1", 4); // unsigned int(32) major_brand; + avifStreamWriteChars(&s, "avif", 4); // unsigned int(32) major_brand; avifStreamWriteU32(&s, 0); // unsigned int(32) minor_version; - avifStreamWriteChars(&s, "mif1", 4); // unsigned int(32) compatible_brands[]; - avifStreamWriteChars(&s, "avif", 4); // ... compatible_brands[] + avifStreamWriteChars(&s, "avif", 4); // unsigned int(32) compatible_brands[]; + avifStreamWriteChars(&s, "mif1", 4); // ... compatible_brands[] avifStreamWriteChars(&s, "miaf", 4); // ... compatible_brands[] + if ((image->depth == 8) || (image->depth == 10)) { + if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV420) { + avifStreamWriteChars(&s, "MA1B", 4); // ... compatible_brands[] + } else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV444) { + avifStreamWriteChars(&s, "MA1A", 4); // ... compatible_brands[] + } + } avifStreamFinishBox(&s, ftyp); // ----------------------------------------------------------------------- - // Write mdat - - avifBoxMarker mdat = avifStreamWriteBox(&s, "mdat", -1, 0); - uint32_t colorOBUOffset = (uint32_t)s.offset; - avifStreamWrite(&s, colorOBU.data, colorOBU.size); - uint32_t alphaOBUOffset = (uint32_t)s.offset; - avifStreamWrite(&s, alphaOBU.data, alphaOBU.size); - avifStreamFinishBox(&s, mdat); - - // ----------------------------------------------------------------------- // Start meta avifBoxMarker meta = avifStreamWriteBox(&s, "meta", 0, 0); @@ -119,6 +116,10 @@ // ----------------------------------------------------------------------- // Write iloc + // Remember where we want to store the offsets to the mdat OBU offsets to adjust them later. + size_t colorOBUOffsetOffset = 0; + size_t alphaOBUOffsetOffset = 0; + avifBoxMarker iloc = avifStreamWriteBox(&s, "iloc", 0, 0); // iloc header @@ -131,14 +132,16 @@ avifStreamWriteU16(&s, 1); // unsigned int(16) item_ID; avifStreamWriteU16(&s, 0); // unsigned int(16) data_reference_index; avifStreamWriteU16(&s, 1); // unsigned int(16) extent_count; - avifStreamWriteU32(&s, colorOBUOffset); // unsigned int(offset_size*8) extent_offset; + colorOBUOffsetOffset = avifStreamOffset(&s); // + avifStreamWriteU32(&s, 0 /* set later */); // unsigned int(offset_size*8) extent_offset; avifStreamWriteU32(&s, (uint32_t)colorOBU.size); // unsigned int(length_size*8) extent_length; if (hasAlpha) { avifStreamWriteU16(&s, 2); // unsigned int(16) item_ID; avifStreamWriteU16(&s, 0); // unsigned int(16) data_reference_index; avifStreamWriteU16(&s, 1); // unsigned int(16) extent_count; - avifStreamWriteU32(&s, alphaOBUOffset); // unsigned int(offset_size*8) extent_offset; + alphaOBUOffsetOffset = avifStreamOffset(&s); // + avifStreamWriteU32(&s, 0 /* set later */); // unsigned int(offset_size*8) extent_offset; avifStreamWriteU32(&s, (uint32_t)alphaOBU.size); // unsigned int(length_size*8) extent_length; } @@ -281,9 +284,36 @@ avifStreamFinishBox(&s, iprp); // ----------------------------------------------------------------------- - // Finish up stream + // Finish meta box avifStreamFinishBox(&s, meta); + + // ----------------------------------------------------------------------- + // Write mdat + + avifBoxMarker mdat = avifStreamWriteBox(&s, "mdat", -1, 0); + uint32_t colorOBUOffset = (uint32_t)s.offset; + avifStreamWrite(&s, colorOBU.data, colorOBU.size); + uint32_t alphaOBUOffset = (uint32_t)s.offset; + avifStreamWrite(&s, alphaOBU.data, alphaOBU.size); + avifStreamFinishBox(&s, mdat); + + // ----------------------------------------------------------------------- + // Finish up stream + + // Set offsets needed in meta box based on where we eventually wrote mdat + size_t prevOffset = avifStreamOffset(&s); + if (colorOBUOffsetOffset != 0) { + avifStreamSetOffset(&s, colorOBUOffsetOffset); + avifStreamWriteU32(&s, colorOBUOffset); + } + if (alphaOBUOffsetOffset != 0) { + avifStreamSetOffset(&s, alphaOBUOffsetOffset); + avifStreamWriteU32(&s, alphaOBUOffset); + } + avifStreamSetOffset(&s, prevOffset); + + // Close write stream avifStreamFinishWrite(&s); // -----------------------------------------------------------------------