mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-31 02:15:42 +01:00 
			
		
		
		
	Mux API change:
Create common APIs for image, frame and tile. Change-Id: I709ad752133094bd5bc89dd9c832ff79802aac68
This commit is contained in:
		| @@ -94,7 +94,7 @@ Example#2 (pseudo code): Get image & color profile data from a WebP file. | ||||
|   int copy_data = 0; | ||||
|   // ... (Read data from file). | ||||
|   WebPMux* mux = WebPMuxCreate(&data, copy_data); | ||||
|   WebPMuxGetImage(mux, &image); | ||||
|   WebPMuxGetFrame(mux, 1, &image); | ||||
|   // ... (Consume image; e.g. call WebPDecode() to decode the data). | ||||
|   WebPMuxGetChunk(mux, "ICCP", &icc_profile); | ||||
|   // ... (Consume icc_profile). | ||||
|   | ||||
| @@ -142,6 +142,12 @@ static int IsNotCompatible(int count1, int count2) { | ||||
|     return err;                                                      \ | ||||
|   } | ||||
|  | ||||
| #define RETURN_IF_ERROR3(ERR_MSG, FORMAT_STR1, FORMAT_STR2)          \ | ||||
|   if (err != WEBP_MUX_OK) {                                          \ | ||||
|     fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2);              \ | ||||
|     return err;                                                      \ | ||||
|   } | ||||
|  | ||||
| #define ERROR_GOTO1(ERR_MSG, LABEL)                                  \ | ||||
|   do {                                                               \ | ||||
|     fprintf(stderr, ERR_MSG);                                        \ | ||||
| @@ -183,51 +189,36 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) { | ||||
|   if (flag & ALPHA_FLAG)     printf(" transparency"); | ||||
|   printf("\n"); | ||||
|  | ||||
|   if (flag & ANIMATION_FLAG) { | ||||
|   if ((flag & ANIMATION_FLAG) || (flag & TILE_FLAG)) { | ||||
|     const int is_anim = !!(flag & ANIMATION_FLAG); | ||||
|     const WebPChunkId id = is_anim ? WEBP_CHUNK_FRAME : WEBP_CHUNK_TILE; | ||||
|     const char* const type_str = is_anim ? "frame" : "tile"; | ||||
|     int nFrames; | ||||
|     int loop_count; | ||||
|     err = WebPMuxGetLoopCount(mux, &loop_count); | ||||
|     RETURN_IF_ERROR("Failed to retrieve loop count\n"); | ||||
|     printf("Loop Count : %d\n", loop_count); | ||||
|  | ||||
|     err = WebPMuxNumChunks(mux, WEBP_CHUNK_FRAME, &nFrames); | ||||
|     RETURN_IF_ERROR("Failed to retrieve number of frames\n"); | ||||
|     if (is_anim) { | ||||
|       int loop_count; | ||||
|       err = WebPMuxGetLoopCount(mux, &loop_count); | ||||
|       RETURN_IF_ERROR("Failed to retrieve loop count\n"); | ||||
|       printf("Loop Count : %d\n", loop_count); | ||||
|     } | ||||
|  | ||||
|     printf("Number of frames: %d\n", nFrames); | ||||
|     err = WebPMuxNumChunks(mux, id, &nFrames); | ||||
|     RETURN_IF_ERROR2("Failed to retrieve number of %ss\n", type_str); | ||||
|  | ||||
|     printf("Number of %ss: %d\n", type_str, nFrames); | ||||
|     if (nFrames > 0) { | ||||
|       int i; | ||||
|       printf("No.: x_offset y_offset duration image_size"); | ||||
|       printf("\n"); | ||||
|       printf("No.: x_offset y_offset "); | ||||
|       if (is_anim) printf("duration "); | ||||
|       printf("image_size\n"); | ||||
|       for (i = 1; i <= nFrames; i++) { | ||||
|         WebPMuxFrameInfo frame; | ||||
|         err = WebPMuxGetFrame(mux, i, &frame); | ||||
|         RETURN_IF_ERROR2("Failed to retrieve frame#%d\n", i); | ||||
|         printf("%3d: %8d %8d %8d %10zu", i, frame.x_offset_, frame.y_offset_, | ||||
|                frame.duration_, frame.bitstream_.size_); | ||||
|         RETURN_IF_ERROR3("Failed to retrieve %s#%d\n", type_str, i); | ||||
|         printf("%3d: %8d %8d ", i, frame.x_offset_, frame.y_offset_); | ||||
|         if (is_anim) printf("%8d ", frame.duration_); | ||||
|         printf("%10zu\n", frame.bitstream_.size_); | ||||
|         WebPDataClear(&frame.bitstream_); | ||||
|         printf("\n"); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (flag & TILE_FLAG) { | ||||
|     int nTiles; | ||||
|     err = WebPMuxNumChunks(mux, WEBP_CHUNK_TILE, &nTiles); | ||||
|     RETURN_IF_ERROR("Failed to retrieve number of tiles\n"); | ||||
|  | ||||
|     printf("Number of tiles: %d\n", nTiles); | ||||
|     if (nTiles > 0) { | ||||
|       int i; | ||||
|       printf("No.: x_offset y_offset image_size"); | ||||
|       printf("\n"); | ||||
|       for (i = 1; i <= nTiles; i++) { | ||||
|         WebPMuxFrameInfo tile; | ||||
|         err = WebPMuxGetTile(mux, i, &tile); | ||||
|         RETURN_IF_ERROR2("Failed to retrieve tile#%d\n", i); | ||||
|         printf("%3d: %8d %8d %10zu", | ||||
|                i, tile.x_offset_, tile.y_offset_, tile.bitstream_.size_); | ||||
|         WebPDataClear(&tile.bitstream_); | ||||
|         printf("\n"); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -247,10 +238,10 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) { | ||||
|   } | ||||
|  | ||||
|   if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | TILE_FLAG))) { | ||||
|     WebPData bitstream; | ||||
|     err = WebPMuxGetImage(mux, &bitstream); | ||||
|     WebPMuxFrameInfo image; | ||||
|     err = WebPMuxGetFrame(mux, 1, &image); | ||||
|     RETURN_IF_ERROR("Failed to retrieve the image\n"); | ||||
|     printf("Size of the image (with alpha): %zu\n", bitstream.size_); | ||||
|     printf("Size of the image (with alpha): %zu\n", image.bitstream_.size_); | ||||
|   } | ||||
|  | ||||
|   return WEBP_MUX_OK; | ||||
| @@ -693,6 +684,7 @@ static int GetFrameTile(const WebPMux* mux, | ||||
|   WebPMux* mux_single = NULL; | ||||
|   long num = 0; | ||||
|   int ok = 1; | ||||
|   const WebPChunkId id = isFrame ? WEBP_CHUNK_FRAME : WEBP_CHUNK_TILE; | ||||
|   WebPMuxFrameInfo info; | ||||
|   WebPDataInit(&info.bitstream_); | ||||
|  | ||||
| @@ -701,18 +693,11 @@ static int GetFrameTile(const WebPMux* mux, | ||||
|     ERROR_GOTO1("ERROR: Frame/Tile index must be non-negative.\n", ErrGet); | ||||
|   } | ||||
|  | ||||
|   if (isFrame) { | ||||
|     err = WebPMuxGetFrame(mux, num, &info); | ||||
|     if (err != WEBP_MUX_OK) { | ||||
|       ERROR_GOTO3("ERROR (%s): Could not get frame %ld.\n", | ||||
|                   ErrorString(err), num, ErrGet); | ||||
|     } | ||||
|   } else { | ||||
|     err = WebPMuxGetTile(mux, num, &info); | ||||
|     if (err != WEBP_MUX_OK) { | ||||
|       ERROR_GOTO3("ERROR (%s): Could not get frame %ld.\n", | ||||
|                   ErrorString(err), num, ErrGet); | ||||
|     } | ||||
|   err = WebPMuxGetFrame(mux, num, &info); | ||||
|   if (err == WEBP_MUX_OK && info.id != id) err = WEBP_MUX_NOT_FOUND; | ||||
|   if (err != WEBP_MUX_OK) { | ||||
|     ERROR_GOTO3("ERROR (%s): Could not get frame %ld.\n", | ||||
|                 ErrorString(err), num, ErrGet); | ||||
|   } | ||||
|  | ||||
|   mux_single = WebPMuxNew(); | ||||
| @@ -726,6 +711,7 @@ static int GetFrameTile(const WebPMux* mux, | ||||
|     ERROR_GOTO2("ERROR (%s): Could not create single image mux object.\n", | ||||
|                 ErrorString(err), ErrGet); | ||||
|   } | ||||
|  | ||||
|   ok = WriteWebP(mux_single, config->output_); | ||||
|  | ||||
|  ErrGet: | ||||
| @@ -808,6 +794,7 @@ static int Process(const WebPMuxConfig* config) { | ||||
|                 WebPDataClear(&frame.bitstream_); | ||||
|                 ERROR_GOTO1("ERROR: Could not parse frame properties.\n", Err2); | ||||
|               } | ||||
|               frame.id = WEBP_CHUNK_FRAME; | ||||
|               err = WebPMuxPushFrame(mux, &frame, 1); | ||||
|               WebPDataClear(&frame.bitstream_); | ||||
|               if (err != WEBP_MUX_OK) { | ||||
| @@ -836,7 +823,8 @@ static int Process(const WebPMuxConfig* config) { | ||||
|               WebPDataClear(&tile.bitstream_); | ||||
|               ERROR_GOTO1("ERROR: Could not parse tile properties.\n", Err2); | ||||
|             } | ||||
|             err = WebPMuxPushTile(mux, &tile, 1); | ||||
|             tile.id = WEBP_CHUNK_TILE; | ||||
|             err = WebPMuxPushFrame(mux, &tile, 1); | ||||
|             WebPDataClear(&tile.bitstream_); | ||||
|             if (err != WEBP_MUX_OK) { | ||||
|               ERROR_GOTO3("ERROR (%s): Could not add a tile at index %d.\n", | ||||
|   | ||||
| @@ -205,61 +205,6 @@ static WebPMuxError DeleteLoopCount(WebPMux* const mux) { | ||||
| //------------------------------------------------------------------------------ | ||||
| // Set API(s). | ||||
|  | ||||
| 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 WebPMuxSetChunk(WebPMux* mux, const char fourcc[4], | ||||
|                              const WebPData* chunk_data, int copy_data) { | ||||
|   const CHUNK_INDEX idx = ChunkGetIndexFromFourCC(fourcc); | ||||
| @@ -278,105 +223,60 @@ WebPMuxError WebPMuxSetChunk(WebPMux* mux, const char fourcc[4], | ||||
|   return MuxSet(mux, idx, 1, chunk_data, copy_data); | ||||
| } | ||||
|  | ||||
|  | ||||
| WebPMuxError WebPMuxSetLoopCount(WebPMux* mux, int loop_count) { | ||||
| // Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'. | ||||
| static WebPMuxError AddDataToChunkList( | ||||
|     const WebPData* const data, int copy_data, uint32_t tag, | ||||
|     WebPChunk** chunk_list) { | ||||
|   WebPChunk chunk; | ||||
|   WebPMuxError err; | ||||
|   uint8_t* data = NULL; | ||||
|  | ||||
|   if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   if (loop_count >= MAX_LOOP_COUNT) return WEBP_MUX_INVALID_ARGUMENT; | ||||
|  | ||||
|   // Delete the existing LOOP chunk(s). | ||||
|   err = DeleteLoopCount(mux); | ||||
|   if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; | ||||
|  | ||||
|   // Add the given loop count. | ||||
|   data = (uint8_t*)malloc(kChunks[IDX_LOOP].size); | ||||
|   if (data == NULL) return WEBP_MUX_MEMORY_ERROR; | ||||
|  | ||||
|   PutLE16(data, loop_count); | ||||
|   err = MuxAddChunk(mux, 1, kChunks[IDX_LOOP].tag, data, | ||||
|                     kChunks[IDX_LOOP].size, 1); | ||||
|   free(data); | ||||
|   ChunkInit(&chunk); | ||||
|   err = ChunkAssignData(&chunk, data, copy_data, tag); | ||||
|   if (err != WEBP_MUX_OK) goto Err; | ||||
|   err = ChunkSetNth(&chunk, chunk_list, 1); | ||||
|   if (err != WEBP_MUX_OK) goto Err; | ||||
|   return WEBP_MUX_OK; | ||||
|  Err: | ||||
|   ChunkRelease(&chunk); | ||||
|   return err; | ||||
| } | ||||
|  | ||||
| static WebPMuxError MuxPushFrameTileInternal( | ||||
|     WebPMux* const mux, const WebPMuxFrameInfo* const frame_tile_info, | ||||
|     int copy_data, uint32_t tag) { | ||||
|   const WebPData* bitstream; | ||||
|   int x_offset, y_offset, duration; | ||||
|   WebPChunk chunk; | ||||
|   WebPData image; | ||||
|   WebPData alpha; | ||||
| // 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 WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream, | ||||
|                              int copy_data) { | ||||
|   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 || frame_tile_info == NULL) { | ||||
|   if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL || | ||||
|       bitstream->size_ > MAX_CHUNK_PAYLOAD) { | ||||
|     return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   } | ||||
|  | ||||
|   bitstream = &frame_tile_info->bitstream_; | ||||
|   x_offset = frame_tile_info->x_offset_; | ||||
|   y_offset = frame_tile_info->y_offset_; | ||||
|   duration = is_frame ? frame_tile_info->duration_ : 1 /* unused */; | ||||
|  | ||||
|   if (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 || | ||||
|       (is_frame && (duration <= 0 || duration > MAX_DURATION))) { | ||||
|     return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   if (mux->images_ != NULL) { | ||||
|     // Only one 'simple image' can be added in mux. So, remove present images. | ||||
|     MuxImageDeleteAll(&mux->images_); | ||||
|   } | ||||
|  | ||||
|   // 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); | ||||
|   err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi); | ||||
|   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_); | ||||
| @@ -386,61 +286,103 @@ static WebPMuxError MuxPushFrameTileInternal( | ||||
|   return WEBP_MUX_OK; | ||||
|  | ||||
|  Err:  // Something bad happened. | ||||
|   WebPDataClear(&frame_tile); | ||||
|   ChunkRelease(&chunk); | ||||
|   MuxImageRelease(&wpi); | ||||
|   return err; | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxPushFrame(WebPMux* mux, | ||||
|                               const WebPMuxFrameInfo* frame, | ||||
| WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame, | ||||
|                               int copy_data) { | ||||
|   return MuxPushFrameTileInternal(mux, frame, copy_data, | ||||
|                                   kChunks[IDX_FRAME].tag); | ||||
|   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_FRAME); | ||||
|   if (!(is_frame || (frame->id == WEBP_CHUNK_TILE))) { | ||||
|     return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   } | ||||
|  | ||||
|   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. | ||||
|  | ||||
|   { | ||||
|     const int is_lossless = (wpi.img_->tag_ == kChunks[IDX_VP8L].tag); | ||||
|     const int x_offset = frame->x_offset_ & ~1;  // Snap offsets to even. | ||||
|     const int y_offset = frame->y_offset_ & ~1; | ||||
|     const int duration = is_frame ? frame->duration_ : 1 /* unused */; | ||||
|     const uint32_t tag = kChunks[is_frame ? IDX_FRAME : IDX_TILE].tag; | ||||
|     WebPData frame_tile; | ||||
|     if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET || | ||||
|         y_offset < 0 || y_offset >= MAX_POSITION_OFFSET || | ||||
|         (duration <= 0 || duration > MAX_DURATION)) { | ||||
|       err = WEBP_MUX_INVALID_ARGUMENT; | ||||
|       goto Err; | ||||
|     } | ||||
|     err = CreateFrameTileData(&wpi.img_->data_, 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 = AddDataToChunkList(&frame_tile, 1, tag, &wpi.header_); | ||||
|     WebPDataClear(&frame_tile);  // frame_tile 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 WebPMuxPushTile(WebPMux* mux, | ||||
|                              const WebPMuxFrameInfo* tile, | ||||
|                              int copy_data) { | ||||
|   return MuxPushFrameTileInternal(mux, tile /*unused duration*/, copy_data, | ||||
|                                   kChunks[IDX_TILE].tag); | ||||
| WebPMuxError WebPMuxSetLoopCount(WebPMux* mux, int loop_count) { | ||||
|   WebPMuxError err; | ||||
|   uint8_t data[LOOP_CHUNK_SIZE]; | ||||
|  | ||||
|   if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   if (loop_count >= MAX_LOOP_COUNT) return WEBP_MUX_INVALID_ARGUMENT; | ||||
|  | ||||
|   // Delete the existing LOOP chunk(s). | ||||
|   err = DeleteLoopCount(mux); | ||||
|   if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; | ||||
|  | ||||
|   // Add the given loop count. | ||||
|   PutLE16(data, loop_count); | ||||
|   return MuxAddChunk(mux, 1, kChunks[IDX_LOOP].tag, data, sizeof(data), 1); | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Delete API(s). | ||||
|  | ||||
| WebPMuxError WebPMuxDeleteImage(WebPMux* mux) { | ||||
|   WebPMuxError err; | ||||
|  | ||||
|   if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; | ||||
|  | ||||
|   err = MuxValidateForImage(mux); | ||||
|   if (err != WEBP_MUX_OK) return err; | ||||
|  | ||||
|   // All well, delete image. | ||||
|   MuxImageDeleteAll(&mux->images_); | ||||
|   return WEBP_MUX_OK; | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxDeleteChunk(WebPMux* mux, const char fourcc[4]) { | ||||
|   return MuxDeleteAllNamedData(mux, ChunkGetTagFromFourCC(fourcc)); | ||||
| } | ||||
|  | ||||
| static WebPMuxError DeleteFrameTileInternal(WebPMux* const mux, uint32_t nth, | ||||
|                                             CHUNK_INDEX idx) { | ||||
|   const WebPChunkId id = kChunks[idx].id; | ||||
|   if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; | ||||
|  | ||||
|   assert(idx == IDX_FRAME || idx == IDX_TILE); | ||||
|   return MuxImageDeleteNth(&mux->images_, nth, id); | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) { | ||||
|   return DeleteFrameTileInternal(mux, nth, IDX_FRAME); | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxDeleteTile(WebPMux* mux, uint32_t nth) { | ||||
|   return DeleteFrameTileInternal(mux, nth, IDX_TILE); | ||||
|   if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   return MuxImageDeleteNth(&mux->images_, nth); | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
|   | ||||
| @@ -199,6 +199,7 @@ WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi); | ||||
| void MuxImageDeleteAll(WebPMuxImage** const wpi_list); | ||||
|  | ||||
| // Count number of images matching the given tag id in the 'wpi_list'. | ||||
| // If id == WEBP_CHUNK_NIL, all images will be matched. | ||||
| int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id); | ||||
|  | ||||
| // Check if given ID corresponds to an image related chunk. | ||||
| @@ -228,13 +229,12 @@ static WEBP_INLINE WebPChunk** MuxImageGetListFromId( | ||||
| // Pushes 'wpi' at the end of 'wpi_list'. | ||||
| WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list); | ||||
|  | ||||
| // Delete nth image in the image list with given tag id. | ||||
| WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth, | ||||
|                                WebPChunkId id); | ||||
| // Delete nth image in the image list. | ||||
| WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth); | ||||
|  | ||||
| // Get nth image in the image list with given tag id. | ||||
| // Get nth image in the image list. | ||||
| WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, | ||||
|                             WebPChunkId id, WebPMuxImage** wpi); | ||||
|                             WebPMuxImage** wpi); | ||||
|  | ||||
| // Total size of the given image. | ||||
| size_t MuxImageDiskSize(const WebPMuxImage* const wpi); | ||||
|   | ||||
| @@ -109,7 +109,7 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) { | ||||
|  | ||||
| // Outputs a pointer to 'prev_chunk->next_', | ||||
| //   where 'prev_chunk' is the pointer to the chunk at position (nth - 1). | ||||
| // Returns 1 if nth chunk was found, 0 otherwise. | ||||
| // Returns true if nth chunk was found. | ||||
| static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth, | ||||
|                                 WebPChunk*** const location) { | ||||
|   uint32_t count = 0; | ||||
| @@ -275,10 +275,14 @@ int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) { | ||||
|   int count = 0; | ||||
|   const WebPMuxImage* current; | ||||
|   for (current = wpi_list; current != NULL; current = current->next_) { | ||||
|     const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(current, id); | ||||
|     if (wpi_chunk != NULL) { | ||||
|       const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); | ||||
|       if (wpi_chunk_id == id) ++count; | ||||
|     if (id == WEBP_CHUNK_NIL) { | ||||
|       ++count;  // Special case: count all images. | ||||
|     } else { | ||||
|       const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(current, id); | ||||
|       if (wpi_chunk != NULL) { | ||||
|         const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); | ||||
|         if (wpi_chunk_id == id) ++count;  // Count images with a matching 'id'. | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return count; | ||||
| @@ -286,34 +290,22 @@ int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) { | ||||
|  | ||||
| // Outputs a pointer to 'prev_wpi->next_', | ||||
| //   where 'prev_wpi' is the pointer to the image at position (nth - 1). | ||||
| // Returns 1 if nth image with given id was found, 0 otherwise. | ||||
| // Returns true if nth image was found. | ||||
| static int SearchImageToGetOrDelete(WebPMuxImage** wpi_list, uint32_t nth, | ||||
|                                     WebPChunkId id, | ||||
|                                     WebPMuxImage*** const location) { | ||||
|   uint32_t count = 0; | ||||
|   assert(wpi_list); | ||||
|   *location = wpi_list; | ||||
|  | ||||
|   // Search makes sense only for the following. | ||||
|   assert(id == WEBP_CHUNK_FRAME || id == WEBP_CHUNK_TILE || | ||||
|          id == WEBP_CHUNK_IMAGE); | ||||
|   assert(id != WEBP_CHUNK_IMAGE || nth == 1); | ||||
|  | ||||
|   if (nth == 0) { | ||||
|     nth = MuxImageCount(*wpi_list, id); | ||||
|     nth = MuxImageCount(*wpi_list, WEBP_CHUNK_NIL); | ||||
|     if (nth == 0) return 0;  // Not found. | ||||
|   } | ||||
|  | ||||
|   while (*wpi_list) { | ||||
|     WebPMuxImage* const cur_wpi = *wpi_list; | ||||
|     const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(cur_wpi, id); | ||||
|     if (wpi_chunk != NULL) { | ||||
|       const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_); | ||||
|       if (wpi_chunk_id == id) { | ||||
|         ++count; | ||||
|         if (count == nth) return 1;  // Found. | ||||
|       } | ||||
|     } | ||||
|     ++count; | ||||
|     if (count == nth) return 1;  // Found. | ||||
|     wpi_list = &cur_wpi->next_; | ||||
|     *location = wpi_list; | ||||
|   } | ||||
| @@ -361,10 +353,9 @@ void MuxImageDeleteAll(WebPMuxImage** const wpi_list) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth, | ||||
|                                WebPChunkId id) { | ||||
| WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth) { | ||||
|   assert(wpi_list); | ||||
|   if (!SearchImageToGetOrDelete(wpi_list, nth, id, &wpi_list)) { | ||||
|   if (!SearchImageToGetOrDelete(wpi_list, nth, &wpi_list)) { | ||||
|     return WEBP_MUX_NOT_FOUND; | ||||
|   } | ||||
|   *wpi_list = MuxImageDelete(*wpi_list); | ||||
| @@ -375,10 +366,10 @@ WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth, | ||||
| // MuxImage reader methods. | ||||
|  | ||||
| WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth, | ||||
|                             WebPChunkId id, WebPMuxImage** wpi) { | ||||
|                             WebPMuxImage** wpi) { | ||||
|   assert(wpi_list); | ||||
|   assert(wpi); | ||||
|   if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, id, | ||||
|   if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, | ||||
|                                 (WebPMuxImage***)&wpi_list)) { | ||||
|     return WEBP_MUX_NOT_FOUND; | ||||
|   } | ||||
|   | ||||
| @@ -190,6 +190,8 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data, | ||||
| //------------------------------------------------------------------------------ | ||||
| // Get API(s). | ||||
|  | ||||
| // TODO(urvang): Change the behavior of this to return ALPHA_FLAG when the mux | ||||
| // doesn't contain a VP8X chunk, but does contain a VP8L chunk with real alpha. | ||||
| WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { | ||||
|   WebPData data; | ||||
|   WebPMuxError err; | ||||
| @@ -200,10 +202,7 @@ WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) { | ||||
|   // Check if VP8X chunk is present. | ||||
|   err = MuxGet(mux, IDX_VP8X, 1, &data); | ||||
|   if (err == WEBP_MUX_NOT_FOUND) { | ||||
|     // Check if VP8/VP8L chunk is present. | ||||
|     err = WebPMuxGetImage(mux, &data); | ||||
|     WebPDataClear(&data); | ||||
|     return err; | ||||
|     return MuxValidateForImage(mux);  // Check if a single image is present. | ||||
|   } else if (err != WEBP_MUX_OK) { | ||||
|     return err; | ||||
|   } | ||||
| @@ -230,7 +229,7 @@ static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width, | ||||
| } | ||||
|  | ||||
| // Assemble a single image WebP bitstream from 'wpi'. | ||||
| static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi, | ||||
| static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi, | ||||
|                                         WebPData* const bitstream) { | ||||
|   uint8_t* dst; | ||||
|  | ||||
| @@ -270,25 +269,6 @@ static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi, | ||||
|   return WEBP_MUX_OK; | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxGetImage(const WebPMux* mux, WebPData* bitstream) { | ||||
|   WebPMuxError err; | ||||
|   WebPMuxImage* wpi = NULL; | ||||
|  | ||||
|   if (mux == NULL || bitstream == NULL) { | ||||
|     return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   } | ||||
|  | ||||
|   err = MuxValidateForImage(mux); | ||||
|   if (err != WEBP_MUX_OK) return err; | ||||
|  | ||||
|   // All well. Get the image. | ||||
|   err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, WEBP_CHUNK_IMAGE, | ||||
|                        &wpi); | ||||
|   assert(err == WEBP_MUX_OK);  // Already tested above. | ||||
|  | ||||
|   return SynthesizeBitstream(wpi, bitstream); | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4], | ||||
|                              WebPData* chunk_data) { | ||||
|   const CHUNK_INDEX idx = ChunkGetIndexFromFourCC(fourcc); | ||||
| @@ -306,6 +286,56 @@ WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4], | ||||
|   } | ||||
| } | ||||
|  | ||||
| static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi, | ||||
|                                         WebPMuxFrameInfo* const info) { | ||||
|   // Set some defaults for unrelated fields. | ||||
|   info->x_offset_ = 0; | ||||
|   info->y_offset_ = 0; | ||||
|   info->duration_ = 1; | ||||
|   // Extract data for related fields. | ||||
|   info->id = ChunkGetIdFromTag(wpi->img_->tag_); | ||||
|   return SynthesizeBitstream(wpi, &info->bitstream_); | ||||
| } | ||||
|  | ||||
| static WebPMuxError MuxGetFrameTileInternal(const WebPMuxImage* const wpi, | ||||
|                                             WebPMuxFrameInfo* const frame) { | ||||
|   const int is_frame = (wpi->header_->tag_ == kChunks[IDX_FRAME].tag); | ||||
|   const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE; | ||||
|   const WebPData* frame_tile_data; | ||||
|   assert(wpi->header_ != NULL);  // Already checked by WebPMuxGetFrame(). | ||||
|   // Get frame/tile chunk. | ||||
|   frame_tile_data = &wpi->header_->data_; | ||||
|   if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA; | ||||
|   // Extract info. | ||||
|   frame->x_offset_ = 2 * GetLE24(frame_tile_data->bytes_ + 0); | ||||
|   frame->y_offset_ = 2 * GetLE24(frame_tile_data->bytes_ + 3); | ||||
|   frame->duration_ = is_frame ? 1 + GetLE24(frame_tile_data->bytes_ + 12) : 1; | ||||
|   frame->id = ChunkGetIdFromTag(wpi->header_->tag_); | ||||
|   return SynthesizeBitstream(wpi, &frame->bitstream_); | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxGetFrame( | ||||
|     const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame) { | ||||
|   WebPMuxError err; | ||||
|   WebPMuxImage* wpi; | ||||
|  | ||||
|   // Sanity checks. | ||||
|   if (mux == NULL || frame == NULL) { | ||||
|     return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   } | ||||
|  | ||||
|   // Get the nth WebPMuxImage. | ||||
|   err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, &wpi); | ||||
|   if (err != WEBP_MUX_OK) return err; | ||||
|  | ||||
|   // Get frame info. | ||||
|   if (wpi->header_ == NULL) { | ||||
|     return MuxGetImageInternal(wpi, frame); | ||||
|   } else { | ||||
|     return MuxGetFrameTileInternal(wpi, frame); | ||||
|   } | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxGetLoopCount(const WebPMux* mux, int* loop_count) { | ||||
|   WebPData image; | ||||
|   WebPMuxError err; | ||||
| @@ -320,49 +350,6 @@ WebPMuxError WebPMuxGetLoopCount(const WebPMux* mux, int* loop_count) { | ||||
|   return WEBP_MUX_OK; | ||||
| } | ||||
|  | ||||
| static WebPMuxError MuxGetFrameTileInternal( | ||||
|     const WebPMux* const mux, uint32_t nth, | ||||
|     WebPMuxFrameInfo* const frame_tile_info, uint32_t tag) { | ||||
|   const WebPData* frame_tile_data; | ||||
|   WebPMuxError err; | ||||
|   WebPMuxImage* wpi; | ||||
|  | ||||
|   const int is_frame = (tag == kChunks[WEBP_CHUNK_FRAME].tag) ? 1 : 0; | ||||
|   const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE; | ||||
|   const WebPChunkId id = kChunks[idx].id; | ||||
|  | ||||
|   if (mux == NULL || frame_tile_info == NULL) { | ||||
|     return WEBP_MUX_INVALID_ARGUMENT; | ||||
|   } | ||||
|  | ||||
|   // Get the nth WebPMuxImage. | ||||
|   err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, id, &wpi); | ||||
|   if (err != WEBP_MUX_OK) return err; | ||||
|  | ||||
|   // Get frame chunk. | ||||
|   assert(wpi->header_ != NULL);  // As MuxImageGetNth() already checked header_. | ||||
|   frame_tile_data = &wpi->header_->data_; | ||||
|  | ||||
|   if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA; | ||||
|   frame_tile_info->x_offset_ = 2 * GetLE24(frame_tile_data->bytes_ + 0); | ||||
|   frame_tile_info->y_offset_ = 2 * GetLE24(frame_tile_data->bytes_ + 3); | ||||
|   if (is_frame) { | ||||
|     frame_tile_info->duration_ = 1 + GetLE24(frame_tile_data->bytes_ + 12); | ||||
|   } | ||||
|  | ||||
|   return SynthesizeBitstream(wpi, &frame_tile_info->bitstream_); | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxGetFrame(const WebPMux* mux, uint32_t nth, | ||||
|                              WebPMuxFrameInfo* frame) { | ||||
|   return MuxGetFrameTileInternal(mux, nth, frame, kChunks[IDX_FRAME].tag); | ||||
| } | ||||
|  | ||||
| WebPMuxError WebPMuxGetTile(const WebPMux* mux, uint32_t nth, | ||||
|                             WebPMuxFrameInfo* tile) { | ||||
|   return MuxGetFrameTileInternal(mux, nth, tile, kChunks[IDX_TILE].tag); | ||||
| } | ||||
|  | ||||
| // Get chunk index from chunk id. Returns IDX_NIL if not found. | ||||
| static CHUNK_INDEX ChunkGetIndexFromId(WebPChunkId id) { | ||||
|   int i; | ||||
|   | ||||
							
								
								
									
										165
									
								
								src/webp/mux.h
									
									
									
									
									
								
							
							
						
						
									
										165
									
								
								src/webp/mux.h
									
									
									
									
									
								
							| @@ -35,7 +35,7 @@ | ||||
| //   int copy_data = 0; | ||||
| //   // ... (Read data from file). | ||||
| //   WebPMux* mux = WebPMuxCreate(&data, copy_data); | ||||
| //   WebPMuxGetImage(mux, &image); | ||||
| //   WebPMuxGetFrame(mux, 1, &image); | ||||
| //   // ... (Consume image; e.g. call WebPDecode() to decode the data). | ||||
| //   WebPMuxGetChunk(mux, "ICCP", &icc_profile); | ||||
| //   // ... (Consume icc_data). | ||||
| @@ -151,8 +151,8 @@ WEBP_EXTERN(WebPMux*) WebPMuxCreateInternal(const WebPData*, int, int); | ||||
| // Creates a mux object from raw data given in WebP RIFF format. | ||||
| // Parameters: | ||||
| //   bitstream - (in) the bitstream data in WebP RIFF format | ||||
| //   copy_data - (in) value 1 indicates given data WILL copied to the mux, and | ||||
| //               value 0 indicates data will NOT be copied. | ||||
| //   copy_data - (in) value 1 indicates given data WILL be copied to the mux | ||||
| //               and value 0 indicates data will NOT be copied. | ||||
| // Returns: | ||||
| //   A pointer to the mux object created from given data - on success. | ||||
| //   NULL - In case of invalid data or memory error. | ||||
| @@ -162,54 +162,12 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream, | ||||
| } | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Single Image. | ||||
|  | ||||
| // Sets the image in the mux object. Any existing images (including frame/tile) | ||||
| // will be removed. | ||||
| // Parameters: | ||||
| //   mux - (in/out) object in which the image is to be set | ||||
| //   bitstream - (in) can either be a raw VP8/VP8L bitstream or a single-image | ||||
| //               WebP file (non-animated and non-tiled) | ||||
| //   copy_data - (in) value 1 indicates given data WILL copied to the mux, and | ||||
| //               value 0 indicates data will NOT be copied. | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL. | ||||
| //   WEBP_MUX_MEMORY_ERROR - on memory allocation error. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(WebPMux* mux, | ||||
|                                           const WebPData* bitstream, | ||||
|                                           int copy_data); | ||||
|  | ||||
| // Gets image data from the mux object. | ||||
| // The content of 'bitstream' is allocated using malloc(), and NOT | ||||
| // owned by the 'mux' object. It MUST be deallocated by the caller by calling | ||||
| // WebPDataClear(). | ||||
| // Parameters: | ||||
| //   mux - (in) object from which the image is to be fetched | ||||
| //   bitstream - (out) the image data | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if either mux or bitstream is NULL | ||||
| //                               or if mux contains animation/tiling. | ||||
| //   WEBP_MUX_NOT_FOUND - if image is not present in mux object. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxGetImage(const WebPMux* mux, | ||||
|                                           WebPData* bitstream); | ||||
|  | ||||
| // Deletes the image in the mux object. | ||||
| // Parameters: | ||||
| //   mux - (in/out) object from which the image is to be deleted | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux is NULL | ||||
| //                               or if mux contains animation/tiling. | ||||
| //   WEBP_MUX_NOT_FOUND - if image is not present in mux object. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxDeleteImage(WebPMux* mux); | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Chunks. | ||||
| // Non-image chunks. | ||||
|  | ||||
| // Note: Only non-image related chunks should be managed through chunk APIs. | ||||
| // (Image related chunks are: "FRM ", "TILE", "VP8 ", "VP8L" and "ALPH"). | ||||
| // To add, get and delete images, use APIs WebPMuxSetImage(), | ||||
| // WebPMuxPushFrame(), WebPMuxGetFrame() and WebPMuxDeleteFrame(). | ||||
|  | ||||
| // Adds a chunk with id 'fourcc' and data 'chunk_data' in the mux object. | ||||
| // Any existing chunk(s) with the same id will be removed. | ||||
| @@ -218,8 +176,8 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteImage(WebPMux* mux); | ||||
| //   fourcc - (in) a character array containing the fourcc of the given chunk; | ||||
| //                 e.g., "ICCP", "META" etc. | ||||
| //   chunk_data - (in) the chunk data to be added | ||||
| //   copy_data - (in) value 1 indicates given data WILL copied to the mux, and | ||||
| //               value 0 indicates data will NOT be copied. | ||||
| //   copy_data - (in) value 1 indicates given data WILL be copied to the mux | ||||
| //               and value 0 indicates data will NOT be copied. | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux or chunk_data is NULL | ||||
| //                               or if fourcc corresponds to an image chunk. | ||||
| @@ -258,26 +216,48 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteChunk( | ||||
|     WebPMux* mux, const char fourcc[4]); | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Animation. | ||||
| // Images. | ||||
|  | ||||
| // Encapsulates data about a single frame/tile. | ||||
| struct WebPMuxFrameInfo { | ||||
|   WebPData bitstream_;  // image data: can either be a raw VP8/VP8L bitstream | ||||
|                         // or a single-image WebP file. | ||||
|   int x_offset_;        // x-offset of the frame. | ||||
|   int y_offset_;        // y-offset of the frame. | ||||
|   int duration_;        // duration of the frame (in milliseconds). | ||||
|   uint32_t pad[3];      // padding for later use | ||||
|   WebPData    bitstream_;  // image data: can either be a raw VP8/VP8L bitstream | ||||
|                            // or a single-image WebP file. | ||||
|   int         x_offset_;   // x-offset of the frame. | ||||
|   int         y_offset_;   // y-offset of the frame. | ||||
|   int         duration_;   // duration of the frame (in milliseconds). | ||||
|  | ||||
|   WebPChunkId id;          // frame type: should be one of WEBP_CHUNK_FRAME, | ||||
|                            // WEBP_CHUNK_TILE or WEBP_CHUNK_IMAGE | ||||
|   uint32_t pad[3];         // padding for later use | ||||
| }; | ||||
|  | ||||
| // Adds an animation frame at the end of the mux object. | ||||
| // Note: as WebP only supports even offsets, any odd offset will be snapped to | ||||
| // an even location using: offset &= ~1 | ||||
| // Sets the (non-animated and non-tiled) image in the mux object. | ||||
| // Note: Any existing images (including frames/tiles) will be removed. | ||||
| // Parameters: | ||||
| //   mux - (in/out) object to which an animation frame is to be added | ||||
| //   mux - (in/out) object in which the image is to be set | ||||
| //   bitstream - (in) can either be a raw VP8/VP8L bitstream or a single-image | ||||
| //               WebP file (non-animated and non-tiled) | ||||
| //   copy_data - (in) value 1 indicates given data WILL be copied to the mux | ||||
| //               and value 0 indicates data will NOT be copied. | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL. | ||||
| //   WEBP_MUX_MEMORY_ERROR - on memory allocation error. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxSetImage( | ||||
|     WebPMux* mux, const WebPData* bitstream, int copy_data); | ||||
|  | ||||
| // Adds a frame at the end of the mux object. | ||||
| // Notes: (1) frame.id should be one of WEBP_CHUNK_FRAME or WEBP_CHUNK_TILE | ||||
| //        (2) For setting a non-animated non-tiled image, use WebPMuxSetImage() | ||||
| //            instead. | ||||
| //        (3) Type of frame being pushed must be same as the frames in mux. | ||||
| //        (4) As WebP only supports even offsets, any odd offset will be snapped | ||||
| //            to an even location using: offset &= ~1 | ||||
| // Parameters: | ||||
| //   mux - (in/out) object to which the frame is to be added | ||||
| //   frame - (in) frame data. | ||||
| //   copy_data - (in) value 1 indicates given data WILL copied to the mux, and | ||||
| //               value 0 indicates data will NOT be copied. | ||||
| //   copy_data - (in) value 1 indicates given data WILL be copied to the mux | ||||
| //               and value 0 indicates data will NOT be copied. | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL | ||||
| //                               or if content of 'frame' is invalid. | ||||
| @@ -286,7 +266,7 @@ struct WebPMuxFrameInfo { | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame( | ||||
|     WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data); | ||||
|  | ||||
| // Gets the nth animation frame from the mux object. | ||||
| // Gets the nth frame from the mux object. | ||||
| // The content of 'frame->bitstream_' is allocated using malloc(), and NOT | ||||
| // owned by the 'mux' object. It MUST be deallocated by the caller by calling | ||||
| // WebPDataClear(). | ||||
| @@ -296,25 +276,28 @@ WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame( | ||||
| //   nth - (in) index of the frame in the mux object | ||||
| //   frame - (out) data of the returned frame | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL. | ||||
| //   WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object. | ||||
| //   WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame( | ||||
|     const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame); | ||||
|  | ||||
| // Deletes an animation frame from the mux object. | ||||
| // Deletes a frame from the mux object. | ||||
| // nth=0 has a special meaning - last position. | ||||
| // Parameters: | ||||
| //   mux - (in/out) object from which a frame is to be deleted | ||||
| //   nth - (in) The position from which the frame is to be deleted | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux is NULL | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux is NULL. | ||||
| //   WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object | ||||
| //                        before deletion. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth); | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Animation. | ||||
|  | ||||
| // Sets the animation loop count in the mux object. Any existing loop count | ||||
| // value(s) will be removed. | ||||
| // Parameters: | ||||
| @@ -338,54 +321,6 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetLoopCount(WebPMux* mux, int loop_count); | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxGetLoopCount(const WebPMux* mux, | ||||
|                                               int* loop_count); | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Tiling. | ||||
|  | ||||
| // Adds a tile at the end of the mux object. | ||||
| // Note: as WebP only supports even offsets, any odd offset will be snapped to | ||||
| // an even location using: offset &= ~1 | ||||
| // Parameters: | ||||
| //   mux - (in/out) object to which a tile is to be added. | ||||
| //   tile - (in) tile data. | ||||
| //   copy_data - (in) value 1 indicates given data WILL copied to the mux, and | ||||
| //               value 0 indicates data will NOT be copied. | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux or tile is NULL | ||||
| //                               or if content of 'tile' is invalid. | ||||
| //   WEBP_MUX_MEMORY_ERROR - on memory allocation error. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxPushTile( | ||||
|     WebPMux* mux, const WebPMuxFrameInfo* tile, int copy_data); | ||||
|  | ||||
| // Gets the nth tile from the mux object. | ||||
| // The content of 'tile->bitstream_' is allocated using malloc(), and NOT | ||||
| // owned by the 'mux' object. It MUST be deallocated by the caller by calling | ||||
| // WebPDataClear(). | ||||
| // nth=0 has a special meaning - last position. | ||||
| // Parameters: | ||||
| //   mux - (in) object from which the info is to be fetched | ||||
| //   nth - (in) index of the tile in the mux object | ||||
| //   tile - (out) data of the returned tile | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if either mux or tile is NULL | ||||
| //   WEBP_MUX_NOT_FOUND - if there are less than nth tiles in the mux object. | ||||
| //   WEBP_MUX_BAD_DATA - if nth tile chunk in mux is invalid. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxGetTile( | ||||
|     const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* tile); | ||||
|  | ||||
| // Deletes a tile from the mux object. | ||||
| // nth=0 has a special meaning - last position | ||||
| // Parameters: | ||||
| //   mux - (in/out) object from which a tile is to be deleted | ||||
| //   nth - (in) The position from which the tile is to be deleted | ||||
| // Returns: | ||||
| //   WEBP_MUX_INVALID_ARGUMENT - if mux is NULL | ||||
| //   WEBP_MUX_NOT_FOUND - If there are less than nth tiles in the mux object | ||||
| //                        before deletion. | ||||
| //   WEBP_MUX_OK - on success. | ||||
| WEBP_EXTERN(WebPMuxError) WebPMuxDeleteTile(WebPMux* mux, uint32_t nth); | ||||
|  | ||||
| //------------------------------------------------------------------------------ | ||||
| // Misc Utilities. | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user