| OLD | NEW |
| 1 // Copyright 2011 Google Inc. All Rights Reserved. | 1 // Copyright 2011 Google Inc. All Rights Reserved. |
| 2 // | 2 // |
| 3 // Use of this source code is governed by a BSD-style license | 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 | 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 | 5 // tree. An additional intellectual property rights grant can be found |
| 6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
| 7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
| 8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
| 9 // | 9 // |
| 10 // Incremental decoding | 10 // Incremental decoding |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 int p; | 123 int p; |
| 124 for (p = 0; p <= last_part; ++p) { | 124 for (p = 0; p <= last_part; ++p) { |
| 125 VP8RemapBitReader(dec->parts_ + p, offset); | 125 VP8RemapBitReader(dec->parts_ + p, offset); |
| 126 } | 126 } |
| 127 // Remap partition #0 data pointer to new offset, but only in MAP | 127 // Remap partition #0 data pointer to new offset, but only in MAP |
| 128 // mode (in APPEND mode, partition #0 is copied into a fixed memory). | 128 // mode (in APPEND mode, partition #0 is copied into a fixed memory). |
| 129 if (mem->mode_ == MEM_MODE_MAP) { | 129 if (mem->mode_ == MEM_MODE_MAP) { |
| 130 VP8RemapBitReader(&dec->br_, offset); | 130 VP8RemapBitReader(&dec->br_, offset); |
| 131 } | 131 } |
| 132 } | 132 } |
| 133 assert(last_part >= 0); | 133 { |
| 134 dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_; | 134 const uint8_t* const last_start = dec->parts_[last_part].buf_; |
| 135 assert(last_part >= 0); |
| 136 VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start, |
| 137 mem->buf_ + mem->end_ - last_start); |
| 138 } |
| 135 if (NeedCompressedAlpha(idec)) { | 139 if (NeedCompressedAlpha(idec)) { |
| 136 ALPHDecoder* const alph_dec = dec->alph_dec_; | 140 ALPHDecoder* const alph_dec = dec->alph_dec_; |
| 137 dec->alpha_data_ += offset; | 141 dec->alpha_data_ += offset; |
| 138 if (alph_dec != NULL) { | 142 if (alph_dec != NULL) { |
| 139 if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { | 143 if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) { |
| 140 VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; | 144 VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_; |
| 141 assert(alph_vp8l_dec != NULL); | 145 assert(alph_vp8l_dec != NULL); |
| 142 assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN); | 146 assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN); |
| 143 VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_, | 147 VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_, |
| 144 dec->alpha_data_ + ALPHA_HEADER_LEN, | 148 dec->alpha_data_ + ALPHA_HEADER_LEN, |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 mem->mode_ = expected; // switch to the expected mode | 237 mem->mode_ = expected; // switch to the expected mode |
| 234 } else if (mem->mode_ != expected) { | 238 } else if (mem->mode_ != expected) { |
| 235 return 0; // we mixed the modes => error | 239 return 0; // we mixed the modes => error |
| 236 } | 240 } |
| 237 assert(mem->mode_ == expected); // mode is ok | 241 assert(mem->mode_ == expected); // mode is ok |
| 238 return 1; | 242 return 1; |
| 239 } | 243 } |
| 240 | 244 |
| 241 // To be called last. | 245 // To be called last. |
| 242 static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { | 246 static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) { |
| 243 #if WEBP_DECODER_ABI_VERSION > 0x0203 | |
| 244 const WebPDecoderOptions* const options = idec->params_.options; | 247 const WebPDecoderOptions* const options = idec->params_.options; |
| 245 WebPDecBuffer* const output = idec->params_.output; | 248 WebPDecBuffer* const output = idec->params_.output; |
| 246 | 249 |
| 247 idec->state_ = STATE_DONE; | 250 idec->state_ = STATE_DONE; |
| 248 if (options != NULL && options->flip) { | 251 if (options != NULL && options->flip) { |
| 249 return WebPFlipBuffer(output); | 252 return WebPFlipBuffer(output); |
| 253 } else { |
| 254 return VP8_STATUS_OK; |
| 250 } | 255 } |
| 251 #endif | |
| 252 idec->state_ = STATE_DONE; | |
| 253 return VP8_STATUS_OK; | |
| 254 } | 256 } |
| 255 | 257 |
| 256 //------------------------------------------------------------------------------ | 258 //------------------------------------------------------------------------------ |
| 257 // Macroblock-decoding contexts | 259 // Macroblock-decoding contexts |
| 258 | 260 |
| 259 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, | 261 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, |
| 260 MBContext* const context) { | 262 MBContext* const context) { |
| 261 context->left_ = dec->mb_info_[-1]; | 263 context->left_ = dec->mb_info_[-1]; |
| 262 context->info_ = dec->mb_info_[dec->mb_x_]; | 264 context->info_ = dec->mb_info_[dec->mb_x_]; |
| 263 context->token_br_ = *token_br; | 265 context->token_br_ = *token_br; |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 return VP8_STATUS_BITSTREAM_ERROR; | 372 return VP8_STATUS_BITSTREAM_ERROR; |
| 371 } | 373 } |
| 372 if (mem->mode_ == MEM_MODE_APPEND) { | 374 if (mem->mode_ == MEM_MODE_APPEND) { |
| 373 // We copy and grab ownership of the partition #0 data. | 375 // We copy and grab ownership of the partition #0 data. |
| 374 uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size); | 376 uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size); |
| 375 if (part0_buf == NULL) { | 377 if (part0_buf == NULL) { |
| 376 return VP8_STATUS_OUT_OF_MEMORY; | 378 return VP8_STATUS_OUT_OF_MEMORY; |
| 377 } | 379 } |
| 378 memcpy(part0_buf, br->buf_, part_size); | 380 memcpy(part0_buf, br->buf_, part_size); |
| 379 mem->part0_buf_ = part0_buf; | 381 mem->part0_buf_ = part0_buf; |
| 380 br->buf_ = part0_buf; | 382 VP8BitReaderSetBuffer(br, part0_buf, part_size); |
| 381 br->buf_end_ = part0_buf + part_size; | |
| 382 } else { | 383 } else { |
| 383 // Else: just keep pointers to the partition #0's data in dec_->br_. | 384 // Else: just keep pointers to the partition #0's data in dec_->br_. |
| 384 } | 385 } |
| 385 mem->start_ += part_size; | 386 mem->start_ += part_size; |
| 386 return VP8_STATUS_OK; | 387 return VP8_STATUS_OK; |
| 387 } | 388 } |
| 388 | 389 |
| 389 static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { | 390 static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { |
| 390 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; | 391 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; |
| 391 VP8Io* const io = &idec->io_; | 392 VP8Io* const io = &idec->io_; |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) { | 500 static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) { |
| 500 VP8Io* const io = &idec->io_; | 501 VP8Io* const io = &idec->io_; |
| 501 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; | 502 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; |
| 502 const WebPDecParams* const params = &idec->params_; | 503 const WebPDecParams* const params = &idec->params_; |
| 503 WebPDecBuffer* const output = params->output; | 504 WebPDecBuffer* const output = params->output; |
| 504 size_t curr_size = MemDataSize(&idec->mem_); | 505 size_t curr_size = MemDataSize(&idec->mem_); |
| 505 assert(idec->is_lossless_); | 506 assert(idec->is_lossless_); |
| 506 | 507 |
| 507 // Wait until there's enough data for decoding header. | 508 // Wait until there's enough data for decoding header. |
| 508 if (curr_size < (idec->chunk_size_ >> 3)) { | 509 if (curr_size < (idec->chunk_size_ >> 3)) { |
| 509 return VP8_STATUS_SUSPENDED; | 510 dec->status_ = VP8_STATUS_SUSPENDED; |
| 511 return ErrorStatusLossless(idec, dec->status_); |
| 510 } | 512 } |
| 513 |
| 511 if (!VP8LDecodeHeader(dec, io)) { | 514 if (!VP8LDecodeHeader(dec, io)) { |
| 515 if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && |
| 516 curr_size < idec->chunk_size_) { |
| 517 dec->status_ = VP8_STATUS_SUSPENDED; |
| 518 } |
| 512 return ErrorStatusLossless(idec, dec->status_); | 519 return ErrorStatusLossless(idec, dec->status_); |
| 513 } | 520 } |
| 514 // Allocate/verify output buffer now. | 521 // Allocate/verify output buffer now. |
| 515 dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, | 522 dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, |
| 516 output); | 523 output); |
| 517 if (dec->status_ != VP8_STATUS_OK) { | 524 if (dec->status_ != VP8_STATUS_OK) { |
| 518 return IDecError(idec, dec->status_); | 525 return IDecError(idec, dec->status_); |
| 519 } | 526 } |
| 520 | 527 |
| 521 idec->state_ = STATE_VP8L_DATA; | 528 idec->state_ = STATE_VP8L_DATA; |
| 522 return VP8_STATUS_OK; | 529 return VP8_STATUS_OK; |
| 523 } | 530 } |
| 524 | 531 |
| 525 static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) { | 532 static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) { |
| 526 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; | 533 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; |
| 527 const size_t curr_size = MemDataSize(&idec->mem_); | 534 const size_t curr_size = MemDataSize(&idec->mem_); |
| 528 assert(idec->is_lossless_); | 535 assert(idec->is_lossless_); |
| 529 | 536 |
| 530 // At present Lossless decoder can't decode image incrementally. So wait till | 537 // Switch to incremental decoding if we don't have all the bytes available. |
| 531 // all the image data is aggregated before image can be decoded. | 538 dec->incremental_ = (curr_size < idec->chunk_size_); |
| 532 if (curr_size < idec->chunk_size_) { | |
| 533 return VP8_STATUS_SUSPENDED; | |
| 534 } | |
| 535 | 539 |
| 536 if (!VP8LDecodeImage(dec)) { | 540 if (!VP8LDecodeImage(dec)) { |
| 537 // The decoding is called after all the data-bytes are aggregated. Change | |
| 538 // the error to VP8_BITSTREAM_ERROR in case lossless decoder fails to decode | |
| 539 // all the pixels (VP8_STATUS_SUSPENDED). | |
| 540 if (dec->status_ == VP8_STATUS_SUSPENDED) { | |
| 541 dec->status_ = VP8_STATUS_BITSTREAM_ERROR; | |
| 542 } | |
| 543 return ErrorStatusLossless(idec, dec->status_); | 541 return ErrorStatusLossless(idec, dec->status_); |
| 544 } | 542 } |
| 545 | 543 assert(dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED); |
| 546 return FinishDecoding(idec); | 544 return (dec->status_ == VP8_STATUS_SUSPENDED) ? dec->status_ |
| 545 : FinishDecoding(idec); |
| 547 } | 546 } |
| 548 | 547 |
| 549 // Main decoding loop | 548 // Main decoding loop |
| 550 static VP8StatusCode IDecode(WebPIDecoder* idec) { | 549 static VP8StatusCode IDecode(WebPIDecoder* idec) { |
| 551 VP8StatusCode status = VP8_STATUS_SUSPENDED; | 550 VP8StatusCode status = VP8_STATUS_SUSPENDED; |
| 552 | 551 |
| 553 if (idec->state_ == STATE_WEBP_HEADER) { | 552 if (idec->state_ == STATE_WEBP_HEADER) { |
| 554 status = DecodeWebPHeaders(idec); | 553 status = DecodeWebPHeaders(idec); |
| 555 } else { | 554 } else { |
| 556 if (idec->dec_ == NULL) { | 555 if (idec->dec_ == NULL) { |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 786 } | 785 } |
| 787 return idec->params_.output; | 786 return idec->params_.output; |
| 788 } | 787 } |
| 789 | 788 |
| 790 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, | 789 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec, |
| 791 int* left, int* top, | 790 int* left, int* top, |
| 792 int* width, int* height) { | 791 int* width, int* height) { |
| 793 const WebPDecBuffer* const src = GetOutputBuffer(idec); | 792 const WebPDecBuffer* const src = GetOutputBuffer(idec); |
| 794 if (left != NULL) *left = 0; | 793 if (left != NULL) *left = 0; |
| 795 if (top != NULL) *top = 0; | 794 if (top != NULL) *top = 0; |
| 796 // TODO(skal): later include handling of rotations. | |
| 797 if (src) { | 795 if (src) { |
| 798 if (width != NULL) *width = src->width; | 796 if (width != NULL) *width = src->width; |
| 799 if (height != NULL) *height = idec->params_.last_y; | 797 if (height != NULL) *height = idec->params_.last_y; |
| 800 } else { | 798 } else { |
| 801 if (width != NULL) *width = 0; | 799 if (width != NULL) *width = 0; |
| 802 if (height != NULL) *height = 0; | 800 if (height != NULL) *height = 0; |
| 803 } | 801 } |
| 804 return src; | 802 return src; |
| 805 } | 803 } |
| 806 | 804 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 852 return 0; | 850 return 0; |
| 853 } | 851 } |
| 854 | 852 |
| 855 idec->io_.put = put; | 853 idec->io_.put = put; |
| 856 idec->io_.setup = setup; | 854 idec->io_.setup = setup; |
| 857 idec->io_.teardown = teardown; | 855 idec->io_.teardown = teardown; |
| 858 idec->io_.opaque = user_data; | 856 idec->io_.opaque = user_data; |
| 859 | 857 |
| 860 return 1; | 858 return 1; |
| 861 } | 859 } |
| 862 | |
| OLD | NEW |