// Extracts image & alpha data from the given bitstream and then sets wpi.alpha_ // and wpi.img_ appropriately. static WebPMuxError SetAlphaAndImageChunks( const WebPData* const bitstream, int copy_data, WebPMuxImage* const wpi) { int is_lossless = 0; WebPData image, alpha; WebPMuxError err = GetImageData(bitstream, &image, &alpha, &is_lossless); const int image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag; if (err != WEBP_MUX_OK) return err; if (alpha.bytes != NULL) { err = AddDataToChunkList(&alpha, copy_data, kChunks[IDX_ALPHA].tag, &wpi->alpha_); if (err != WEBP_MUX_OK) return err; } return AddDataToChunkList(&image, copy_data, image_tag, &wpi->img_); }
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; }
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; }