Home | History | Annotate | Download | only in dec
      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 (at) google.com (Somnath Banerjee)
     13 
     14 #include <assert.h>
     15 #include <string.h>
     16 #include <stdlib.h>
     17 
     18 #include "./webpi.h"
     19 #include "./vp8i.h"
     20 #include "../utils/utils.h"
     21 
     22 #if defined(__cplusplus) || defined(c_plusplus)
     23 extern "C" {
     24 #endif
     25 
     26 // In append mode, buffer allocations increase as multiples of this value.
     27 // Needs to be a power of 2.
     28 #define CHUNK_SIZE 4096
     29 #define MAX_MB_SIZE 4096
     30 
     31 //------------------------------------------------------------------------------
     32 // Data structures for memory and states
     33 
     34 // Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE.
     35 // If there is any error the decoder goes into state ERROR.
     36 typedef enum {
     37   STATE_PRE_VP8,  // All data before that of the first VP8 chunk.
     38   STATE_VP8_FRAME_HEADER,  // For VP8 Frame header (within VP8 chunk).
     39   STATE_VP8_PARTS0,
     40   STATE_VP8_DATA,
     41   STATE_VP8L_HEADER,
     42   STATE_VP8L_DATA,
     43   STATE_DONE,
     44   STATE_ERROR
     45 } DecState;
     46 
     47 // Operating state for the MemBuffer
     48 typedef enum {
     49   MEM_MODE_NONE = 0,
     50   MEM_MODE_APPEND,
     51   MEM_MODE_MAP
     52 } MemBufferMode;
     53 
     54 // storage for partition #0 and partial data (in a rolling fashion)
     55 typedef struct {
     56   MemBufferMode mode_;  // Operation mode
     57   size_t start_;        // start location of the data to be decoded
     58   size_t end_;          // end location
     59   size_t buf_size_;     // size of the allocated buffer
     60   uint8_t* buf_;        // We don't own this buffer in case WebPIUpdate()
     61 
     62   size_t part0_size_;         // size of partition #0
     63   const uint8_t* part0_buf_;  // buffer to store partition #0
     64 } MemBuffer;
     65 
     66 struct WebPIDecoder {
     67   DecState state_;         // current decoding state
     68   WebPDecParams params_;   // Params to store output info
     69   int is_lossless_;        // for down-casting 'dec_'.
     70   void* dec_;              // either a VP8Decoder or a VP8LDecoder instance
     71   VP8Io io_;
     72 
     73   MemBuffer mem_;          // input memory buffer.
     74   WebPDecBuffer output_;   // output buffer (when no external one is supplied)
     75   size_t chunk_size_;      // Compressed VP8/VP8L size extracted from Header.
     76 };
     77 
     78 // MB context to restore in case VP8DecodeMB() fails
     79 typedef struct {
     80   VP8MB left_;
     81   VP8MB info_;
     82   uint8_t intra_t_[4];
     83   uint8_t intra_l_[4];
     84   VP8BitReader br_;
     85   VP8BitReader token_br_;
     86 } MBContext;
     87 
     88 //------------------------------------------------------------------------------
     89 // MemBuffer: incoming data handling
     90 
     91 static void RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
     92   if (br->buf_ != NULL) {
     93     br->buf_ += offset;
     94     br->buf_end_ += offset;
     95   }
     96 }
     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_PRE_VP8) {
    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_PRE_VP8.
    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 int last_part = dec->num_parts_ - 1;
    131       if (offset != 0) {
    132         int p;
    133         for (p = 0; p <= last_part; ++p) {
    134           RemapBitReader(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           RemapBitReader(&dec->br_, offset);
    140         }
    141       }
    142       assert(last_part >= 0);
    143       dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
    144       if (NeedCompressedAlpha(idec)) dec->alpha_data_ += offset;
    145     } else {    // Resize lossless bitreader
    146       VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
    147       VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem));
    148     }
    149   }
    150 }
    151 
    152 // Appends data to the end of MemBuffer->buf_. It expands the allocated memory
    153 // size if required and also updates VP8BitReader's if new memory is allocated.
    154 static int AppendToMemBuffer(WebPIDecoder* const idec,
    155                              const uint8_t* const data, size_t data_size) {
    156   VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
    157   MemBuffer* const mem = &idec->mem_;
    158   const int need_compressed_alpha = NeedCompressedAlpha(idec);
    159   const uint8_t* const old_start = mem->buf_ + mem->start_;
    160   const uint8_t* const old_base =
    161       need_compressed_alpha ? dec->alpha_data_ : old_start;
    162   assert(mem->mode_ == MEM_MODE_APPEND);
    163   if (data_size > MAX_CHUNK_PAYLOAD) {
    164     // security safeguard: trying to allocate more than what the format
    165     // allows for a chunk should be considered a smoke smell.
    166     return 0;
    167   }
    168 
    169   if (mem->end_ + data_size > mem->buf_size_) {  // Need some free memory
    170     const size_t new_mem_start = old_start - old_base;
    171     const size_t current_size = MemDataSize(mem) + new_mem_start;
    172     const uint64_t new_size = (uint64_t)current_size + data_size;
    173     const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
    174     uint8_t* const new_buf =
    175         (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
    176     if (new_buf == NULL) return 0;
    177     memcpy(new_buf, old_base, current_size);
    178     free(mem->buf_);
    179     mem->buf_ = new_buf;
    180     mem->buf_size_ = (size_t)extra_size;
    181     mem->start_ = new_mem_start;
    182     mem->end_ = current_size;
    183   }
    184 
    185   memcpy(mem->buf_ + mem->end_, data, data_size);
    186   mem->end_ += data_size;
    187   assert(mem->end_ <= mem->buf_size_);
    188 
    189   DoRemap(idec, mem->buf_ + mem->start_ - old_start);
    190   return 1;
    191 }
    192 
    193 static int RemapMemBuffer(WebPIDecoder* const idec,
    194                           const uint8_t* const data, size_t data_size) {
    195   MemBuffer* const mem = &idec->mem_;
    196   const uint8_t* const old_buf = mem->buf_;
    197   const uint8_t* const old_start = old_buf + mem->start_;
    198   assert(mem->mode_ == MEM_MODE_MAP);
    199 
    200   if (data_size < mem->buf_size_) return 0;  // can't remap to a shorter buffer!
    201 
    202   mem->buf_ = (uint8_t*)data;
    203   mem->end_ = mem->buf_size_ = data_size;
    204 
    205   DoRemap(idec, mem->buf_ + mem->start_ - old_start);
    206   return 1;
    207 }
    208 
    209 static void InitMemBuffer(MemBuffer* const mem) {
    210   mem->mode_       = MEM_MODE_NONE;
    211   mem->buf_        = NULL;
    212   mem->buf_size_   = 0;
    213   mem->part0_buf_  = NULL;
    214   mem->part0_size_ = 0;
    215 }
    216 
    217 static void ClearMemBuffer(MemBuffer* const mem) {
    218   assert(mem);
    219   if (mem->mode_ == MEM_MODE_APPEND) {
    220     free(mem->buf_);
    221     free((void*)mem->part0_buf_);
    222   }
    223 }
    224 
    225 static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
    226   if (mem->mode_ == MEM_MODE_NONE) {
    227     mem->mode_ = expected;    // switch to the expected mode
    228   } else if (mem->mode_ != expected) {
    229     return 0;         // we mixed the modes => error
    230   }
    231   assert(mem->mode_ == expected);   // mode is ok
    232   return 1;
    233 }
    234 
    235 //------------------------------------------------------------------------------
    236 // Macroblock-decoding contexts
    237 
    238 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
    239                         MBContext* const context) {
    240   const VP8BitReader* const br = &dec->br_;
    241   const VP8MB* const left = dec->mb_info_ - 1;
    242   const VP8MB* const info = dec->mb_info_ + dec->mb_x_;
    243 
    244   context->left_ = *left;
    245   context->info_ = *info;
    246   context->br_ = *br;
    247   context->token_br_ = *token_br;
    248   memcpy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4);
    249   memcpy(context->intra_l_, dec->intra_l_, 4);
    250 }
    251 
    252 static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
    253                            VP8BitReader* const token_br) {
    254   VP8BitReader* const br = &dec->br_;
    255   VP8MB* const left = dec->mb_info_ - 1;
    256   VP8MB* const info = dec->mb_info_ + dec->mb_x_;
    257 
    258   *left = context->left_;
    259   *info = context->info_;
    260   *br = context->br_;
    261   *token_br = context->token_br_;
    262   memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4);
    263   memcpy(dec->intra_l_, context->intra_l_, 4);
    264 }
    265 
    266 //------------------------------------------------------------------------------
    267 
    268 static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
    269   if (idec->state_ == STATE_VP8_DATA) {
    270     VP8Io* const io = &idec->io_;
    271     if (io->teardown) {
    272       io->teardown(io);
    273     }
    274   }
    275   idec->state_ = STATE_ERROR;
    276   return error;
    277 }
    278 
    279 static void ChangeState(WebPIDecoder* const idec, DecState new_state,
    280                         size_t consumed_bytes) {
    281   MemBuffer* const mem = &idec->mem_;
    282   idec->state_ = new_state;
    283   mem->start_ += consumed_bytes;
    284   assert(mem->start_ <= mem->end_);
    285   idec->io_.data = mem->buf_ + mem->start_;
    286   idec->io_.data_size = MemDataSize(mem);
    287 }
    288 
    289 // Headers
    290 static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
    291   MemBuffer* const mem = &idec->mem_;
    292   const uint8_t* data = mem->buf_ + mem->start_;
    293   size_t curr_size = MemDataSize(mem);
    294   VP8StatusCode status;
    295   WebPHeaderStructure headers;
    296 
    297   headers.data = data;
    298   headers.data_size = curr_size;
    299   status = WebPParseHeaders(&headers);
    300   if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
    301     return VP8_STATUS_SUSPENDED;  // We haven't found a VP8 chunk yet.
    302   } else if (status != VP8_STATUS_OK) {
    303     return IDecError(idec, status);
    304   }
    305 
    306   idec->chunk_size_ = headers.compressed_size;
    307   idec->is_lossless_ = headers.is_lossless;
    308   if (!idec->is_lossless_) {
    309     VP8Decoder* const dec = VP8New();
    310     if (dec == NULL) {
    311       return VP8_STATUS_OUT_OF_MEMORY;
    312     }
    313     idec->dec_ = dec;
    314 #ifdef WEBP_USE_THREAD
    315     dec->use_threads_ = (idec->params_.options != NULL) &&
    316                         (idec->params_.options->use_threads > 0);
    317 #else
    318     dec->use_threads_ = 0;
    319 #endif
    320     dec->alpha_data_ = headers.alpha_data;
    321     dec->alpha_data_size_ = headers.alpha_data_size;
    322     ChangeState(idec, STATE_VP8_FRAME_HEADER, headers.offset);
    323   } else {
    324     VP8LDecoder* const dec = VP8LNew();
    325     if (dec == NULL) {
    326       return VP8_STATUS_OUT_OF_MEMORY;
    327     }
    328     idec->dec_ = dec;
    329     ChangeState(idec, STATE_VP8L_HEADER, headers.offset);
    330   }
    331   return VP8_STATUS_OK;
    332 }
    333 
    334 static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
    335   const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_;
    336   const size_t curr_size = MemDataSize(&idec->mem_);
    337   uint32_t bits;
    338 
    339   if (curr_size < VP8_FRAME_HEADER_SIZE) {
    340     // Not enough data bytes to extract VP8 Frame Header.
    341     return VP8_STATUS_SUSPENDED;
    342   }
    343   if (!VP8GetInfo(data, curr_size, idec->chunk_size_, NULL, NULL)) {
    344     return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    345   }
    346 
    347   bits = data[0] | (data[1] << 8) | (data[2] << 16);
    348   idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE;
    349 
    350   idec->io_.data = data;
    351   idec->io_.data_size = curr_size;
    352   idec->state_ = STATE_VP8_PARTS0;
    353   return VP8_STATUS_OK;
    354 }
    355 
    356 // Partition #0
    357 static int CopyParts0Data(WebPIDecoder* const idec) {
    358   VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
    359   VP8BitReader* const br = &dec->br_;
    360   const size_t psize = br->buf_end_ - br->buf_;
    361   MemBuffer* const mem = &idec->mem_;
    362   assert(!idec->is_lossless_);
    363   assert(mem->part0_buf_ == NULL);
    364   assert(psize > 0);
    365   assert(psize <= mem->part0_size_);  // Format limit: no need for runtime check
    366   if (mem->mode_ == MEM_MODE_APPEND) {
    367     // We copy and grab ownership of the partition #0 data.
    368     uint8_t* const part0_buf = (uint8_t*)malloc(psize);
    369     if (part0_buf == NULL) {
    370       return 0;
    371     }
    372     memcpy(part0_buf, br->buf_, psize);
    373     mem->part0_buf_ = part0_buf;
    374     br->buf_ = part0_buf;
    375     br->buf_end_ = part0_buf + psize;
    376   } else {
    377     // Else: just keep pointers to the partition #0's data in dec_->br_.
    378   }
    379   mem->start_ += psize;
    380   return 1;
    381 }
    382 
    383 static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
    384   VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
    385   VP8Io* const io = &idec->io_;
    386   const WebPDecParams* const params = &idec->params_;
    387   WebPDecBuffer* const output = params->output;
    388 
    389   // Wait till we have enough data for the whole partition #0
    390   if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) {
    391     return VP8_STATUS_SUSPENDED;
    392   }
    393 
    394   if (!VP8GetHeaders(dec, io)) {
    395     const VP8StatusCode status = dec->status_;
    396     if (status == VP8_STATUS_SUSPENDED ||
    397         status == VP8_STATUS_NOT_ENOUGH_DATA) {
    398       // treating NOT_ENOUGH_DATA as SUSPENDED state
    399       return VP8_STATUS_SUSPENDED;
    400     }
    401     return IDecError(idec, status);
    402   }
    403 
    404   // Allocate/Verify output buffer now
    405   dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options,
    406                                        output);
    407   if (dec->status_ != VP8_STATUS_OK) {
    408     return IDecError(idec, dec->status_);
    409   }
    410 
    411   if (!CopyParts0Data(idec)) {
    412     return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY);
    413   }
    414 
    415   // Finish setting up the decoding parameters. Will call io->setup().
    416   if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) {
    417     return IDecError(idec, dec->status_);
    418   }
    419 
    420   // Note: past this point, teardown() must always be called
    421   // in case of error.
    422   idec->state_ = STATE_VP8_DATA;
    423   // Allocate memory and prepare everything.
    424   if (!VP8InitFrame(dec, io)) {
    425     return IDecError(idec, dec->status_);
    426   }
    427   return VP8_STATUS_OK;
    428 }
    429 
    430 // Remaining partitions
    431 static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
    432   VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
    433   VP8Io* const io = &idec->io_;
    434 
    435   assert(dec->ready_);
    436 
    437   for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
    438     VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
    439     if (dec->mb_x_ == 0) {
    440       VP8InitScanline(dec);
    441     }
    442     for (; dec->mb_x_ < dec->mb_w_;  dec->mb_x_++) {
    443       MBContext context;
    444       SaveContext(dec, token_br, &context);
    445 
    446       if (!VP8DecodeMB(dec, token_br)) {
    447         RestoreContext(&context, dec, token_br);
    448         // We shouldn't fail when MAX_MB data was available
    449         if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
    450           return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
    451         }
    452         return VP8_STATUS_SUSPENDED;
    453       }
    454       // Reconstruct and emit samples.
    455       VP8ReconstructBlock(dec);
    456 
    457       // Release buffer only if there is only one partition
    458       if (dec->num_parts_ == 1) {
    459         idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_;
    460         assert(idec->mem_.start_ <= idec->mem_.end_);
    461       }
    462     }
    463     if (!VP8ProcessRow(dec, io)) {
    464       return IDecError(idec, VP8_STATUS_USER_ABORT);
    465     }
    466     dec->mb_x_ = 0;
    467   }
    468   // Synchronize the thread and check for errors.
    469   if (!VP8ExitCritical(dec, io)) {
    470     return IDecError(idec, VP8_STATUS_USER_ABORT);
    471   }
    472   dec->ready_ = 0;
    473   idec->state_ = STATE_DONE;
    474 
    475   return VP8_STATUS_OK;
    476 }
    477 
    478 static int ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) {
    479   if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
    480     return VP8_STATUS_SUSPENDED;
    481   }
    482   return IDecError(idec, status);
    483 }
    484 
    485 static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) {
    486   VP8Io* const io = &idec->io_;
    487   VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
    488   const WebPDecParams* const params = &idec->params_;
    489   WebPDecBuffer* const output = params->output;
    490   size_t curr_size = MemDataSize(&idec->mem_);
    491   assert(idec->is_lossless_);
    492 
    493   // Wait until there's enough data for decoding header.
    494   if (curr_size < (idec->chunk_size_ >> 3)) {
    495     return VP8_STATUS_SUSPENDED;
    496   }
    497   if (!VP8LDecodeHeader(dec, io)) {
    498     return ErrorStatusLossless(idec, dec->status_);
    499   }
    500   // Allocate/verify output buffer now.
    501   dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options,
    502                                        output);
    503   if (dec->status_ != VP8_STATUS_OK) {
    504     return IDecError(idec, dec->status_);
    505   }
    506 
    507   idec->state_ = STATE_VP8L_DATA;
    508   return VP8_STATUS_OK;
    509 }
    510 
    511 static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
    512   VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
    513   const size_t curr_size = MemDataSize(&idec->mem_);
    514   assert(idec->is_lossless_);
    515 
    516   // At present Lossless decoder can't decode image incrementally. So wait till
    517   // all the image data is aggregated before image can be decoded.
    518   if (curr_size < idec->chunk_size_) {
    519     return VP8_STATUS_SUSPENDED;
    520   }
    521 
    522   if (!VP8LDecodeImage(dec)) {
    523     return ErrorStatusLossless(idec, dec->status_);
    524   }
    525 
    526   idec->state_ = STATE_DONE;
    527 
    528   return VP8_STATUS_OK;
    529 }
    530 
    531   // Main decoding loop
    532 static VP8StatusCode IDecode(WebPIDecoder* idec) {
    533   VP8StatusCode status = VP8_STATUS_SUSPENDED;
    534 
    535   if (idec->state_ == STATE_PRE_VP8) {
    536     status = DecodeWebPHeaders(idec);
    537   } else {
    538     if (idec->dec_ == NULL) {
    539       return VP8_STATUS_SUSPENDED;    // can't continue if we have no decoder.
    540     }
    541   }
    542   if (idec->state_ == STATE_VP8_FRAME_HEADER) {
    543     status = DecodeVP8FrameHeader(idec);
    544   }
    545   if (idec->state_ == STATE_VP8_PARTS0) {
    546     status = DecodePartition0(idec);
    547   }
    548   if (idec->state_ == STATE_VP8_DATA) {
    549     status = DecodeRemaining(idec);
    550   }
    551   if (idec->state_ == STATE_VP8L_HEADER) {
    552     status = DecodeVP8LHeader(idec);
    553   }
    554   if (idec->state_ == STATE_VP8L_DATA) {
    555     status = DecodeVP8LData(idec);
    556   }
    557   return status;
    558 }
    559 
    560 //------------------------------------------------------------------------------
    561 // Public functions
    562 
    563 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
    564   WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec));
    565   if (idec == NULL) {
    566     return NULL;
    567   }
    568 
    569   idec->state_ = STATE_PRE_VP8;
    570   idec->chunk_size_ = 0;
    571 
    572   InitMemBuffer(&idec->mem_);
    573   WebPInitDecBuffer(&idec->output_);
    574   VP8InitIo(&idec->io_);
    575 
    576   WebPResetDecParams(&idec->params_);
    577   idec->params_.output = output_buffer ? output_buffer : &idec->output_;
    578   WebPInitCustomIo(&idec->params_, &idec->io_);  // Plug the I/O functions.
    579 
    580   return idec;
    581 }
    582 
    583 WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
    584                           WebPDecoderConfig* config) {
    585   WebPIDecoder* idec;
    586 
    587   // Parse the bitstream's features, if requested:
    588   if (data != NULL && data_size > 0 && config != NULL) {
    589     if (WebPGetFeatures(data, data_size, &config->input) != VP8_STATUS_OK) {
    590       return NULL;
    591     }
    592   }
    593   // Create an instance of the incremental decoder
    594   idec = WebPINewDecoder(config ? &config->output : NULL);
    595   if (idec == NULL) {
    596     return NULL;
    597   }
    598   // Finish initialization
    599   if (config != NULL) {
    600     idec->params_.options = &config->options;
    601   }
    602   return idec;
    603 }
    604 
    605 void WebPIDelete(WebPIDecoder* idec) {
    606   if (idec == NULL) return;
    607   if (idec->dec_ != NULL) {
    608     if (!idec->is_lossless_) {
    609       VP8Delete(idec->dec_);
    610     } else {
    611       VP8LDelete(idec->dec_);
    612     }
    613   }
    614   ClearMemBuffer(&idec->mem_);
    615   WebPFreeDecBuffer(&idec->output_);
    616   free(idec);
    617 }
    618 
    619 //------------------------------------------------------------------------------
    620 // Wrapper toward WebPINewDecoder
    621 
    622 WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
    623                           size_t output_buffer_size, int output_stride) {
    624   const int is_external_memory = (output_buffer != NULL);
    625   WebPIDecoder* idec;
    626 
    627   if (mode >= MODE_YUV) return NULL;
    628   if (!is_external_memory) {    // Overwrite parameters to sane values.
    629     output_buffer_size = 0;
    630     output_stride = 0;
    631   } else {  // A buffer was passed. Validate the other params.
    632     if (output_stride == 0 || output_buffer_size == 0) {
    633       return NULL;   // invalid parameter.
    634     }
    635   }
    636   idec = WebPINewDecoder(NULL);
    637   if (idec == NULL) return NULL;
    638   idec->output_.colorspace = mode;
    639   idec->output_.is_external_memory = is_external_memory;
    640   idec->output_.u.RGBA.rgba = output_buffer;
    641   idec->output_.u.RGBA.stride = output_stride;
    642   idec->output_.u.RGBA.size = output_buffer_size;
    643   return idec;
    644 }
    645 
    646 WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
    647                            uint8_t* u, size_t u_size, int u_stride,
    648                            uint8_t* v, size_t v_size, int v_stride,
    649                            uint8_t* a, size_t a_size, int a_stride) {
    650   const int is_external_memory = (luma != NULL);
    651   WebPIDecoder* idec;
    652   WEBP_CSP_MODE colorspace;
    653 
    654   if (!is_external_memory) {    // Overwrite parameters to sane values.
    655     luma_size = u_size = v_size = a_size = 0;
    656     luma_stride = u_stride = v_stride = a_stride = 0;
    657     u = v = a = NULL;
    658     colorspace = MODE_YUVA;
    659   } else {  // A luma buffer was passed. Validate the other parameters.
    660     if (u == NULL || v == NULL) return NULL;
    661     if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL;
    662     if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL;
    663     if (a != NULL) {
    664       if (a_size == 0 || a_stride == 0) return NULL;
    665     }
    666     colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
    667   }
    668 
    669   idec = WebPINewDecoder(NULL);
    670   if (idec == NULL) return NULL;
    671 
    672   idec->output_.colorspace = colorspace;
    673   idec->output_.is_external_memory = is_external_memory;
    674   idec->output_.u.YUVA.y = luma;
    675   idec->output_.u.YUVA.y_stride = luma_stride;
    676   idec->output_.u.YUVA.y_size = luma_size;
    677   idec->output_.u.YUVA.u = u;
    678   idec->output_.u.YUVA.u_stride = u_stride;
    679   idec->output_.u.YUVA.u_size = u_size;
    680   idec->output_.u.YUVA.v = v;
    681   idec->output_.u.YUVA.v_stride = v_stride;
    682   idec->output_.u.YUVA.v_size = v_size;
    683   idec->output_.u.YUVA.a = a;
    684   idec->output_.u.YUVA.a_stride = a_stride;
    685   idec->output_.u.YUVA.a_size = a_size;
    686   return idec;
    687 }
    688 
    689 WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
    690                           uint8_t* u, size_t u_size, int u_stride,
    691                           uint8_t* v, size_t v_size, int v_stride) {
    692   return WebPINewYUVA(luma, luma_size, luma_stride,
    693                       u, u_size, u_stride,
    694                       v, v_size, v_stride,
    695                       NULL, 0, 0);
    696 }
    697 
    698 //------------------------------------------------------------------------------
    699 
    700 static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
    701   assert(idec);
    702   if (idec->state_ == STATE_ERROR) {
    703     return VP8_STATUS_BITSTREAM_ERROR;
    704   }
    705   if (idec->state_ == STATE_DONE) {
    706     return VP8_STATUS_OK;
    707   }
    708   return VP8_STATUS_SUSPENDED;
    709 }
    710 
    711 VP8StatusCode WebPIAppend(WebPIDecoder* idec,
    712                           const uint8_t* data, size_t data_size) {
    713   VP8StatusCode status;
    714   if (idec == NULL || data == NULL) {
    715     return VP8_STATUS_INVALID_PARAM;
    716   }
    717   status = IDecCheckStatus(idec);
    718   if (status != VP8_STATUS_SUSPENDED) {
    719     return status;
    720   }
    721   // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
    722   if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) {
    723     return VP8_STATUS_INVALID_PARAM;
    724   }
    725   // Append data to memory buffer
    726   if (!AppendToMemBuffer(idec, data, data_size)) {
    727     return VP8_STATUS_OUT_OF_MEMORY;
    728   }
    729   return IDecode(idec);
    730 }
    731 
    732 VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
    733                           const uint8_t* data, size_t data_size) {
    734   VP8StatusCode status;
    735   if (idec == NULL || data == NULL) {
    736     return VP8_STATUS_INVALID_PARAM;
    737   }
    738   status = IDecCheckStatus(idec);
    739   if (status != VP8_STATUS_SUSPENDED) {
    740     return status;
    741   }
    742   // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
    743   if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) {
    744     return VP8_STATUS_INVALID_PARAM;
    745   }
    746   // Make the memory buffer point to the new buffer
    747   if (!RemapMemBuffer(idec, data, data_size)) {
    748     return VP8_STATUS_INVALID_PARAM;
    749   }
    750   return IDecode(idec);
    751 }
    752 
    753 //------------------------------------------------------------------------------
    754 
    755 static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) {
    756   if (idec == NULL || idec->dec_ == NULL) {
    757     return NULL;
    758   }
    759   if (idec->state_ <= STATE_VP8_PARTS0) {
    760     return NULL;
    761   }
    762   return idec->params_.output;
    763 }
    764 
    765 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
    766                                       int* left, int* top,
    767                                       int* width, int* height) {
    768   const WebPDecBuffer* const src = GetOutputBuffer(idec);
    769   if (left != NULL) *left = 0;
    770   if (top != NULL) *top = 0;
    771   // TODO(skal): later include handling of rotations.
    772   if (src) {
    773     if (width != NULL) *width = src->width;
    774     if (height != NULL) *height = idec->params_.last_y;
    775   } else {
    776     if (width != NULL) *width = 0;
    777     if (height != NULL) *height = 0;
    778   }
    779   return src;
    780 }
    781 
    782 uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
    783                         int* width, int* height, int* stride) {
    784   const WebPDecBuffer* const src = GetOutputBuffer(idec);
    785   if (src == NULL) return NULL;
    786   if (src->colorspace >= MODE_YUV) {
    787     return NULL;
    788   }
    789 
    790   if (last_y != NULL) *last_y = idec->params_.last_y;
    791   if (width != NULL) *width = src->width;
    792   if (height != NULL) *height = src->height;
    793   if (stride != NULL) *stride = src->u.RGBA.stride;
    794 
    795   return src->u.RGBA.rgba;
    796 }
    797 
    798 uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
    799                          uint8_t** u, uint8_t** v, uint8_t** a,
    800                          int* width, int* height,
    801                          int* stride, int* uv_stride, int* a_stride) {
    802   const WebPDecBuffer* const src = GetOutputBuffer(idec);
    803   if (src == NULL) return NULL;
    804   if (src->colorspace < MODE_YUV) {
    805     return NULL;
    806   }
    807 
    808   if (last_y != NULL) *last_y = idec->params_.last_y;
    809   if (u != NULL) *u = src->u.YUVA.u;
    810   if (v != NULL) *v = src->u.YUVA.v;
    811   if (a != NULL) *a = src->u.YUVA.a;
    812   if (width != NULL) *width = src->width;
    813   if (height != NULL) *height = src->height;
    814   if (stride != NULL) *stride = src->u.YUVA.y_stride;
    815   if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride;
    816   if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride;
    817 
    818   return src->u.YUVA.y;
    819 }
    820 
    821 int WebPISetIOHooks(WebPIDecoder* const idec,
    822                     VP8IoPutHook put,
    823                     VP8IoSetupHook setup,
    824                     VP8IoTeardownHook teardown,
    825                     void* user_data) {
    826   if (idec == NULL || idec->state_ > STATE_PRE_VP8) {
    827     return 0;
    828   }
    829 
    830   idec->io_.put = put;
    831   idec->io_.setup = setup;
    832   idec->io_.teardown = teardown;
    833   idec->io_.opaque = user_data;
    834 
    835   return 1;
    836 }
    837 
    838 #if defined(__cplusplus) || defined(c_plusplus)
    839 }    // extern "C"
    840 #endif
    841