WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream, int copy_data) { WebPMuxImage wpi; WebPMuxError err; // Sanity checks. if (mux == NULL || bitstream == NULL || bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } if (mux->images_ != NULL) { // Only one 'simple image' can be added in mux. So, remove present images. DeleteAllImages(&mux->images_); } MuxImageInit(&wpi); err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi); if (err != WEBP_MUX_OK) goto Err; // Add this WebPMuxImage to mux. err = MuxImagePush(&wpi, &mux->images_); if (err != WEBP_MUX_OK) goto Err; // All is well. return WEBP_MUX_OK; Err: // Something bad happened. MuxImageRelease(&wpi); return err; }
WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream, int copy_data) { WebPMuxError err; WebPChunk chunk; WebPMuxImage wpi; WebPData image; WebPData alpha; int is_lossless; int image_tag; if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || bitstream->size_ > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } // If given data is for a whole webp file, // extract only the VP8/VP8L data from it. err = GetImageData(bitstream, &image, &alpha, &is_lossless); if (err != WEBP_MUX_OK) return err; image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; // Delete the existing images. MuxImageDeleteAll(&mux->images_); MuxImageInit(&wpi); if (alpha.bytes_ != NULL) { // Add alpha chunk. ChunkInit(&chunk); err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, &wpi.alpha_, 1); if (err != WEBP_MUX_OK) goto Err; } // Add image chunk. ChunkInit(&chunk); err = ChunkAssignData(&chunk, &image, copy_data, image_tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, &wpi.img_, 1); if (err != WEBP_MUX_OK) goto Err; // Add this image to mux. err = MuxImagePush(&wpi, &mux->images_); if (err != WEBP_MUX_OK) goto Err; // All OK. return WEBP_MUX_OK; Err: // Something bad happened. ChunkRelease(&chunk); MuxImageRelease(&wpi); return err; }
WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data) { WebPMuxImage wpi; WebPMuxError err; int is_frame; const WebPData* const bitstream = &frame->bitstream; // Sanity checks. if (mux == NULL || frame == NULL) return WEBP_MUX_INVALID_ARGUMENT; is_frame = (frame->id == WEBP_CHUNK_ANMF); if (!(is_frame || (frame->id == WEBP_CHUNK_FRGM))) { return WEBP_MUX_INVALID_ARGUMENT; } #ifndef WEBP_EXPERIMENTAL_FEATURES if (frame->id == WEBP_CHUNK_FRGM) { // disabled for now. return WEBP_MUX_INVALID_ARGUMENT; } #endif if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } if (mux->images_ != NULL) { const WebPMuxImage* const image = mux->images_; const uint32_t image_id = (image->header_ != NULL) ? ChunkGetIdFromTag(image->header_->tag_) : WEBP_CHUNK_IMAGE; if (image_id != frame->id) { return WEBP_MUX_INVALID_ARGUMENT; // Conflicting frame types. } } MuxImageInit(&wpi); err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi); if (err != WEBP_MUX_OK) goto Err; assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful. { WebPData frame_frgm; const uint32_t tag = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].tag; WebPMuxFrameInfo tmp = *frame; tmp.x_offset &= ~1; // Snap offsets to even. tmp.y_offset &= ~1; if (!is_frame) { // Reset unused values. tmp.duration = 1; tmp.dispose_method = WEBP_MUX_DISPOSE_NONE; tmp.blend_method = WEBP_MUX_BLEND; } if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET || tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET || (tmp.duration < 0 || tmp.duration >= MAX_DURATION) || tmp.dispose_method != (tmp.dispose_method & 1)) { err = WEBP_MUX_INVALID_ARGUMENT; goto Err; } err = CreateFrameFragmentData(wpi.width_, wpi.height_, &tmp, is_frame, &frame_frgm); if (err != WEBP_MUX_OK) goto Err; // Add frame/fragment chunk (with copy_data = 1). err = AddDataToChunkList(&frame_frgm, 1, tag, &wpi.header_); WebPDataClear(&frame_frgm); // frame_frgm owned by wpi.header_ now. if (err != WEBP_MUX_OK) goto Err; } // Add this WebPMuxImage to mux. err = MuxImagePush(&wpi, &mux->images_); if (err != WEBP_MUX_OK) goto Err; // All is well. return WEBP_MUX_OK; Err: // Something bad happened. MuxImageRelease(&wpi); return err; }
WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) { // Delete the components of wpi. If wpi is NULL this is a noop. WebPMuxImage* const next = MuxImageRelease(wpi); free(wpi); return next; }
static WebPMuxError MuxPushFrameTileInternal( WebPMux* const mux, const WebPData* const bitstream, int x_offset, int y_offset, int duration, int copy_data, uint32_t tag) { WebPChunk chunk; WebPData image; WebPData alpha; WebPMuxImage wpi; WebPMuxError err; WebPData frame_tile; const int is_frame = (tag == kChunks[IDX_FRAME].tag) ? 1 : 0; int is_lossless; int image_tag; // Sanity checks. if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || bitstream->size_ > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET || y_offset < 0 || y_offset >= MAX_POSITION_OFFSET || duration <= 0 || duration > MAX_DURATION) { return WEBP_MUX_INVALID_ARGUMENT; } // Snap offsets to even positions. x_offset &= ~1; y_offset &= ~1; // If given data is for a whole webp file, // extract only the VP8/VP8L data from it. err = GetImageData(bitstream, &image, &alpha, &is_lossless); if (err != WEBP_MUX_OK) return err; image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; WebPDataInit(&frame_tile); ChunkInit(&chunk); MuxImageInit(&wpi); if (alpha.bytes_ != NULL) { // Add alpha chunk. err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, &wpi.alpha_, 1); if (err != WEBP_MUX_OK) goto Err; ChunkInit(&chunk); // chunk owned by wpi.alpha_ now. } // Add image chunk. err = ChunkAssignData(&chunk, &image, copy_data, image_tag); if (err != WEBP_MUX_OK) goto Err; err = ChunkSetNth(&chunk, &wpi.img_, 1); if (err != WEBP_MUX_OK) goto Err; ChunkInit(&chunk); // chunk owned by wpi.img_ now. // Create frame/tile data. err = CreateFrameTileData(&image, x_offset, y_offset, duration, is_lossless, is_frame, &frame_tile); if (err != WEBP_MUX_OK) goto Err; // Add frame/tile chunk (with copy_data = 1). err = ChunkAssignData(&chunk, &frame_tile, 1, tag); if (err != WEBP_MUX_OK) goto Err; WebPDataClear(&frame_tile); err = ChunkSetNth(&chunk, &wpi.header_, 1); if (err != WEBP_MUX_OK) goto Err; ChunkInit(&chunk); // chunk owned by wpi.header_ now. // Add this WebPMuxImage to mux. err = MuxImagePush(&wpi, &mux->images_); if (err != WEBP_MUX_OK) goto Err; // All is well. return WEBP_MUX_OK; Err: // Something bad happened. WebPDataClear(&frame_tile); ChunkRelease(&chunk); MuxImageRelease(&wpi); return err; }
WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* info, int copy_data) { WebPMuxImage wpi; WebPMuxError err; // Sanity checks. if (mux == NULL || info == NULL) return WEBP_MUX_INVALID_ARGUMENT; if (info->id != WEBP_CHUNK_ANMF) return WEBP_MUX_INVALID_ARGUMENT; if (info->bitstream.bytes == NULL || info->bitstream.size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } if (mux->images_ != NULL) { const WebPMuxImage* const image = mux->images_; const uint32_t image_id = (image->header_ != NULL) ? ChunkGetIdFromTag(image->header_->tag_) : WEBP_CHUNK_IMAGE; if (image_id != info->id) { return WEBP_MUX_INVALID_ARGUMENT; // Conflicting frame types. } } MuxImageInit(&wpi); err = SetAlphaAndImageChunks(&info->bitstream, copy_data, &wpi); if (err != WEBP_MUX_OK) goto Err; assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful. { WebPData frame; const uint32_t tag = kChunks[IDX_ANMF].tag; WebPMuxFrameInfo tmp = *info; tmp.x_offset &= ~1; // Snap offsets to even. tmp.y_offset &= ~1; if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET || tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET || (tmp.duration < 0 || tmp.duration >= MAX_DURATION) || tmp.dispose_method != (tmp.dispose_method & 1)) { err = WEBP_MUX_INVALID_ARGUMENT; goto Err; } err = CreateFrameData(wpi.width_, wpi.height_, &tmp, &frame); if (err != WEBP_MUX_OK) goto Err; // Add frame chunk (with copy_data = 1). err = AddDataToChunkList(&frame, 1, tag, &wpi.header_); WebPDataClear(&frame); // frame owned by wpi.header_ now. if (err != WEBP_MUX_OK) goto Err; } // Add this WebPMuxImage to mux. err = MuxImagePush(&wpi, &mux->images_); if (err != WEBP_MUX_OK) goto Err; // All is well. return WEBP_MUX_OK; Err: // Something bad happened. MuxImageRelease(&wpi); return err; }