// Assemble a single image WebP bitstream from 'wpi'. static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, WebPData* const bitstream) { uint8_t* dst; // Allocate data. const int need_vp8x = (wpi->alpha_ != NULL); const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0; const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0; // Note: No need to output ANMF/FRGM chunk for a single image. const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size + ChunkDiskSize(wpi->img_); uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size); if (data == NULL) return WEBP_MUX_MEMORY_ERROR; // Main RIFF header. dst = MuxEmitRiffHeader(data, size); if (need_vp8x) { dst = EmitVP8XChunk(dst, wpi->width_, wpi->height_, ALPHA_FLAG); // VP8X. dst = ChunkListEmit(wpi->alpha_, dst); // ALPH. } // Bitstream. dst = ChunkListEmit(wpi->img_, dst); assert(dst == data + size); // Output. bitstream->bytes = data; bitstream->size = size; return WEBP_MUX_OK; }
uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) { // Ordering of chunks to be emitted is strictly as follows: // 1. ANMF/FRGM chunk (if present). // 2. ALPH chunk (if present). // 3. VP8/VP8L chunk. assert(wpi); if (wpi->header_ != NULL) { dst = ChunkEmitSpecial(wpi->header_, MuxImageDiskSize(wpi), dst); } if (wpi->alpha_ != NULL) dst = ChunkEmit(wpi->alpha_, dst); if (wpi->img_ != NULL) dst = ChunkEmit(wpi->img_, dst); if (wpi->unknown_ != NULL) dst = ChunkListEmit(wpi->unknown_, dst); return dst; }
WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { size_t size = 0; uint8_t* data = NULL; uint8_t* dst = NULL; WebPMuxError err; if (assembled_data == NULL) { return WEBP_MUX_INVALID_ARGUMENT; } // Clean up returned data, in case something goes wrong. memset(assembled_data, 0, sizeof(*assembled_data)); if (mux == NULL) { return WEBP_MUX_INVALID_ARGUMENT; } // Finalize mux. err = MuxCleanup(mux); if (err != WEBP_MUX_OK) return err; err = CreateVP8XChunk(mux); if (err != WEBP_MUX_OK) return err; // Allocate data. size = ChunkListDiskSize(mux->vp8x_) + ChunkListDiskSize(mux->iccp_) + ChunkListDiskSize(mux->anim_) + ImageListDiskSize(mux->images_) + ChunkListDiskSize(mux->exif_) + ChunkListDiskSize(mux->xmp_) + ChunkListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE; data = (uint8_t*)WebPSafeMalloc(1ULL, size); if (data == NULL) return WEBP_MUX_MEMORY_ERROR; // Emit header & chunks. dst = MuxEmitRiffHeader(data, size); dst = ChunkListEmit(mux->vp8x_, dst); dst = ChunkListEmit(mux->iccp_, dst); dst = ChunkListEmit(mux->anim_, dst); dst = ImageListEmit(mux->images_, dst); dst = ChunkListEmit(mux->exif_, dst); dst = ChunkListEmit(mux->xmp_, dst); dst = ChunkListEmit(mux->unknown_, dst); assert(dst == data + size); // Validate mux. err = MuxValidate(mux); if (err != WEBP_MUX_OK) { WebPSafeFree(data); data = NULL; size = 0; } // Finalize data. assembled_data->bytes = data; assembled_data->size = size; return err; }
WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { size_t size = 0; uint8_t* data = NULL; uint8_t* dst = NULL; int num_frames; int num_loop_chunks; WebPMuxError err; if (mux == NULL || assembled_data == NULL) { return WEBP_MUX_INVALID_ARGUMENT; } // Remove LOOP chunk if unnecessary. err = WebPMuxNumChunks(mux, kChunks[IDX_LOOP].id, &num_loop_chunks); if (err != WEBP_MUX_OK) return err; if (num_loop_chunks >= 1) { err = WebPMuxNumChunks(mux, kChunks[IDX_FRAME].id, &num_frames); if (err != WEBP_MUX_OK) return err; if (num_frames == 0) { err = DeleteLoopCount(mux); if (err != WEBP_MUX_OK) return err; } } // Create VP8X chunk. err = CreateVP8XChunk(mux); if (err != WEBP_MUX_OK) return err; // Allocate data. size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_) + ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_) + ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE; data = (uint8_t*)malloc(size); if (data == NULL) return WEBP_MUX_MEMORY_ERROR; // Emit header & chunks. dst = MuxEmitRiffHeader(data, size); dst = ChunkListEmit(mux->vp8x_, dst); dst = ChunkListEmit(mux->iccp_, dst); dst = ChunkListEmit(mux->loop_, dst); dst = MuxImageListEmit(mux->images_, dst); dst = ChunkListEmit(mux->meta_, dst); dst = ChunkListEmit(mux->unknown_, dst); assert(dst == data + size); // Validate mux. err = MuxValidate(mux); if (err != WEBP_MUX_OK) { free(data); data = NULL; size = 0; } // Finalize. assembled_data->bytes_ = data; assembled_data->size_ = size; return err; }