1 // Copyright 2011 Google Inc. All Rights Reserved.
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 // -----------------------------------------------------------------------------
10 // Incremental decoding
12 // Author: somnath@google.com (Somnath Banerjee)
21 #include "../utils/utils.h"
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
28 //------------------------------------------------------------------------------
29 // Data structures for memory and states
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.
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).
46 // Operating state for the MemBuffer
53 // storage for partition #0 and partial data (in a rolling fashion)
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()
61 size_t part0_size_
; // size of partition #0
62 const uint8_t* part0_buf_
; // buffer to store partition #0
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
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.
76 int last_mb_y_
; // last row reached for intra-mode decoding
79 // MB context to restore in case VP8DecodeMB() fails
83 VP8BitReader token_br_
;
86 //------------------------------------------------------------------------------
87 // MemBuffer: incoming data handling
89 static WEBP_INLINE
size_t MemDataSize(const MemBuffer
* mem
) {
90 return (mem
->end_
- mem
->start_
);
93 // Check if we need to preserve the compressed alpha data, as it may not have
95 static int NeedCompressedAlpha(const WebPIDecoder
* const idec
) {
96 if (idec
->state_
== STATE_WEBP_HEADER
) {
97 // We haven't parsed the headers yet, so we don't know whether the image is
98 // lossy or lossless. This also means that we haven't parsed the ALPH chunk.
101 if (idec
->is_lossless_
) {
102 return 0; // ALPH chunk is not present for lossless images.
104 const VP8Decoder
* const dec
= (VP8Decoder
*)idec
->dec_
;
105 assert(dec
!= NULL
); // Must be true as idec->state_ != STATE_WEBP_HEADER.
106 return (dec
->alpha_data_
!= NULL
) && !dec
->is_alpha_decoded_
;
110 static void DoRemap(WebPIDecoder
* const idec
, ptrdiff_t offset
) {
111 MemBuffer
* const mem
= &idec
->mem_
;
112 const uint8_t* const new_base
= mem
->buf_
+ mem
->start_
;
113 // note: for VP8, setting up idec->io_ is only really needed at the beginning
114 // of the decoding, till partition #0 is complete.
115 idec
->io_
.data
= new_base
;
116 idec
->io_
.data_size
= MemDataSize(mem
);
118 if (idec
->dec_
!= NULL
) {
119 if (!idec
->is_lossless_
) {
120 VP8Decoder
* const dec
= (VP8Decoder
*)idec
->dec_
;
121 const int last_part
= dec
->num_parts_
- 1;
124 for (p
= 0; p
<= last_part
; ++p
) {
125 VP8RemapBitReader(dec
->parts_
+ p
, offset
);
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).
129 if (mem
->mode_
== MEM_MODE_MAP
) {
130 VP8RemapBitReader(&dec
->br_
, offset
);
133 assert(last_part
>= 0);
134 dec
->parts_
[last_part
].buf_end_
= mem
->buf_
+ mem
->end_
;
135 if (NeedCompressedAlpha(idec
)) {
136 ALPHDecoder
* const alph_dec
= dec
->alph_dec_
;
137 dec
->alpha_data_
+= offset
;
138 if (alph_dec
!= NULL
) {
139 if (alph_dec
->method_
== ALPHA_LOSSLESS_COMPRESSION
) {
140 VP8LDecoder
* const alph_vp8l_dec
= alph_dec
->vp8l_dec_
;
141 assert(alph_vp8l_dec
!= NULL
);
142 assert(dec
->alpha_data_size_
>= ALPHA_HEADER_LEN
);
143 VP8LBitReaderSetBuffer(&alph_vp8l_dec
->br_
,
144 dec
->alpha_data_
+ ALPHA_HEADER_LEN
,
145 dec
->alpha_data_size_
- ALPHA_HEADER_LEN
);
146 } else { // alph_dec->method_ == ALPHA_NO_COMPRESSION
147 // Nothing special to do in this case.
151 } else { // Resize lossless bitreader
152 VP8LDecoder
* const dec
= (VP8LDecoder
*)idec
->dec_
;
153 VP8LBitReaderSetBuffer(&dec
->br_
, new_base
, MemDataSize(mem
));
158 // Appends data to the end of MemBuffer->buf_. It expands the allocated memory
159 // size if required and also updates VP8BitReader's if new memory is allocated.
160 static int AppendToMemBuffer(WebPIDecoder
* const idec
,
161 const uint8_t* const data
, size_t data_size
) {
162 VP8Decoder
* const dec
= (VP8Decoder
*)idec
->dec_
;
163 MemBuffer
* const mem
= &idec
->mem_
;
164 const int need_compressed_alpha
= NeedCompressedAlpha(idec
);
165 const uint8_t* const old_start
= mem
->buf_
+ mem
->start_
;
166 const uint8_t* const old_base
=
167 need_compressed_alpha
? dec
->alpha_data_
: old_start
;
168 assert(mem
->mode_
== MEM_MODE_APPEND
);
169 if (data_size
> MAX_CHUNK_PAYLOAD
) {
170 // security safeguard: trying to allocate more than what the format
171 // allows for a chunk should be considered a smoke smell.
175 if (mem
->end_
+ data_size
> mem
->buf_size_
) { // Need some free memory
176 const size_t new_mem_start
= old_start
- old_base
;
177 const size_t current_size
= MemDataSize(mem
) + new_mem_start
;
178 const uint64_t new_size
= (uint64_t)current_size
+ data_size
;
179 const uint64_t extra_size
= (new_size
+ CHUNK_SIZE
- 1) & ~(CHUNK_SIZE
- 1);
180 uint8_t* const new_buf
=
181 (uint8_t*)WebPSafeMalloc(extra_size
, sizeof(*new_buf
));
182 if (new_buf
== NULL
) return 0;
183 memcpy(new_buf
, old_base
, current_size
);
184 WebPSafeFree(mem
->buf_
);
186 mem
->buf_size_
= (size_t)extra_size
;
187 mem
->start_
= new_mem_start
;
188 mem
->end_
= current_size
;
191 memcpy(mem
->buf_
+ mem
->end_
, data
, data_size
);
192 mem
->end_
+= data_size
;
193 assert(mem
->end_
<= mem
->buf_size_
);
195 DoRemap(idec
, mem
->buf_
+ mem
->start_
- old_start
);
199 static int RemapMemBuffer(WebPIDecoder
* const idec
,
200 const uint8_t* const data
, size_t data_size
) {
201 MemBuffer
* const mem
= &idec
->mem_
;
202 const uint8_t* const old_buf
= mem
->buf_
;
203 const uint8_t* const old_start
= old_buf
+ mem
->start_
;
204 assert(mem
->mode_
== MEM_MODE_MAP
);
206 if (data_size
< mem
->buf_size_
) return 0; // can't remap to a shorter buffer!
208 mem
->buf_
= (uint8_t*)data
;
209 mem
->end_
= mem
->buf_size_
= data_size
;
211 DoRemap(idec
, mem
->buf_
+ mem
->start_
- old_start
);
215 static void InitMemBuffer(MemBuffer
* const mem
) {
216 mem
->mode_
= MEM_MODE_NONE
;
219 mem
->part0_buf_
= NULL
;
220 mem
->part0_size_
= 0;
223 static void ClearMemBuffer(MemBuffer
* const mem
) {
225 if (mem
->mode_
== MEM_MODE_APPEND
) {
226 WebPSafeFree(mem
->buf_
);
227 WebPSafeFree((void*)mem
->part0_buf_
);
231 static int CheckMemBufferMode(MemBuffer
* const mem
, MemBufferMode expected
) {
232 if (mem
->mode_
== MEM_MODE_NONE
) {
233 mem
->mode_
= expected
; // switch to the expected mode
234 } else if (mem
->mode_
!= expected
) {
235 return 0; // we mixed the modes => error
237 assert(mem
->mode_
== expected
); // mode is ok
241 // To be called last.
242 static VP8StatusCode
FinishDecoding(WebPIDecoder
* const idec
) {
243 #if WEBP_DECODER_ABI_VERSION > 0x0203
244 const WebPDecoderOptions
* const options
= idec
->params_
.options
;
245 WebPDecBuffer
* const output
= idec
->params_
.output
;
247 idec
->state_
= STATE_DONE
;
248 if (options
!= NULL
&& options
->flip
) {
249 return WebPFlipBuffer(output
);
252 idec
->state_
= STATE_DONE
;
253 return VP8_STATUS_OK
;
256 //------------------------------------------------------------------------------
257 // Macroblock-decoding contexts
259 static void SaveContext(const VP8Decoder
* dec
, const VP8BitReader
* token_br
,
260 MBContext
* const context
) {
261 context
->left_
= dec
->mb_info_
[-1];
262 context
->info_
= dec
->mb_info_
[dec
->mb_x_
];
263 context
->token_br_
= *token_br
;
266 static void RestoreContext(const MBContext
* context
, VP8Decoder
* const dec
,
267 VP8BitReader
* const token_br
) {
268 dec
->mb_info_
[-1] = context
->left_
;
269 dec
->mb_info_
[dec
->mb_x_
] = context
->info_
;
270 *token_br
= context
->token_br_
;
273 //------------------------------------------------------------------------------
275 static VP8StatusCode
IDecError(WebPIDecoder
* const idec
, VP8StatusCode error
) {
276 if (idec
->state_
== STATE_VP8_DATA
) {
277 VP8Io
* const io
= &idec
->io_
;
278 if (io
->teardown
!= NULL
) {
282 idec
->state_
= STATE_ERROR
;
286 static void ChangeState(WebPIDecoder
* const idec
, DecState new_state
,
287 size_t consumed_bytes
) {
288 MemBuffer
* const mem
= &idec
->mem_
;
289 idec
->state_
= new_state
;
290 mem
->start_
+= consumed_bytes
;
291 assert(mem
->start_
<= mem
->end_
);
292 idec
->io_
.data
= mem
->buf_
+ mem
->start_
;
293 idec
->io_
.data_size
= MemDataSize(mem
);
297 static VP8StatusCode
DecodeWebPHeaders(WebPIDecoder
* const idec
) {
298 MemBuffer
* const mem
= &idec
->mem_
;
299 const uint8_t* data
= mem
->buf_
+ mem
->start_
;
300 size_t curr_size
= MemDataSize(mem
);
301 VP8StatusCode status
;
302 WebPHeaderStructure headers
;
305 headers
.data_size
= curr_size
;
306 headers
.have_all_data
= 0;
307 status
= WebPParseHeaders(&headers
);
308 if (status
== VP8_STATUS_NOT_ENOUGH_DATA
) {
309 return VP8_STATUS_SUSPENDED
; // We haven't found a VP8 chunk yet.
310 } else if (status
!= VP8_STATUS_OK
) {
311 return IDecError(idec
, status
);
314 idec
->chunk_size_
= headers
.compressed_size
;
315 idec
->is_lossless_
= headers
.is_lossless
;
316 if (!idec
->is_lossless_
) {
317 VP8Decoder
* const dec
= VP8New();
319 return VP8_STATUS_OUT_OF_MEMORY
;
322 dec
->alpha_data_
= headers
.alpha_data
;
323 dec
->alpha_data_size_
= headers
.alpha_data_size
;
324 ChangeState(idec
, STATE_VP8_HEADER
, headers
.offset
);
326 VP8LDecoder
* const dec
= VP8LNew();
328 return VP8_STATUS_OUT_OF_MEMORY
;
331 ChangeState(idec
, STATE_VP8L_HEADER
, headers
.offset
);
333 return VP8_STATUS_OK
;
336 static VP8StatusCode
DecodeVP8FrameHeader(WebPIDecoder
* const idec
) {
337 const uint8_t* data
= idec
->mem_
.buf_
+ idec
->mem_
.start_
;
338 const size_t curr_size
= MemDataSize(&idec
->mem_
);
342 if (curr_size
< VP8_FRAME_HEADER_SIZE
) {
343 // Not enough data bytes to extract VP8 Frame Header.
344 return VP8_STATUS_SUSPENDED
;
346 if (!VP8GetInfo(data
, curr_size
, idec
->chunk_size_
, &width
, &height
)) {
347 return IDecError(idec
, VP8_STATUS_BITSTREAM_ERROR
);
350 bits
= data
[0] | (data
[1] << 8) | (data
[2] << 16);
351 idec
->mem_
.part0_size_
= (bits
>> 5) + VP8_FRAME_HEADER_SIZE
;
353 idec
->io_
.data
= data
;
354 idec
->io_
.data_size
= curr_size
;
355 idec
->state_
= STATE_VP8_PARTS0
;
356 return VP8_STATUS_OK
;
360 static VP8StatusCode
CopyParts0Data(WebPIDecoder
* const idec
) {
361 VP8Decoder
* const dec
= (VP8Decoder
*)idec
->dec_
;
362 VP8BitReader
* const br
= &dec
->br_
;
363 const size_t part_size
= br
->buf_end_
- br
->buf_
;
364 MemBuffer
* const mem
= &idec
->mem_
;
365 assert(!idec
->is_lossless_
);
366 assert(mem
->part0_buf_
== NULL
);
367 // the following is a format limitation, no need for runtime check:
368 assert(part_size
<= mem
->part0_size_
);
369 if (part_size
== 0) { // can't have zero-size partition #0
370 return VP8_STATUS_BITSTREAM_ERROR
;
372 if (mem
->mode_
== MEM_MODE_APPEND
) {
373 // We copy and grab ownership of the partition #0 data.
374 uint8_t* const part0_buf
= (uint8_t*)WebPSafeMalloc(1ULL, part_size
);
375 if (part0_buf
== NULL
) {
376 return VP8_STATUS_OUT_OF_MEMORY
;
378 memcpy(part0_buf
, br
->buf_
, part_size
);
379 mem
->part0_buf_
= part0_buf
;
380 br
->buf_
= part0_buf
;
381 br
->buf_end_
= part0_buf
+ part_size
;
383 // Else: just keep pointers to the partition #0's data in dec_->br_.
385 mem
->start_
+= part_size
;
386 return VP8_STATUS_OK
;
389 static VP8StatusCode
DecodePartition0(WebPIDecoder
* const idec
) {
390 VP8Decoder
* const dec
= (VP8Decoder
*)idec
->dec_
;
391 VP8Io
* const io
= &idec
->io_
;
392 const WebPDecParams
* const params
= &idec
->params_
;
393 WebPDecBuffer
* const output
= params
->output
;
395 // Wait till we have enough data for the whole partition #0
396 if (MemDataSize(&idec
->mem_
) < idec
->mem_
.part0_size_
) {
397 return VP8_STATUS_SUSPENDED
;
400 if (!VP8GetHeaders(dec
, io
)) {
401 const VP8StatusCode status
= dec
->status_
;
402 if (status
== VP8_STATUS_SUSPENDED
||
403 status
== VP8_STATUS_NOT_ENOUGH_DATA
) {
404 // treating NOT_ENOUGH_DATA as SUSPENDED state
405 return VP8_STATUS_SUSPENDED
;
407 return IDecError(idec
, status
);
410 // Allocate/Verify output buffer now
411 dec
->status_
= WebPAllocateDecBuffer(io
->width
, io
->height
, params
->options
,
413 if (dec
->status_
!= VP8_STATUS_OK
) {
414 return IDecError(idec
, dec
->status_
);
416 // This change must be done before calling VP8InitFrame()
417 dec
->mt_method_
= VP8GetThreadMethod(params
->options
, NULL
,
418 io
->width
, io
->height
);
419 VP8InitDithering(params
->options
, dec
);
421 dec
->status_
= CopyParts0Data(idec
);
422 if (dec
->status_
!= VP8_STATUS_OK
) {
423 return IDecError(idec
, dec
->status_
);
426 // Finish setting up the decoding parameters. Will call io->setup().
427 if (VP8EnterCritical(dec
, io
) != VP8_STATUS_OK
) {
428 return IDecError(idec
, dec
->status_
);
431 // Note: past this point, teardown() must always be called
433 idec
->state_
= STATE_VP8_DATA
;
434 // Allocate memory and prepare everything.
435 if (!VP8InitFrame(dec
, io
)) {
436 return IDecError(idec
, dec
->status_
);
438 return VP8_STATUS_OK
;
441 // Remaining partitions
442 static VP8StatusCode
DecodeRemaining(WebPIDecoder
* const idec
) {
443 VP8Decoder
* const dec
= (VP8Decoder
*)idec
->dec_
;
444 VP8Io
* const io
= &idec
->io_
;
447 for (; dec
->mb_y_
< dec
->mb_h_
; ++dec
->mb_y_
) {
448 if (idec
->last_mb_y_
!= dec
->mb_y_
) {
449 if (!VP8ParseIntraModeRow(&dec
->br_
, dec
)) {
450 // note: normally, error shouldn't occur since we already have the whole
451 // partition0 available here in DecodeRemaining(). Reaching EOF while
452 // reading intra modes really means a BITSTREAM_ERROR.
453 return IDecError(idec
, VP8_STATUS_BITSTREAM_ERROR
);
455 idec
->last_mb_y_
= dec
->mb_y_
;
457 for (; dec
->mb_x_
< dec
->mb_w_
; ++dec
->mb_x_
) {
458 VP8BitReader
* const token_br
=
459 &dec
->parts_
[dec
->mb_y_
& (dec
->num_parts_
- 1)];
461 SaveContext(dec
, token_br
, &context
);
462 if (!VP8DecodeMB(dec
, token_br
)) {
463 // We shouldn't fail when MAX_MB data was available
464 if (dec
->num_parts_
== 1 && MemDataSize(&idec
->mem_
) > MAX_MB_SIZE
) {
465 return IDecError(idec
, VP8_STATUS_BITSTREAM_ERROR
);
467 RestoreContext(&context
, dec
, token_br
);
468 return VP8_STATUS_SUSPENDED
;
470 // Release buffer only if there is only one partition
471 if (dec
->num_parts_
== 1) {
472 idec
->mem_
.start_
= token_br
->buf_
- idec
->mem_
.buf_
;
473 assert(idec
->mem_
.start_
<= idec
->mem_
.end_
);
476 VP8InitScanline(dec
); // Prepare for next scanline
478 // Reconstruct, filter and emit the row.
479 if (!VP8ProcessRow(dec
, io
)) {
480 return IDecError(idec
, VP8_STATUS_USER_ABORT
);
483 // Synchronize the thread and check for errors.
484 if (!VP8ExitCritical(dec
, io
)) {
485 return IDecError(idec
, VP8_STATUS_USER_ABORT
);
488 return FinishDecoding(idec
);
491 static VP8StatusCode
ErrorStatusLossless(WebPIDecoder
* const idec
,
492 VP8StatusCode status
) {
493 if (status
== VP8_STATUS_SUSPENDED
|| status
== VP8_STATUS_NOT_ENOUGH_DATA
) {
494 return VP8_STATUS_SUSPENDED
;
496 return IDecError(idec
, status
);
499 static VP8StatusCode
DecodeVP8LHeader(WebPIDecoder
* const idec
) {
500 VP8Io
* const io
= &idec
->io_
;
501 VP8LDecoder
* const dec
= (VP8LDecoder
*)idec
->dec_
;
502 const WebPDecParams
* const params
= &idec
->params_
;
503 WebPDecBuffer
* const output
= params
->output
;
504 size_t curr_size
= MemDataSize(&idec
->mem_
);
505 assert(idec
->is_lossless_
);
507 // Wait until there's enough data for decoding header.
508 if (curr_size
< (idec
->chunk_size_
>> 3)) {
509 return VP8_STATUS_SUSPENDED
;
511 if (!VP8LDecodeHeader(dec
, io
)) {
512 return ErrorStatusLossless(idec
, dec
->status_
);
514 // Allocate/verify output buffer now.
515 dec
->status_
= WebPAllocateDecBuffer(io
->width
, io
->height
, params
->options
,
517 if (dec
->status_
!= VP8_STATUS_OK
) {
518 return IDecError(idec
, dec
->status_
);
521 idec
->state_
= STATE_VP8L_DATA
;
522 return VP8_STATUS_OK
;
525 static VP8StatusCode
DecodeVP8LData(WebPIDecoder
* const idec
) {
526 VP8LDecoder
* const dec
= (VP8LDecoder
*)idec
->dec_
;
527 const size_t curr_size
= MemDataSize(&idec
->mem_
);
528 assert(idec
->is_lossless_
);
530 // At present Lossless decoder can't decode image incrementally. So wait till
531 // all the image data is aggregated before image can be decoded.
532 if (curr_size
< idec
->chunk_size_
) {
533 return VP8_STATUS_SUSPENDED
;
536 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
;
543 return ErrorStatusLossless(idec
, dec
->status_
);
546 return FinishDecoding(idec
);
549 // Main decoding loop
550 static VP8StatusCode
IDecode(WebPIDecoder
* idec
) {
551 VP8StatusCode status
= VP8_STATUS_SUSPENDED
;
553 if (idec
->state_
== STATE_WEBP_HEADER
) {
554 status
= DecodeWebPHeaders(idec
);
556 if (idec
->dec_
== NULL
) {
557 return VP8_STATUS_SUSPENDED
; // can't continue if we have no decoder.
560 if (idec
->state_
== STATE_VP8_HEADER
) {
561 status
= DecodeVP8FrameHeader(idec
);
563 if (idec
->state_
== STATE_VP8_PARTS0
) {
564 status
= DecodePartition0(idec
);
566 if (idec
->state_
== STATE_VP8_DATA
) {
567 status
= DecodeRemaining(idec
);
569 if (idec
->state_
== STATE_VP8L_HEADER
) {
570 status
= DecodeVP8LHeader(idec
);
572 if (idec
->state_
== STATE_VP8L_DATA
) {
573 status
= DecodeVP8LData(idec
);
578 //------------------------------------------------------------------------------
581 WebPIDecoder
* WebPINewDecoder(WebPDecBuffer
* output_buffer
) {
582 WebPIDecoder
* idec
= (WebPIDecoder
*)WebPSafeCalloc(1ULL, sizeof(*idec
));
587 idec
->state_
= STATE_WEBP_HEADER
;
588 idec
->chunk_size_
= 0;
590 idec
->last_mb_y_
= -1;
592 InitMemBuffer(&idec
->mem_
);
593 WebPInitDecBuffer(&idec
->output_
);
594 VP8InitIo(&idec
->io_
);
596 WebPResetDecParams(&idec
->params_
);
597 idec
->params_
.output
= (output_buffer
!= NULL
) ? output_buffer
599 WebPInitCustomIo(&idec
->params_
, &idec
->io_
); // Plug the I/O functions.
604 WebPIDecoder
* WebPIDecode(const uint8_t* data
, size_t data_size
,
605 WebPDecoderConfig
* config
) {
608 // Parse the bitstream's features, if requested:
609 if (data
!= NULL
&& data_size
> 0 && config
!= NULL
) {
610 if (WebPGetFeatures(data
, data_size
, &config
->input
) != VP8_STATUS_OK
) {
614 // Create an instance of the incremental decoder
615 idec
= WebPINewDecoder(config
? &config
->output
: NULL
);
619 // Finish initialization
620 if (config
!= NULL
) {
621 idec
->params_
.options
= &config
->options
;
626 void WebPIDelete(WebPIDecoder
* idec
) {
627 if (idec
== NULL
) return;
628 if (idec
->dec_
!= NULL
) {
629 if (!idec
->is_lossless_
) {
630 if (idec
->state_
== STATE_VP8_DATA
) {
631 // Synchronize the thread, clean-up and check for errors.
632 VP8ExitCritical((VP8Decoder
*)idec
->dec_
, &idec
->io_
);
634 VP8Delete((VP8Decoder
*)idec
->dec_
);
636 VP8LDelete((VP8LDecoder
*)idec
->dec_
);
639 ClearMemBuffer(&idec
->mem_
);
640 WebPFreeDecBuffer(&idec
->output_
);
644 //------------------------------------------------------------------------------
645 // Wrapper toward WebPINewDecoder
647 WebPIDecoder
* WebPINewRGB(WEBP_CSP_MODE mode
, uint8_t* output_buffer
,
648 size_t output_buffer_size
, int output_stride
) {
649 const int is_external_memory
= (output_buffer
!= NULL
);
652 if (mode
>= MODE_YUV
) return NULL
;
653 if (!is_external_memory
) { // Overwrite parameters to sane values.
654 output_buffer_size
= 0;
656 } else { // A buffer was passed. Validate the other params.
657 if (output_stride
== 0 || output_buffer_size
== 0) {
658 return NULL
; // invalid parameter.
661 idec
= WebPINewDecoder(NULL
);
662 if (idec
== NULL
) return NULL
;
663 idec
->output_
.colorspace
= mode
;
664 idec
->output_
.is_external_memory
= is_external_memory
;
665 idec
->output_
.u
.RGBA
.rgba
= output_buffer
;
666 idec
->output_
.u
.RGBA
.stride
= output_stride
;
667 idec
->output_
.u
.RGBA
.size
= output_buffer_size
;
671 WebPIDecoder
* WebPINewYUVA(uint8_t* luma
, size_t luma_size
, int luma_stride
,
672 uint8_t* u
, size_t u_size
, int u_stride
,
673 uint8_t* v
, size_t v_size
, int v_stride
,
674 uint8_t* a
, size_t a_size
, int a_stride
) {
675 const int is_external_memory
= (luma
!= NULL
);
677 WEBP_CSP_MODE colorspace
;
679 if (!is_external_memory
) { // Overwrite parameters to sane values.
680 luma_size
= u_size
= v_size
= a_size
= 0;
681 luma_stride
= u_stride
= v_stride
= a_stride
= 0;
683 colorspace
= MODE_YUVA
;
684 } else { // A luma buffer was passed. Validate the other parameters.
685 if (u
== NULL
|| v
== NULL
) return NULL
;
686 if (luma_size
== 0 || u_size
== 0 || v_size
== 0) return NULL
;
687 if (luma_stride
== 0 || u_stride
== 0 || v_stride
== 0) return NULL
;
689 if (a_size
== 0 || a_stride
== 0) return NULL
;
691 colorspace
= (a
== NULL
) ? MODE_YUV
: MODE_YUVA
;
694 idec
= WebPINewDecoder(NULL
);
695 if (idec
== NULL
) return NULL
;
697 idec
->output_
.colorspace
= colorspace
;
698 idec
->output_
.is_external_memory
= is_external_memory
;
699 idec
->output_
.u
.YUVA
.y
= luma
;
700 idec
->output_
.u
.YUVA
.y_stride
= luma_stride
;
701 idec
->output_
.u
.YUVA
.y_size
= luma_size
;
702 idec
->output_
.u
.YUVA
.u
= u
;
703 idec
->output_
.u
.YUVA
.u_stride
= u_stride
;
704 idec
->output_
.u
.YUVA
.u_size
= u_size
;
705 idec
->output_
.u
.YUVA
.v
= v
;
706 idec
->output_
.u
.YUVA
.v_stride
= v_stride
;
707 idec
->output_
.u
.YUVA
.v_size
= v_size
;
708 idec
->output_
.u
.YUVA
.a
= a
;
709 idec
->output_
.u
.YUVA
.a_stride
= a_stride
;
710 idec
->output_
.u
.YUVA
.a_size
= a_size
;
714 WebPIDecoder
* WebPINewYUV(uint8_t* luma
, size_t luma_size
, int luma_stride
,
715 uint8_t* u
, size_t u_size
, int u_stride
,
716 uint8_t* v
, size_t v_size
, int v_stride
) {
717 return WebPINewYUVA(luma
, luma_size
, luma_stride
,
723 //------------------------------------------------------------------------------
725 static VP8StatusCode
IDecCheckStatus(const WebPIDecoder
* const idec
) {
727 if (idec
->state_
== STATE_ERROR
) {
728 return VP8_STATUS_BITSTREAM_ERROR
;
730 if (idec
->state_
== STATE_DONE
) {
731 return VP8_STATUS_OK
;
733 return VP8_STATUS_SUSPENDED
;
736 VP8StatusCode
WebPIAppend(WebPIDecoder
* idec
,
737 const uint8_t* data
, size_t data_size
) {
738 VP8StatusCode status
;
739 if (idec
== NULL
|| data
== NULL
) {
740 return VP8_STATUS_INVALID_PARAM
;
742 status
= IDecCheckStatus(idec
);
743 if (status
!= VP8_STATUS_SUSPENDED
) {
746 // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
747 if (!CheckMemBufferMode(&idec
->mem_
, MEM_MODE_APPEND
)) {
748 return VP8_STATUS_INVALID_PARAM
;
750 // Append data to memory buffer
751 if (!AppendToMemBuffer(idec
, data
, data_size
)) {
752 return VP8_STATUS_OUT_OF_MEMORY
;
754 return IDecode(idec
);
757 VP8StatusCode
WebPIUpdate(WebPIDecoder
* idec
,
758 const uint8_t* data
, size_t data_size
) {
759 VP8StatusCode status
;
760 if (idec
== NULL
|| data
== NULL
) {
761 return VP8_STATUS_INVALID_PARAM
;
763 status
= IDecCheckStatus(idec
);
764 if (status
!= VP8_STATUS_SUSPENDED
) {
767 // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
768 if (!CheckMemBufferMode(&idec
->mem_
, MEM_MODE_MAP
)) {
769 return VP8_STATUS_INVALID_PARAM
;
771 // Make the memory buffer point to the new buffer
772 if (!RemapMemBuffer(idec
, data
, data_size
)) {
773 return VP8_STATUS_INVALID_PARAM
;
775 return IDecode(idec
);
778 //------------------------------------------------------------------------------
780 static const WebPDecBuffer
* GetOutputBuffer(const WebPIDecoder
* const idec
) {
781 if (idec
== NULL
|| idec
->dec_
== NULL
) {
784 if (idec
->state_
<= STATE_VP8_PARTS0
) {
787 return idec
->params_
.output
;
790 const WebPDecBuffer
* WebPIDecodedArea(const WebPIDecoder
* idec
,
792 int* width
, int* height
) {
793 const WebPDecBuffer
* const src
= GetOutputBuffer(idec
);
794 if (left
!= NULL
) *left
= 0;
795 if (top
!= NULL
) *top
= 0;
796 // TODO(skal): later include handling of rotations.
798 if (width
!= NULL
) *width
= src
->width
;
799 if (height
!= NULL
) *height
= idec
->params_
.last_y
;
801 if (width
!= NULL
) *width
= 0;
802 if (height
!= NULL
) *height
= 0;
807 uint8_t* WebPIDecGetRGB(const WebPIDecoder
* idec
, int* last_y
,
808 int* width
, int* height
, int* stride
) {
809 const WebPDecBuffer
* const src
= GetOutputBuffer(idec
);
810 if (src
== NULL
) return NULL
;
811 if (src
->colorspace
>= MODE_YUV
) {
815 if (last_y
!= NULL
) *last_y
= idec
->params_
.last_y
;
816 if (width
!= NULL
) *width
= src
->width
;
817 if (height
!= NULL
) *height
= src
->height
;
818 if (stride
!= NULL
) *stride
= src
->u
.RGBA
.stride
;
820 return src
->u
.RGBA
.rgba
;
823 uint8_t* WebPIDecGetYUVA(const WebPIDecoder
* idec
, int* last_y
,
824 uint8_t** u
, uint8_t** v
, uint8_t** a
,
825 int* width
, int* height
,
826 int* stride
, int* uv_stride
, int* a_stride
) {
827 const WebPDecBuffer
* const src
= GetOutputBuffer(idec
);
828 if (src
== NULL
) return NULL
;
829 if (src
->colorspace
< MODE_YUV
) {
833 if (last_y
!= NULL
) *last_y
= idec
->params_
.last_y
;
834 if (u
!= NULL
) *u
= src
->u
.YUVA
.u
;
835 if (v
!= NULL
) *v
= src
->u
.YUVA
.v
;
836 if (a
!= NULL
) *a
= src
->u
.YUVA
.a
;
837 if (width
!= NULL
) *width
= src
->width
;
838 if (height
!= NULL
) *height
= src
->height
;
839 if (stride
!= NULL
) *stride
= src
->u
.YUVA
.y_stride
;
840 if (uv_stride
!= NULL
) *uv_stride
= src
->u
.YUVA
.u_stride
;
841 if (a_stride
!= NULL
) *a_stride
= src
->u
.YUVA
.a_stride
;
843 return src
->u
.YUVA
.y
;
846 int WebPISetIOHooks(WebPIDecoder
* const idec
,
848 VP8IoSetupHook setup
,
849 VP8IoTeardownHook teardown
,
851 if (idec
== NULL
|| idec
->state_
> STATE_WEBP_HEADER
) {
856 idec
->io_
.setup
= setup
;
857 idec
->io_
.teardown
= teardown
;
858 idec
->io_
.opaque
= user_data
;