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