| 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 |
| 11 // | 11 // |
| 12 // Author: somnath@google.com (Somnath Banerjee) | 12 // Author: somnath@google.com (Somnath Banerjee) |
| 13 | 13 |
| 14 #include <assert.h> | 14 #include <assert.h> |
| 15 #include <string.h> | 15 #include <string.h> |
| 16 #include <stdlib.h> | 16 #include <stdlib.h> |
| 17 | 17 |
| 18 #include "./alphai.h" |
| 18 #include "./webpi.h" | 19 #include "./webpi.h" |
| 19 #include "./vp8i.h" | 20 #include "./vp8i.h" |
| 20 #include "../utils/utils.h" | 21 #include "../utils/utils.h" |
| 21 | 22 |
| 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. | 23 // In append mode, buffer allocations increase as multiples of this value. |
| 27 // Needs to be a power of 2. | 24 // Needs to be a power of 2. |
| 28 #define CHUNK_SIZE 4096 | 25 #define CHUNK_SIZE 4096 |
| 29 #define MAX_MB_SIZE 4096 | 26 #define MAX_MB_SIZE 4096 |
| 30 | 27 |
| 31 //------------------------------------------------------------------------------ | 28 //------------------------------------------------------------------------------ |
| 32 // Data structures for memory and states | 29 // Data structures for memory and states |
| 33 | 30 |
| 34 // Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE. | 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. |
| 35 // If there is any error the decoder goes into state ERROR. | 34 // If there is any error the decoder goes into state ERROR. |
| 36 typedef enum { | 35 typedef enum { |
| 37 STATE_PRE_VP8, // All data before that of the first VP8 chunk. | 36 STATE_WEBP_HEADER, // All the data before that of the VP8/VP8L chunk. |
| 38 STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk). | 37 STATE_VP8_HEADER, // The VP8 Frame header (within the VP8 chunk). |
| 39 STATE_VP8_PARTS0, | 38 STATE_VP8_PARTS0, |
| 40 STATE_VP8_DATA, | 39 STATE_VP8_DATA, |
| 41 STATE_VP8L_HEADER, | 40 STATE_VP8L_HEADER, |
| 42 STATE_VP8L_DATA, | 41 STATE_VP8L_DATA, |
| 43 STATE_DONE, | 42 STATE_DONE, |
| 44 STATE_ERROR | 43 STATE_ERROR |
| 45 } DecState; | 44 } DecState; |
| 46 | 45 |
| 47 // Operating state for the MemBuffer | 46 // Operating state for the MemBuffer |
| 48 typedef enum { | 47 typedef enum { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 } | 94 } |
| 96 } | 95 } |
| 97 | 96 |
| 98 static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { | 97 static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) { |
| 99 return (mem->end_ - mem->start_); | 98 return (mem->end_ - mem->start_); |
| 100 } | 99 } |
| 101 | 100 |
| 102 // Check if we need to preserve the compressed alpha data, as it may not have | 101 // Check if we need to preserve the compressed alpha data, as it may not have |
| 103 // been decoded yet. | 102 // been decoded yet. |
| 104 static int NeedCompressedAlpha(const WebPIDecoder* const idec) { | 103 static int NeedCompressedAlpha(const WebPIDecoder* const idec) { |
| 105 if (idec->state_ == STATE_PRE_VP8) { | 104 if (idec->state_ == STATE_WEBP_HEADER) { |
| 106 // We haven't parsed the headers yet, so we don't know whether the image is | 105 // 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. | 106 // lossy or lossless. This also means that we haven't parsed the ALPH chunk. |
| 108 return 0; | 107 return 0; |
| 109 } | 108 } |
| 110 if (idec->is_lossless_) { | 109 if (idec->is_lossless_) { |
| 111 return 0; // ALPH chunk is not present for lossless images. | 110 return 0; // ALPH chunk is not present for lossless images. |
| 112 } else { | 111 } else { |
| 113 const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; | 112 const VP8Decoder* const dec = (VP8Decoder*)idec->dec_; |
| 114 assert(dec != NULL); // Must be true as idec->state_ != STATE_PRE_VP8. | 113 assert(dec != NULL); // Must be true as idec->state_ != STATE_WEBP_HEADER. |
| 115 return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_; | 114 return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_; |
| 116 } | 115 } |
| 117 } | 116 } |
| 118 | 117 |
| 119 static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { | 118 static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) { |
| 120 MemBuffer* const mem = &idec->mem_; | 119 MemBuffer* const mem = &idec->mem_; |
| 121 const uint8_t* const new_base = mem->buf_ + mem->start_; | 120 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 | 121 // note: for VP8, setting up idec->io_ is only really needed at the beginning |
| 123 // of the decoding, till partition #0 is complete. | 122 // of the decoding, till partition #0 is complete. |
| 124 idec->io_.data = new_base; | 123 idec->io_.data = new_base; |
| 125 idec->io_.data_size = MemDataSize(mem); | 124 idec->io_.data_size = MemDataSize(mem); |
| 126 | 125 |
| 127 if (idec->dec_ != NULL) { | 126 if (idec->dec_ != NULL) { |
| 128 if (!idec->is_lossless_) { | 127 if (!idec->is_lossless_) { |
| 129 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; | 128 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; |
| 130 const int last_part = dec->num_parts_ - 1; | 129 const int last_part = dec->num_parts_ - 1; |
| 131 if (offset != 0) { | 130 if (offset != 0) { |
| 132 int p; | 131 int p; |
| 133 for (p = 0; p <= last_part; ++p) { | 132 for (p = 0; p <= last_part; ++p) { |
| 134 RemapBitReader(dec->parts_ + p, offset); | 133 RemapBitReader(dec->parts_ + p, offset); |
| 135 } | 134 } |
| 136 // Remap partition #0 data pointer to new offset, but only in MAP | 135 // 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). | 136 // mode (in APPEND mode, partition #0 is copied into a fixed memory). |
| 138 if (mem->mode_ == MEM_MODE_MAP) { | 137 if (mem->mode_ == MEM_MODE_MAP) { |
| 139 RemapBitReader(&dec->br_, offset); | 138 RemapBitReader(&dec->br_, offset); |
| 140 } | 139 } |
| 141 } | 140 } |
| 142 assert(last_part >= 0); | 141 assert(last_part >= 0); |
| 143 dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_; | 142 dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_; |
| 144 if (NeedCompressedAlpha(idec)) dec->alpha_data_ += offset; | 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 } |
| 145 } else { // Resize lossless bitreader | 159 } else { // Resize lossless bitreader |
| 146 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; | 160 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; |
| 147 VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem)); | 161 VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem)); |
| 148 } | 162 } |
| 149 } | 163 } |
| 150 } | 164 } |
| 151 | 165 |
| 152 // Appends data to the end of MemBuffer->buf_. It expands the allocated memory | 166 // 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. | 167 // size if required and also updates VP8BitReader's if new memory is allocated. |
| 154 static int AppendToMemBuffer(WebPIDecoder* const idec, | 168 static int AppendToMemBuffer(WebPIDecoder* const idec, |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 *token_br = context->token_br_; | 275 *token_br = context->token_br_; |
| 262 memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4); | 276 memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4); |
| 263 memcpy(dec->intra_l_, context->intra_l_, 4); | 277 memcpy(dec->intra_l_, context->intra_l_, 4); |
| 264 } | 278 } |
| 265 | 279 |
| 266 //------------------------------------------------------------------------------ | 280 //------------------------------------------------------------------------------ |
| 267 | 281 |
| 268 static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) { | 282 static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) { |
| 269 if (idec->state_ == STATE_VP8_DATA) { | 283 if (idec->state_ == STATE_VP8_DATA) { |
| 270 VP8Io* const io = &idec->io_; | 284 VP8Io* const io = &idec->io_; |
| 271 if (io->teardown) { | 285 if (io->teardown != NULL) { |
| 272 io->teardown(io); | 286 io->teardown(io); |
| 273 } | 287 } |
| 274 } | 288 } |
| 275 idec->state_ = STATE_ERROR; | 289 idec->state_ = STATE_ERROR; |
| 276 return error; | 290 return error; |
| 277 } | 291 } |
| 278 | 292 |
| 279 static void ChangeState(WebPIDecoder* const idec, DecState new_state, | 293 static void ChangeState(WebPIDecoder* const idec, DecState new_state, |
| 280 size_t consumed_bytes) { | 294 size_t consumed_bytes) { |
| 281 MemBuffer* const mem = &idec->mem_; | 295 MemBuffer* const mem = &idec->mem_; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 304 } | 318 } |
| 305 | 319 |
| 306 idec->chunk_size_ = headers.compressed_size; | 320 idec->chunk_size_ = headers.compressed_size; |
| 307 idec->is_lossless_ = headers.is_lossless; | 321 idec->is_lossless_ = headers.is_lossless; |
| 308 if (!idec->is_lossless_) { | 322 if (!idec->is_lossless_) { |
| 309 VP8Decoder* const dec = VP8New(); | 323 VP8Decoder* const dec = VP8New(); |
| 310 if (dec == NULL) { | 324 if (dec == NULL) { |
| 311 return VP8_STATUS_OUT_OF_MEMORY; | 325 return VP8_STATUS_OUT_OF_MEMORY; |
| 312 } | 326 } |
| 313 idec->dec_ = dec; | 327 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; | 328 dec->alpha_data_ = headers.alpha_data; |
| 321 dec->alpha_data_size_ = headers.alpha_data_size; | 329 dec->alpha_data_size_ = headers.alpha_data_size; |
| 322 ChangeState(idec, STATE_VP8_FRAME_HEADER, headers.offset); | 330 ChangeState(idec, STATE_VP8_HEADER, headers.offset); |
| 323 } else { | 331 } else { |
| 324 VP8LDecoder* const dec = VP8LNew(); | 332 VP8LDecoder* const dec = VP8LNew(); |
| 325 if (dec == NULL) { | 333 if (dec == NULL) { |
| 326 return VP8_STATUS_OUT_OF_MEMORY; | 334 return VP8_STATUS_OUT_OF_MEMORY; |
| 327 } | 335 } |
| 328 idec->dec_ = dec; | 336 idec->dec_ = dec; |
| 329 ChangeState(idec, STATE_VP8L_HEADER, headers.offset); | 337 ChangeState(idec, STATE_VP8L_HEADER, headers.offset); |
| 330 } | 338 } |
| 331 return VP8_STATUS_OK; | 339 return VP8_STATUS_OK; |
| 332 } | 340 } |
| 333 | 341 |
| 334 static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { | 342 static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { |
| 335 const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; | 343 const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; |
| 336 const size_t curr_size = MemDataSize(&idec->mem_); | 344 const size_t curr_size = MemDataSize(&idec->mem_); |
| 345 int width, height; |
| 337 uint32_t bits; | 346 uint32_t bits; |
| 338 | 347 |
| 339 if (curr_size < VP8_FRAME_HEADER_SIZE) { | 348 if (curr_size < VP8_FRAME_HEADER_SIZE) { |
| 340 // Not enough data bytes to extract VP8 Frame Header. | 349 // Not enough data bytes to extract VP8 Frame Header. |
| 341 return VP8_STATUS_SUSPENDED; | 350 return VP8_STATUS_SUSPENDED; |
| 342 } | 351 } |
| 343 if (!VP8GetInfo(data, curr_size, idec->chunk_size_, NULL, NULL)) { | 352 if (!VP8GetInfo(data, curr_size, idec->chunk_size_, &width, &height)) { |
| 344 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); | 353 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); |
| 345 } | 354 } |
| 346 | 355 |
| 347 bits = data[0] | (data[1] << 8) | (data[2] << 16); | 356 bits = data[0] | (data[1] << 8) | (data[2] << 16); |
| 348 idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE; | 357 idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE; |
| 349 | 358 |
| 350 idec->io_.data = data; | 359 idec->io_.data = data; |
| 351 idec->io_.data_size = curr_size; | 360 idec->io_.data_size = curr_size; |
| 352 idec->state_ = STATE_VP8_PARTS0; | 361 idec->state_ = STATE_VP8_PARTS0; |
| 353 return VP8_STATUS_OK; | 362 return VP8_STATUS_OK; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 } | 409 } |
| 401 return IDecError(idec, status); | 410 return IDecError(idec, status); |
| 402 } | 411 } |
| 403 | 412 |
| 404 // Allocate/Verify output buffer now | 413 // Allocate/Verify output buffer now |
| 405 dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, | 414 dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options, |
| 406 output); | 415 output); |
| 407 if (dec->status_ != VP8_STATUS_OK) { | 416 if (dec->status_ != VP8_STATUS_OK) { |
| 408 return IDecError(idec, dec->status_); | 417 return IDecError(idec, dec->status_); |
| 409 } | 418 } |
| 410 | 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); |
| 411 if (!CopyParts0Data(idec)) { | 423 if (!CopyParts0Data(idec)) { |
| 412 return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY); | 424 return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY); |
| 413 } | 425 } |
| 414 | 426 |
| 415 // Finish setting up the decoding parameters. Will call io->setup(). | 427 // Finish setting up the decoding parameters. Will call io->setup(). |
| 416 if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) { | 428 if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) { |
| 417 return IDecError(idec, dec->status_); | 429 return IDecError(idec, dec->status_); |
| 418 } | 430 } |
| 419 | 431 |
| 420 // Note: past this point, teardown() must always be called | 432 // Note: past this point, teardown() must always be called |
| 421 // in case of error. | 433 // in case of error. |
| 422 idec->state_ = STATE_VP8_DATA; | 434 idec->state_ = STATE_VP8_DATA; |
| 423 // Allocate memory and prepare everything. | 435 // Allocate memory and prepare everything. |
| 424 if (!VP8InitFrame(dec, io)) { | 436 if (!VP8InitFrame(dec, io)) { |
| 425 return IDecError(idec, dec->status_); | 437 return IDecError(idec, dec->status_); |
| 426 } | 438 } |
| 427 return VP8_STATUS_OK; | 439 return VP8_STATUS_OK; |
| 428 } | 440 } |
| 429 | 441 |
| 430 // Remaining partitions | 442 // Remaining partitions |
| 431 static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { | 443 static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { |
| 432 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; | 444 VP8Decoder* const dec = (VP8Decoder*)idec->dec_; |
| 433 VP8Io* const io = &idec->io_; | 445 VP8Io* const io = &idec->io_; |
| 434 | 446 |
| 435 assert(dec->ready_); | 447 assert(dec->ready_); |
| 436 | |
| 437 for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { | 448 for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { |
| 438 VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)]; | 449 VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)]; |
| 439 if (dec->mb_x_ == 0) { | 450 for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) { |
| 440 VP8InitScanline(dec); | |
| 441 } | |
| 442 for (; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) { | |
| 443 MBContext context; | 451 MBContext context; |
| 444 SaveContext(dec, token_br, &context); | 452 SaveContext(dec, token_br, &context); |
| 445 | |
| 446 if (!VP8DecodeMB(dec, token_br)) { | 453 if (!VP8DecodeMB(dec, token_br)) { |
| 447 RestoreContext(&context, dec, token_br); | 454 RestoreContext(&context, dec, token_br); |
| 448 // We shouldn't fail when MAX_MB data was available | 455 // We shouldn't fail when MAX_MB data was available |
| 449 if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) { | 456 if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) { |
| 450 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); | 457 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); |
| 451 } | 458 } |
| 452 return VP8_STATUS_SUSPENDED; | 459 return VP8_STATUS_SUSPENDED; |
| 453 } | 460 } |
| 454 // Reconstruct and emit samples. | |
| 455 VP8ReconstructBlock(dec); | |
| 456 | |
| 457 // Release buffer only if there is only one partition | 461 // Release buffer only if there is only one partition |
| 458 if (dec->num_parts_ == 1) { | 462 if (dec->num_parts_ == 1) { |
| 459 idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_; | 463 idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_; |
| 460 assert(idec->mem_.start_ <= idec->mem_.end_); | 464 assert(idec->mem_.start_ <= idec->mem_.end_); |
| 461 } | 465 } |
| 462 } | 466 } |
| 467 VP8InitScanline(dec); // Prepare for next scanline |
| 468 |
| 469 // Reconstruct, filter and emit the row. |
| 463 if (!VP8ProcessRow(dec, io)) { | 470 if (!VP8ProcessRow(dec, io)) { |
| 464 return IDecError(idec, VP8_STATUS_USER_ABORT); | 471 return IDecError(idec, VP8_STATUS_USER_ABORT); |
| 465 } | 472 } |
| 466 dec->mb_x_ = 0; | |
| 467 } | 473 } |
| 468 // Synchronize the thread and check for errors. | 474 // Synchronize the thread and check for errors. |
| 469 if (!VP8ExitCritical(dec, io)) { | 475 if (!VP8ExitCritical(dec, io)) { |
| 470 return IDecError(idec, VP8_STATUS_USER_ABORT); | 476 return IDecError(idec, VP8_STATUS_USER_ABORT); |
| 471 } | 477 } |
| 472 dec->ready_ = 0; | 478 dec->ready_ = 0; |
| 473 idec->state_ = STATE_DONE; | 479 idec->state_ = STATE_DONE; |
| 474 | 480 |
| 475 return VP8_STATUS_OK; | 481 return VP8_STATUS_OK; |
| 476 } | 482 } |
| 477 | 483 |
| 478 static int ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) { | 484 static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec, |
| 485 VP8StatusCode status) { |
| 479 if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) { | 486 if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) { |
| 480 return VP8_STATUS_SUSPENDED; | 487 return VP8_STATUS_SUSPENDED; |
| 481 } | 488 } |
| 482 return IDecError(idec, status); | 489 return IDecError(idec, status); |
| 483 } | 490 } |
| 484 | 491 |
| 485 static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) { | 492 static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) { |
| 486 VP8Io* const io = &idec->io_; | 493 VP8Io* const io = &idec->io_; |
| 487 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; | 494 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_; |
| 488 const WebPDecParams* const params = &idec->params_; | 495 const WebPDecParams* const params = &idec->params_; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 | 532 |
| 526 idec->state_ = STATE_DONE; | 533 idec->state_ = STATE_DONE; |
| 527 | 534 |
| 528 return VP8_STATUS_OK; | 535 return VP8_STATUS_OK; |
| 529 } | 536 } |
| 530 | 537 |
| 531 // Main decoding loop | 538 // Main decoding loop |
| 532 static VP8StatusCode IDecode(WebPIDecoder* idec) { | 539 static VP8StatusCode IDecode(WebPIDecoder* idec) { |
| 533 VP8StatusCode status = VP8_STATUS_SUSPENDED; | 540 VP8StatusCode status = VP8_STATUS_SUSPENDED; |
| 534 | 541 |
| 535 if (idec->state_ == STATE_PRE_VP8) { | 542 if (idec->state_ == STATE_WEBP_HEADER) { |
| 536 status = DecodeWebPHeaders(idec); | 543 status = DecodeWebPHeaders(idec); |
| 537 } else { | 544 } else { |
| 538 if (idec->dec_ == NULL) { | 545 if (idec->dec_ == NULL) { |
| 539 return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. | 546 return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder. |
| 540 } | 547 } |
| 541 } | 548 } |
| 542 if (idec->state_ == STATE_VP8_FRAME_HEADER) { | 549 if (idec->state_ == STATE_VP8_HEADER) { |
| 543 status = DecodeVP8FrameHeader(idec); | 550 status = DecodeVP8FrameHeader(idec); |
| 544 } | 551 } |
| 545 if (idec->state_ == STATE_VP8_PARTS0) { | 552 if (idec->state_ == STATE_VP8_PARTS0) { |
| 546 status = DecodePartition0(idec); | 553 status = DecodePartition0(idec); |
| 547 } | 554 } |
| 548 if (idec->state_ == STATE_VP8_DATA) { | 555 if (idec->state_ == STATE_VP8_DATA) { |
| 549 status = DecodeRemaining(idec); | 556 status = DecodeRemaining(idec); |
| 550 } | 557 } |
| 551 if (idec->state_ == STATE_VP8L_HEADER) { | 558 if (idec->state_ == STATE_VP8L_HEADER) { |
| 552 status = DecodeVP8LHeader(idec); | 559 status = DecodeVP8LHeader(idec); |
| 553 } | 560 } |
| 554 if (idec->state_ == STATE_VP8L_DATA) { | 561 if (idec->state_ == STATE_VP8L_DATA) { |
| 555 status = DecodeVP8LData(idec); | 562 status = DecodeVP8LData(idec); |
| 556 } | 563 } |
| 557 return status; | 564 return status; |
| 558 } | 565 } |
| 559 | 566 |
| 560 //------------------------------------------------------------------------------ | 567 //------------------------------------------------------------------------------ |
| 561 // Public functions | 568 // Public functions |
| 562 | 569 |
| 563 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { | 570 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) { |
| 564 WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec)); | 571 WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec)); |
| 565 if (idec == NULL) { | 572 if (idec == NULL) { |
| 566 return NULL; | 573 return NULL; |
| 567 } | 574 } |
| 568 | 575 |
| 569 idec->state_ = STATE_PRE_VP8; | 576 idec->state_ = STATE_WEBP_HEADER; |
| 570 idec->chunk_size_ = 0; | 577 idec->chunk_size_ = 0; |
| 571 | 578 |
| 572 InitMemBuffer(&idec->mem_); | 579 InitMemBuffer(&idec->mem_); |
| 573 WebPInitDecBuffer(&idec->output_); | 580 WebPInitDecBuffer(&idec->output_); |
| 574 VP8InitIo(&idec->io_); | 581 VP8InitIo(&idec->io_); |
| 575 | 582 |
| 576 WebPResetDecParams(&idec->params_); | 583 WebPResetDecParams(&idec->params_); |
| 577 idec->params_.output = output_buffer ? output_buffer : &idec->output_; | 584 idec->params_.output = (output_buffer != NULL) ? output_buffer |
| 585 : &idec->output_; |
| 578 WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. | 586 WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. |
| 579 | 587 |
| 580 return idec; | 588 return idec; |
| 581 } | 589 } |
| 582 | 590 |
| 583 WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, | 591 WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size, |
| 584 WebPDecoderConfig* config) { | 592 WebPDecoderConfig* config) { |
| 585 WebPIDecoder* idec; | 593 WebPIDecoder* idec; |
| 586 | 594 |
| 587 // Parse the bitstream's features, if requested: | 595 // Parse the bitstream's features, if requested: |
| (...skipping 13 matching lines...) Expand all Loading... |
| 601 } | 609 } |
| 602 return idec; | 610 return idec; |
| 603 } | 611 } |
| 604 | 612 |
| 605 void WebPIDelete(WebPIDecoder* idec) { | 613 void WebPIDelete(WebPIDecoder* idec) { |
| 606 if (idec == NULL) return; | 614 if (idec == NULL) return; |
| 607 if (idec->dec_ != NULL) { | 615 if (idec->dec_ != NULL) { |
| 608 if (!idec->is_lossless_) { | 616 if (!idec->is_lossless_) { |
| 609 if (idec->state_ == STATE_VP8_DATA) { | 617 if (idec->state_ == STATE_VP8_DATA) { |
| 610 // Synchronize the thread, clean-up and check for errors. | 618 // Synchronize the thread, clean-up and check for errors. |
| 611 VP8ExitCritical(idec->dec_, &idec->io_); | 619 VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_); |
| 612 } | 620 } |
| 613 VP8Delete(idec->dec_); | 621 VP8Delete((VP8Decoder*)idec->dec_); |
| 614 } else { | 622 } else { |
| 615 VP8LDelete(idec->dec_); | 623 VP8LDelete((VP8LDecoder*)idec->dec_); |
| 616 } | 624 } |
| 617 } | 625 } |
| 618 ClearMemBuffer(&idec->mem_); | 626 ClearMemBuffer(&idec->mem_); |
| 619 WebPFreeDecBuffer(&idec->output_); | 627 WebPFreeDecBuffer(&idec->output_); |
| 620 free(idec); | 628 free(idec); |
| 621 } | 629 } |
| 622 | 630 |
| 623 //------------------------------------------------------------------------------ | 631 //------------------------------------------------------------------------------ |
| 624 // Wrapper toward WebPINewDecoder | 632 // Wrapper toward WebPINewDecoder |
| 625 | 633 |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride; | 828 if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride; |
| 821 | 829 |
| 822 return src->u.YUVA.y; | 830 return src->u.YUVA.y; |
| 823 } | 831 } |
| 824 | 832 |
| 825 int WebPISetIOHooks(WebPIDecoder* const idec, | 833 int WebPISetIOHooks(WebPIDecoder* const idec, |
| 826 VP8IoPutHook put, | 834 VP8IoPutHook put, |
| 827 VP8IoSetupHook setup, | 835 VP8IoSetupHook setup, |
| 828 VP8IoTeardownHook teardown, | 836 VP8IoTeardownHook teardown, |
| 829 void* user_data) { | 837 void* user_data) { |
| 830 if (idec == NULL || idec->state_ > STATE_PRE_VP8) { | 838 if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) { |
| 831 return 0; | 839 return 0; |
| 832 } | 840 } |
| 833 | 841 |
| 834 idec->io_.put = put; | 842 idec->io_.put = put; |
| 835 idec->io_.setup = setup; | 843 idec->io_.setup = setup; |
| 836 idec->io_.teardown = teardown; | 844 idec->io_.teardown = teardown; |
| 837 idec->io_.opaque = user_data; | 845 idec->io_.opaque = user_data; |
| 838 | 846 |
| 839 return 1; | 847 return 1; |
| 840 } | 848 } |
| 841 | 849 |
| 842 #if defined(__cplusplus) || defined(c_plusplus) | |
| 843 } // extern "C" | |
| 844 #endif | |
| OLD | NEW |