github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/webp/libwebp/src/dec/idec.c (about)

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