go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

idec_dec.c (31958B)


      1 // Copyright 2011 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // Incremental decoding
     11 //
     12 // Author: somnath@google.com (Somnath Banerjee)
     13 
     14 #include <assert.h>
     15 #include <stdlib.h>
     16 #include <string.h>
     17 
     18 #include "src/dec/alphai_dec.h"
     19 #include "src/dec/vp8_dec.h"
     20 #include "src/dec/vp8i_dec.h"
     21 #include "src/dec/vp8li_dec.h"
     22 #include "src/dec/webpi_dec.h"
     23 #include "src/utils/bit_reader_utils.h"
     24 #include "src/utils/thread_utils.h"
     25 #include "src/utils/utils.h"
     26 #include "src/webp/decode.h"
     27 #include "src/webp/format_constants.h"
     28 #include "src/webp/types.h"
     29 
     30 // In append mode, buffer allocations increase as multiples of this value.
     31 // Needs to be a power of 2.
     32 #define CHUNK_SIZE 4096
     33 #define MAX_MB_SIZE 4096
     34 
     35 //------------------------------------------------------------------------------
     36 // Data structures for memory and states
     37 
     38 // Decoding states. State normally flows as:
     39 // WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and
     40 // WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image.
     41 // If there is any error the decoder goes into state ERROR.
     42 typedef enum {
     43   STATE_WEBP_HEADER,  // All the data before that of the VP8/VP8L chunk.
     44   STATE_VP8_HEADER,   // The VP8 Frame header (within the VP8 chunk).
     45   STATE_VP8_PARTS0,
     46   STATE_VP8_DATA,
     47   STATE_VP8L_HEADER,
     48   STATE_VP8L_DATA,
     49   STATE_DONE,
     50   STATE_ERROR
     51 } DecState;
     52 
     53 // Operating state for the MemBuffer
     54 typedef enum {
     55   MEM_MODE_NONE = 0,
     56   MEM_MODE_APPEND,
     57   MEM_MODE_MAP
     58 } MemBufferMode;
     59 
     60 // storage for partition #0 and partial data (in a rolling fashion)
     61 typedef struct {
     62   MemBufferMode mode;  // Operation mode
     63   size_t start;        // start location of the data to be decoded
     64   size_t end;          // end location
     65   size_t buf_size;     // size of the allocated buffer
     66   uint8_t* buf;        // We don't own this buffer in case WebPIUpdate()
     67 
     68   size_t part0_size;         // size of partition #0
     69   const uint8_t* part0_buf;  // buffer to store partition #0
     70 } MemBuffer;
     71 
     72 struct WebPIDecoder {
     73   DecState state;         // current decoding state
     74   WebPDecParams params;   // Params to store output info
     75   int is_lossless;        // for down-casting 'dec'.
     76   void* dec;              // either a VP8Decoder or a VP8LDecoder instance
     77   VP8Io io;
     78 
     79   MemBuffer mem;          // input memory buffer.
     80   WebPDecBuffer output;   // output buffer (when no external one is supplied,
     81                           // or if the external one has slow-memory)
     82   WebPDecBuffer* final_output;  // Slow-memory output to copy to eventually.
     83   size_t chunk_size;      // Compressed VP8/VP8L size extracted from Header.
     84 
     85   int last_mb_y;          // last row reached for intra-mode decoding
     86 };
     87 
     88 // MB context to restore in case VP8DecodeMB() fails
     89 typedef struct {
     90   VP8MB left;
     91   VP8MB info;
     92   VP8BitReader token_br;
     93 } MBContext;
     94 
     95 //------------------------------------------------------------------------------
     96 // MemBuffer: incoming data handling
     97 
     98 static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
     99   return (mem->end - mem->start);
    100 }
    101 
    102 // Check if we need to preserve the compressed alpha data, as it may not have
    103 // been decoded yet.
    104 static int NeedCompressedAlpha(const WebPIDecoder* const idec) {
    105   if (idec->state == STATE_WEBP_HEADER) {
    106     // We haven't parsed the headers yet, so we don't know whether the image is
    107     // lossy or lossless. This also means that we haven't parsed the ALPH chunk.
    108     return 0;
    109   }
    110   if (idec->is_lossless) {
    111     return 0;  // ALPH chunk is not present for lossless images.
    112   } else {
    113     const VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    114     assert(dec != NULL);  // Must be true as idec->state != STATE_WEBP_HEADER.
    115     return (dec->alpha_data != NULL) && !dec->is_alpha_decoded;
    116   }
    117 }
    118 
    119 static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
    120   MemBuffer* const mem = &idec->mem;
    121   const uint8_t* const new_base = mem->buf + mem->start;
    122   // note: for VP8, setting up idec->io is only really needed at the beginning
    123   // of the decoding, till partition #0 is complete.
    124   idec->io.data = new_base;
    125   idec->io.data_size = MemDataSize(mem);
    126 
    127   if (idec->dec != NULL) {
    128     if (!idec->is_lossless) {
    129       VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    130       const uint32_t last_part = dec->num_parts_minus_one;
    131       if (offset != 0) {
    132         uint32_t p;
    133         for (p = 0; p <= last_part; ++p) {
    134           VP8RemapBitReader(dec->parts + p, offset);
    135         }
    136         // Remap partition #0 data pointer to new offset, but only in MAP
    137         // mode (in APPEND mode, partition #0 is copied into a fixed memory).
    138         if (mem->mode == MEM_MODE_MAP) {
    139           VP8RemapBitReader(&dec->br, offset);
    140         }
    141       }
    142       {
    143         const uint8_t* const last_start = dec->parts[last_part].buf;
    144         // 'last_start' will be NULL when 'idec->state' is < STATE_VP8_PARTS0
    145         // and through a portion of that state (when there isn't enough data to
    146         // parse the partitions). The bitreader is only used meaningfully when
    147         // there is enough data to begin parsing partition 0.
    148         if (last_start != NULL) {
    149           VP8BitReaderSetBuffer(&dec->parts[last_part], last_start,
    150                                 mem->buf + mem->end - last_start);
    151         }
    152       }
    153       if (NeedCompressedAlpha(idec)) {
    154         ALPHDecoder* const alph_dec = dec->alph_dec;
    155         dec->alpha_data += offset;
    156         if (alph_dec != NULL && alph_dec->vp8l_dec != NULL) {
    157           if (alph_dec->method == ALPHA_LOSSLESS_COMPRESSION) {
    158             VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec;
    159             assert(dec->alpha_data_size >= ALPHA_HEADER_LEN);
    160             VP8LBitReaderSetBuffer(&alph_vp8l_dec->br,
    161                                    dec->alpha_data + ALPHA_HEADER_LEN,
    162                                    dec->alpha_data_size - ALPHA_HEADER_LEN);
    163           } else {  // alph_dec->method == ALPHA_NO_COMPRESSION
    164             // Nothing special to do in this case.
    165           }
    166         }
    167       }
    168     } else {    // Resize lossless bitreader
    169       VP8LDecoder* const dec = (VP8LDecoder*)idec->dec;
    170       VP8LBitReaderSetBuffer(&dec->br, new_base, MemDataSize(mem));
    171     }
    172   }
    173 }
    174 
    175 // Appends data to the end of MemBuffer->buf. It expands the allocated memory
    176 // size if required and also updates VP8BitReader's if new memory is allocated.
    177 WEBP_NODISCARD static int AppendToMemBuffer(WebPIDecoder* const idec,
    178                                             const uint8_t* const data,
    179                                             size_t data_size) {
    180   VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    181   MemBuffer* const mem = &idec->mem;
    182   const int need_compressed_alpha = NeedCompressedAlpha(idec);
    183   const uint8_t* const old_start =
    184       (mem->buf == NULL) ? NULL : mem->buf + mem->start;
    185   const uint8_t* const old_base =
    186       need_compressed_alpha ? dec->alpha_data : old_start;
    187   assert(mem->buf != NULL || mem->start == 0);
    188   assert(mem->mode == MEM_MODE_APPEND);
    189   if (data_size > MAX_CHUNK_PAYLOAD) {
    190     // security safeguard: trying to allocate more than what the format
    191     // allows for a chunk should be considered a smoke smell.
    192     return 0;
    193   }
    194 
    195   if (mem->end + data_size > mem->buf_size) {  // Need some free memory
    196     const size_t new_mem_start = old_start - old_base;
    197     const size_t current_size = MemDataSize(mem) + new_mem_start;
    198     const uint64_t new_size = (uint64_t)current_size + data_size;
    199     const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
    200     uint8_t* const new_buf =
    201         (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
    202     if (new_buf == NULL) return 0;
    203     if (old_base != NULL) memcpy(new_buf, old_base, current_size);
    204     WebPSafeFree(mem->buf);
    205     mem->buf = new_buf;
    206     mem->buf_size = (size_t)extra_size;
    207     mem->start = new_mem_start;
    208     mem->end = current_size;
    209   }
    210 
    211   assert(mem->buf != NULL);
    212   memcpy(mem->buf + mem->end, data, data_size);
    213   mem->end += data_size;
    214   assert(mem->end <= mem->buf_size);
    215 
    216   DoRemap(idec, mem->buf + mem->start - old_start);
    217   return 1;
    218 }
    219 
    220 WEBP_NODISCARD static int RemapMemBuffer(WebPIDecoder* const idec,
    221                                          const uint8_t* const data,
    222                                          size_t data_size) {
    223   MemBuffer* const mem = &idec->mem;
    224   const uint8_t* const old_buf = mem->buf;
    225   const uint8_t* const old_start =
    226       (old_buf == NULL) ? NULL : old_buf + mem->start;
    227   assert(old_buf != NULL || mem->start == 0);
    228   assert(mem->mode == MEM_MODE_MAP);
    229 
    230   if (data_size < mem->buf_size) return 0;  // can't remap to a shorter buffer!
    231 
    232   mem->buf = (uint8_t*)data;
    233   mem->end = mem->buf_size = data_size;
    234 
    235   DoRemap(idec, mem->buf + mem->start - old_start);
    236   return 1;
    237 }
    238 
    239 static void InitMemBuffer(MemBuffer* const mem) {
    240   mem->mode       = MEM_MODE_NONE;
    241   mem->buf        = NULL;
    242   mem->buf_size   = 0;
    243   mem->part0_buf  = NULL;
    244   mem->part0_size = 0;
    245 }
    246 
    247 static void ClearMemBuffer(MemBuffer* const mem) {
    248   assert(mem);
    249   if (mem->mode == MEM_MODE_APPEND) {
    250     WebPSafeFree(mem->buf);
    251     WebPSafeFree((void*)mem->part0_buf);
    252   }
    253 }
    254 
    255 WEBP_NODISCARD static int CheckMemBufferMode(MemBuffer* const mem,
    256                                              MemBufferMode expected) {
    257   if (mem->mode == MEM_MODE_NONE) {
    258     mem->mode = expected;    // switch to the expected mode
    259   } else if (mem->mode != expected) {
    260     return 0;         // we mixed the modes => error
    261   }
    262   assert(mem->mode == expected);   // mode is ok
    263   return 1;
    264 }
    265 
    266 // To be called last.
    267 WEBP_NODISCARD static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
    268   const WebPDecoderOptions* const options = idec->params.options;
    269   WebPDecBuffer* const output = idec->params.output;
    270 
    271   idec->state = STATE_DONE;
    272   if (options != NULL && options->flip) {
    273     const VP8StatusCode status = WebPFlipBuffer(output);
    274     if (status != VP8_STATUS_OK) return status;
    275   }
    276   if (idec->final_output != NULL) {
    277     const VP8StatusCode status = WebPCopyDecBufferPixels(
    278         output, idec->final_output);  // do the slow-copy
    279     WebPFreeDecBuffer(&idec->output);
    280     if (status != VP8_STATUS_OK) return status;
    281     *output = *idec->final_output;
    282     idec->final_output = NULL;
    283   }
    284   return VP8_STATUS_OK;
    285 }
    286 
    287 //------------------------------------------------------------------------------
    288 // Macroblock-decoding contexts
    289 
    290 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
    291                         MBContext* const context) {
    292   context->left = dec->mb_info[-1];
    293   context->info = dec->mb_info[dec->mb_x];
    294   context->token_br = *token_br;
    295 }
    296 
    297 static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
    298                            VP8BitReader* const token_br) {
    299   dec->mb_info[-1] = context->left;
    300   dec->mb_info[dec->mb_x] = context->info;
    301   *token_br = context->token_br;
    302 }
    303 
    304 //------------------------------------------------------------------------------
    305 
    306 static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
    307   if (idec->state == STATE_VP8_DATA) {
    308     // Synchronize the thread, clean-up and check for errors.
    309     (void)VP8ExitCritical((VP8Decoder*)idec->dec, &idec->io);
    310   }
    311   idec->state = STATE_ERROR;
    312   return error;
    313 }
    314 
    315 static void ChangeState(WebPIDecoder* const idec, DecState new_state,
    316                         size_t consumed_bytes) {
    317   MemBuffer* const mem = &idec->mem;
    318   idec->state = new_state;
    319   mem->start += consumed_bytes;
    320   assert(mem->start <= mem->end);
    321   idec->io.data = mem->buf + mem->start;
    322   idec->io.data_size = MemDataSize(mem);
    323 }
    324 
    325 // Headers
    326 static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
    327   MemBuffer* const mem = &idec->mem;
    328   const uint8_t* data = mem->buf + mem->start;
    329   size_t curr_size = MemDataSize(mem);
    330   VP8StatusCode status;
    331   WebPHeaderStructure headers;
    332 
    333   headers.data = data;
    334   headers.data_size = curr_size;
    335   headers.have_all_data = 0;
    336   status = WebPParseHeaders(&headers);
    337   if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
    338     return VP8_STATUS_SUSPENDED;  // We haven't found a VP8 chunk yet.
    339   } else if (status != VP8_STATUS_OK) {
    340     return IDecError(idec, status);
    341   }
    342 
    343   idec->chunk_size = headers.compressed_size;
    344   idec->is_lossless = headers.is_lossless;
    345   if (!idec->is_lossless) {
    346     VP8Decoder* const dec = VP8New();
    347     if (dec == NULL) {
    348       return VP8_STATUS_OUT_OF_MEMORY;
    349     }
    350     dec->incremental = 1;
    351     idec->dec = dec;
    352     dec->alpha_data = headers.alpha_data;
    353     dec->alpha_data_size = headers.alpha_data_size;
    354     ChangeState(idec, STATE_VP8_HEADER, headers.offset);
    355   } else {
    356     VP8LDecoder* const dec = VP8LNew();
    357     if (dec == NULL) {
    358       return VP8_STATUS_OUT_OF_MEMORY;
    359     }
    360     idec->dec = dec;
    361     ChangeState(idec, STATE_VP8L_HEADER, headers.offset);
    362   }
    363   return VP8_STATUS_OK;
    364 }
    365 
    366 static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
    367   const uint8_t* data = idec->mem.buf + idec->mem.start;
    368   const size_t curr_size = MemDataSize(&idec->mem);
    369   int width, height;
    370   uint32_t bits;
    371 
    372   if (curr_size < VP8_FRAME_HEADER_SIZE) {
    373     // Not enough data bytes to extract VP8 Frame Header.
    374     return VP8_STATUS_SUSPENDED;
    375   }
    376   if (!VP8GetInfo(data, curr_size, idec->chunk_size, &width, &height)) {
    377     return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    378   }
    379 
    380   bits = data[0] | (data[1] << 8) | (data[2] << 16);
    381   idec->mem.part0_size = (bits >> 5) + VP8_FRAME_HEADER_SIZE;
    382 
    383   idec->io.data = data;
    384   idec->io.data_size = curr_size;
    385   idec->state = STATE_VP8_PARTS0;
    386   return VP8_STATUS_OK;
    387 }
    388 
    389 // Partition #0
    390 static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
    391   VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    392   VP8BitReader* const br = &dec->br;
    393   const size_t part_size = br->buf_end - br->buf;
    394   MemBuffer* const mem = &idec->mem;
    395   assert(!idec->is_lossless);
    396   assert(mem->part0_buf == NULL);
    397   // the following is a format limitation, no need for runtime check:
    398   assert(part_size <= mem->part0_size);
    399   if (part_size == 0) {   // can't have zero-size partition #0
    400     return VP8_STATUS_BITSTREAM_ERROR;
    401   }
    402   if (mem->mode == MEM_MODE_APPEND) {
    403     // We copy and grab ownership of the partition #0 data.
    404     uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size);
    405     if (part0_buf == NULL) {
    406       return VP8_STATUS_OUT_OF_MEMORY;
    407     }
    408     memcpy(part0_buf, br->buf, part_size);
    409     mem->part0_buf = part0_buf;
    410     VP8BitReaderSetBuffer(br, part0_buf, part_size);
    411   } else {
    412     // Else: just keep pointers to the partition #0's data in dec->br.
    413   }
    414   mem->start += part_size;
    415   return VP8_STATUS_OK;
    416 }
    417 
    418 static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
    419   VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    420   VP8Io* const io = &idec->io;
    421   const WebPDecParams* const params = &idec->params;
    422   WebPDecBuffer* const output = params->output;
    423 
    424   // Wait till we have enough data for the whole partition #0
    425   if (MemDataSize(&idec->mem) < idec->mem.part0_size) {
    426     return VP8_STATUS_SUSPENDED;
    427   }
    428 
    429   if (!VP8GetHeaders(dec, io)) {
    430     const VP8StatusCode status = dec->status;
    431     if (status == VP8_STATUS_SUSPENDED ||
    432         status == VP8_STATUS_NOT_ENOUGH_DATA) {
    433       // treating NOT_ENOUGH_DATA as SUSPENDED state
    434       return VP8_STATUS_SUSPENDED;
    435     }
    436     return IDecError(idec, status);
    437   }
    438 
    439   // Allocate/Verify output buffer now
    440   dec->status = WebPAllocateDecBuffer(io->width, io->height, params->options,
    441                                       output);
    442   if (dec->status != VP8_STATUS_OK) {
    443     return IDecError(idec, dec->status);
    444   }
    445   // This change must be done before calling VP8InitFrame()
    446   dec->mt_method = VP8GetThreadMethod(params->options, NULL,
    447                                       io->width, io->height);
    448   VP8InitDithering(params->options, dec);
    449 
    450   dec->status = CopyParts0Data(idec);
    451   if (dec->status != VP8_STATUS_OK) {
    452     return IDecError(idec, dec->status);
    453   }
    454 
    455   // Finish setting up the decoding parameters. Will call io->setup().
    456   if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) {
    457     return IDecError(idec, dec->status);
    458   }
    459 
    460   // Note: past this point, teardown() must always be called
    461   // in case of error.
    462   idec->state = STATE_VP8_DATA;
    463   // Allocate memory and prepare everything.
    464   if (!VP8InitFrame(dec, io)) {
    465     return IDecError(idec, dec->status);
    466   }
    467   return VP8_STATUS_OK;
    468 }
    469 
    470 // Remaining partitions
    471 static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
    472   VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    473   VP8Io* const io = &idec->io;
    474 
    475   // Make sure partition #0 has been read before, to set dec to ready.
    476   if (!dec->ready) {
    477     return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    478   }
    479   for (; dec->mb_y < dec->mb_h; ++dec->mb_y) {
    480     if (idec->last_mb_y != dec->mb_y) {
    481       if (!VP8ParseIntraModeRow(&dec->br, dec)) {
    482         // note: normally, error shouldn't occur since we already have the whole
    483         // partition0 available here in DecodeRemaining(). Reaching EOF while
    484         // reading intra modes really means a BITSTREAM_ERROR.
    485         return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    486       }
    487       idec->last_mb_y = dec->mb_y;
    488     }
    489     for (; dec->mb_x < dec->mb_w; ++dec->mb_x) {
    490       VP8BitReader* const token_br =
    491           &dec->parts[dec->mb_y & dec->num_parts_minus_one];
    492       MBContext context;
    493       SaveContext(dec, token_br, &context);
    494       if (!VP8DecodeMB(dec, token_br)) {
    495         // We shouldn't fail when MAX_MB data was available
    496         if (dec->num_parts_minus_one == 0 &&
    497             MemDataSize(&idec->mem) > MAX_MB_SIZE) {
    498           return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    499         }
    500         // Synchronize the threads.
    501         if (dec->mt_method > 0) {
    502           if (!WebPGetWorkerInterface()->Sync(&dec->worker)) {
    503             return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    504           }
    505         }
    506         RestoreContext(&context, dec, token_br);
    507         return VP8_STATUS_SUSPENDED;
    508       }
    509       // Release buffer only if there is only one partition
    510       if (dec->num_parts_minus_one == 0) {
    511         idec->mem.start = token_br->buf - idec->mem.buf;
    512         assert(idec->mem.start <= idec->mem.end);
    513       }
    514     }
    515     VP8InitScanline(dec);   // Prepare for next scanline
    516 
    517     // Reconstruct, filter and emit the row.
    518     if (!VP8ProcessRow(dec, io)) {
    519       return IDecError(idec, VP8_STATUS_USER_ABORT);
    520     }
    521   }
    522   // Synchronize the thread and check for errors.
    523   if (!VP8ExitCritical(dec, io)) {
    524     idec->state = STATE_ERROR;  // prevent re-entry in IDecError
    525     return IDecError(idec, VP8_STATUS_USER_ABORT);
    526   }
    527   dec->ready = 0;
    528   return FinishDecoding(idec);
    529 }
    530 
    531 static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
    532                                          VP8StatusCode status) {
    533   if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
    534     return VP8_STATUS_SUSPENDED;
    535   }
    536   return IDecError(idec, status);
    537 }
    538 
    539 static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) {
    540   VP8Io* const io = &idec->io;
    541   VP8LDecoder* const dec = (VP8LDecoder*)idec->dec;
    542   const WebPDecParams* const params = &idec->params;
    543   WebPDecBuffer* const output = params->output;
    544   size_t curr_size = MemDataSize(&idec->mem);
    545   assert(idec->is_lossless);
    546 
    547   // Wait until there's enough data for decoding header.
    548   if (curr_size < (idec->chunk_size >> 3)) {
    549     dec->status = VP8_STATUS_SUSPENDED;
    550     return ErrorStatusLossless(idec, dec->status);
    551   }
    552 
    553   if (!VP8LDecodeHeader(dec, io)) {
    554     if (dec->status == VP8_STATUS_BITSTREAM_ERROR &&
    555         curr_size < idec->chunk_size) {
    556       dec->status = VP8_STATUS_SUSPENDED;
    557     }
    558     return ErrorStatusLossless(idec, dec->status);
    559   }
    560   // Allocate/verify output buffer now.
    561   dec->status = WebPAllocateDecBuffer(io->width, io->height, params->options,
    562                                       output);
    563   if (dec->status != VP8_STATUS_OK) {
    564     return IDecError(idec, dec->status);
    565   }
    566 
    567   idec->state = STATE_VP8L_DATA;
    568   return VP8_STATUS_OK;
    569 }
    570 
    571 static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
    572   VP8LDecoder* const dec = (VP8LDecoder*)idec->dec;
    573   const size_t curr_size = MemDataSize(&idec->mem);
    574   assert(idec->is_lossless);
    575 
    576   // Switch to incremental decoding if we don't have all the bytes available.
    577   dec->incremental = (curr_size < idec->chunk_size);
    578 
    579   if (!VP8LDecodeImage(dec)) {
    580     return ErrorStatusLossless(idec, dec->status);
    581   }
    582   assert(dec->status == VP8_STATUS_OK || dec->status == VP8_STATUS_SUSPENDED);
    583   return (dec->status == VP8_STATUS_SUSPENDED) ? dec->status
    584                                                : FinishDecoding(idec);
    585 }
    586 
    587   // Main decoding loop
    588 static VP8StatusCode IDecode(WebPIDecoder* idec) {
    589   VP8StatusCode status = VP8_STATUS_SUSPENDED;
    590 
    591   if (idec->state == STATE_WEBP_HEADER) {
    592     status = DecodeWebPHeaders(idec);
    593   } else {
    594     if (idec->dec == NULL) {
    595       return VP8_STATUS_SUSPENDED;    // can't continue if we have no decoder.
    596     }
    597   }
    598   if (idec->state == STATE_VP8_HEADER) {
    599     status = DecodeVP8FrameHeader(idec);
    600   }
    601   if (idec->state == STATE_VP8_PARTS0) {
    602     status = DecodePartition0(idec);
    603   }
    604   if (idec->state == STATE_VP8_DATA) {
    605     const VP8Decoder* const dec = (VP8Decoder*)idec->dec;
    606     if (dec == NULL) {
    607       return VP8_STATUS_SUSPENDED;  // can't continue if we have no decoder.
    608     }
    609     status = DecodeRemaining(idec);
    610   }
    611   if (idec->state == STATE_VP8L_HEADER) {
    612     status = DecodeVP8LHeader(idec);
    613   }
    614   if (idec->state == STATE_VP8L_DATA) {
    615     status = DecodeVP8LData(idec);
    616   }
    617   return status;
    618 }
    619 
    620 //------------------------------------------------------------------------------
    621 // Internal constructor
    622 
    623 WEBP_NODISCARD static WebPIDecoder* NewDecoder(
    624     WebPDecBuffer* const output_buffer,
    625     const WebPBitstreamFeatures* const features) {
    626   WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
    627   if (idec == NULL) {
    628     return NULL;
    629   }
    630 
    631   idec->state = STATE_WEBP_HEADER;
    632   idec->chunk_size = 0;
    633 
    634   idec->last_mb_y = -1;
    635 
    636   InitMemBuffer(&idec->mem);
    637   if (!WebPInitDecBuffer(&idec->output) || !VP8InitIo(&idec->io)) {
    638     WebPSafeFree(idec);
    639     return NULL;
    640   }
    641 
    642   WebPResetDecParams(&idec->params);
    643   if (output_buffer == NULL || WebPAvoidSlowMemory(output_buffer, features)) {
    644     idec->params.output = &idec->output;
    645     idec->final_output = output_buffer;
    646     if (output_buffer != NULL) {
    647       idec->params.output->colorspace = output_buffer->colorspace;
    648     }
    649   } else {
    650     idec->params.output = output_buffer;
    651     idec->final_output = NULL;
    652   }
    653   WebPInitCustomIo(&idec->params, &idec->io);  // Plug the I/O functions.
    654 
    655   return idec;
    656 }
    657 
    658 //------------------------------------------------------------------------------
    659 // Public functions
    660 
    661 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
    662   return NewDecoder(output_buffer, NULL);
    663 }
    664 
    665 WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
    666                           WebPDecoderConfig* config) {
    667   WebPIDecoder* idec;
    668   WebPBitstreamFeatures tmp_features;
    669   WebPBitstreamFeatures* const features =
    670       (config == NULL) ? &tmp_features : &config->input;
    671   memset(&tmp_features, 0, sizeof(tmp_features));
    672 
    673   // Parse the bitstream's features, if requested:
    674   if (data != NULL && data_size > 0) {
    675     if (WebPGetFeatures(data, data_size, features) != VP8_STATUS_OK) {
    676       return NULL;
    677     }
    678   }
    679 
    680   // Create an instance of the incremental decoder
    681   idec = (config != NULL) ? NewDecoder(&config->output, features)
    682                           : NewDecoder(NULL, features);
    683   if (idec == NULL) {
    684     return NULL;
    685   }
    686   // Finish initialization
    687   if (config != NULL) {
    688     idec->params.options = &config->options;
    689   }
    690   return idec;
    691 }
    692 
    693 void WebPIDelete(WebPIDecoder* idec) {
    694   if (idec == NULL) return;
    695   if (idec->dec != NULL) {
    696     if (!idec->is_lossless) {
    697       if (idec->state == STATE_VP8_DATA) {
    698         // Synchronize the thread, clean-up and check for errors.
    699         // TODO(vrabaud) do we care about the return result?
    700         (void)VP8ExitCritical((VP8Decoder*)idec->dec, &idec->io);
    701       }
    702       VP8Delete((VP8Decoder*)idec->dec);
    703     } else {
    704       VP8LDelete((VP8LDecoder*)idec->dec);
    705     }
    706   }
    707   ClearMemBuffer(&idec->mem);
    708   WebPFreeDecBuffer(&idec->output);
    709   WebPSafeFree(idec);
    710 }
    711 
    712 //------------------------------------------------------------------------------
    713 // Wrapper toward WebPINewDecoder
    714 
    715 WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, uint8_t* output_buffer,
    716                           size_t output_buffer_size, int output_stride) {
    717   const int is_external_memory = (output_buffer != NULL) ? 1 : 0;
    718   WebPIDecoder* idec;
    719 
    720   if (csp >= MODE_YUV) return NULL;
    721   if (is_external_memory == 0) {    // Overwrite parameters to sane values.
    722     output_buffer_size = 0;
    723     output_stride = 0;
    724   } else {  // A buffer was passed. Validate the other params.
    725     if (output_stride == 0 || output_buffer_size == 0) {
    726       return NULL;   // invalid parameter.
    727     }
    728   }
    729   idec = WebPINewDecoder(NULL);
    730   if (idec == NULL) return NULL;
    731   idec->output.colorspace = csp;
    732   idec->output.is_external_memory = is_external_memory;
    733   idec->output.u.RGBA.rgba = output_buffer;
    734   idec->output.u.RGBA.stride = output_stride;
    735   idec->output.u.RGBA.size = output_buffer_size;
    736   return idec;
    737 }
    738 
    739 WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
    740                            uint8_t* u, size_t u_size, int u_stride,
    741                            uint8_t* v, size_t v_size, int v_stride,
    742                            uint8_t* a, size_t a_size, int a_stride) {
    743   const int is_external_memory = (luma != NULL) ? 1 : 0;
    744   WebPIDecoder* idec;
    745   WEBP_CSP_MODE colorspace;
    746 
    747   if (is_external_memory == 0) {    // Overwrite parameters to sane values.
    748     luma_size = u_size = v_size = a_size = 0;
    749     luma_stride = u_stride = v_stride = a_stride = 0;
    750     u = v = a = NULL;
    751     colorspace = MODE_YUVA;
    752   } else {  // A luma buffer was passed. Validate the other parameters.
    753     if (u == NULL || v == NULL) return NULL;
    754     if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL;
    755     if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL;
    756     if (a != NULL) {
    757       if (a_size == 0 || a_stride == 0) return NULL;
    758     }
    759     colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
    760   }
    761 
    762   idec = WebPINewDecoder(NULL);
    763   if (idec == NULL) return NULL;
    764 
    765   idec->output.colorspace = colorspace;
    766   idec->output.is_external_memory = is_external_memory;
    767   idec->output.u.YUVA.y = luma;
    768   idec->output.u.YUVA.y_stride = luma_stride;
    769   idec->output.u.YUVA.y_size = luma_size;
    770   idec->output.u.YUVA.u = u;
    771   idec->output.u.YUVA.u_stride = u_stride;
    772   idec->output.u.YUVA.u_size = u_size;
    773   idec->output.u.YUVA.v = v;
    774   idec->output.u.YUVA.v_stride = v_stride;
    775   idec->output.u.YUVA.v_size = v_size;
    776   idec->output.u.YUVA.a = a;
    777   idec->output.u.YUVA.a_stride = a_stride;
    778   idec->output.u.YUVA.a_size = a_size;
    779   return idec;
    780 }
    781 
    782 WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
    783                           uint8_t* u, size_t u_size, int u_stride,
    784                           uint8_t* v, size_t v_size, int v_stride) {
    785   return WebPINewYUVA(luma, luma_size, luma_stride,
    786                       u, u_size, u_stride,
    787                       v, v_size, v_stride,
    788                       NULL, 0, 0);
    789 }
    790 
    791 //------------------------------------------------------------------------------
    792 
    793 static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
    794   assert(idec);
    795   if (idec->state == STATE_ERROR) {
    796     return VP8_STATUS_BITSTREAM_ERROR;
    797   }
    798   if (idec->state == STATE_DONE) {
    799     return VP8_STATUS_OK;
    800   }
    801   return VP8_STATUS_SUSPENDED;
    802 }
    803 
    804 VP8StatusCode WebPIAppend(WebPIDecoder* idec,
    805                           const uint8_t* data, size_t data_size) {
    806   VP8StatusCode status;
    807   if (idec == NULL || data == NULL) {
    808     return VP8_STATUS_INVALID_PARAM;
    809   }
    810   status = IDecCheckStatus(idec);
    811   if (status != VP8_STATUS_SUSPENDED) {
    812     return status;
    813   }
    814   // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
    815   if (!CheckMemBufferMode(&idec->mem, MEM_MODE_APPEND)) {
    816     return VP8_STATUS_INVALID_PARAM;
    817   }
    818   // Append data to memory buffer
    819   if (!AppendToMemBuffer(idec, data, data_size)) {
    820     return VP8_STATUS_OUT_OF_MEMORY;
    821   }
    822   return IDecode(idec);
    823 }
    824 
    825 VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
    826                           const uint8_t* data, size_t data_size) {
    827   VP8StatusCode status;
    828   if (idec == NULL || data == NULL) {
    829     return VP8_STATUS_INVALID_PARAM;
    830   }
    831   status = IDecCheckStatus(idec);
    832   if (status != VP8_STATUS_SUSPENDED) {
    833     return status;
    834   }
    835   // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
    836   if (!CheckMemBufferMode(&idec->mem, MEM_MODE_MAP)) {
    837     return VP8_STATUS_INVALID_PARAM;
    838   }
    839   // Make the memory buffer point to the new buffer
    840   if (!RemapMemBuffer(idec, data, data_size)) {
    841     return VP8_STATUS_INVALID_PARAM;
    842   }
    843   return IDecode(idec);
    844 }
    845 
    846 //------------------------------------------------------------------------------
    847 
    848 static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) {
    849   if (idec == NULL || idec->dec == NULL) {
    850     return NULL;
    851   }
    852   if (idec->state <= STATE_VP8_PARTS0) {
    853     return NULL;
    854   }
    855   if (idec->final_output != NULL) {
    856     return NULL;   // not yet slow-copied
    857   }
    858   return idec->params.output;
    859 }
    860 
    861 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
    862                                       int* left, int* top,
    863                                       int* width, int* height) {
    864   const WebPDecBuffer* const src = GetOutputBuffer(idec);
    865   if (left != NULL) *left = 0;
    866   if (top != NULL) *top = 0;
    867   if (src != NULL) {
    868     if (width != NULL) *width = src->width;
    869     if (height != NULL) *height = idec->params.last_y;
    870   } else {
    871     if (width != NULL) *width = 0;
    872     if (height != NULL) *height = 0;
    873   }
    874   return src;
    875 }
    876 
    877 WEBP_NODISCARD uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
    878                                        int* width, int* height, int* stride) {
    879   const WebPDecBuffer* const src = GetOutputBuffer(idec);
    880   if (src == NULL) return NULL;
    881   if (src->colorspace >= MODE_YUV) {
    882     return NULL;
    883   }
    884 
    885   if (last_y != NULL) *last_y = idec->params.last_y;
    886   if (width != NULL) *width = src->width;
    887   if (height != NULL) *height = src->height;
    888   if (stride != NULL) *stride = src->u.RGBA.stride;
    889 
    890   return src->u.RGBA.rgba;
    891 }
    892 
    893 WEBP_NODISCARD uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
    894                                         uint8_t** u, uint8_t** v, uint8_t** a,
    895                                         int* width, int* height, int* stride,
    896                                         int* uv_stride, int* a_stride) {
    897   const WebPDecBuffer* const src = GetOutputBuffer(idec);
    898   if (src == NULL) return NULL;
    899   if (src->colorspace < MODE_YUV) {
    900     return NULL;
    901   }
    902 
    903   if (last_y != NULL) *last_y = idec->params.last_y;
    904   if (u != NULL) *u = src->u.YUVA.u;
    905   if (v != NULL) *v = src->u.YUVA.v;
    906   if (a != NULL) *a = src->u.YUVA.a;
    907   if (width != NULL) *width = src->width;
    908   if (height != NULL) *height = src->height;
    909   if (stride != NULL) *stride = src->u.YUVA.y_stride;
    910   if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride;
    911   if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride;
    912 
    913   return src->u.YUVA.y;
    914 }
    915 
    916 int WebPISetIOHooks(WebPIDecoder* const idec,
    917                     VP8IoPutHook put,
    918                     VP8IoSetupHook setup,
    919                     VP8IoTeardownHook teardown,
    920                     void* user_data) {
    921   if (idec == NULL || idec->state > STATE_WEBP_HEADER) {
    922     return 0;
    923   }
    924 
    925   idec->io.put = put;
    926   idec->io.setup = setup;
    927   idec->io.teardown = teardown;
    928   idec->io.opaque = user_data;
    929 
    930   return 1;
    931 }