Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/3rdparty/libwebp/src/dec/idec_dec.c
16358 views
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: [email protected] (Somnath Banerjee)
13
14
#include <assert.h>
15
#include <string.h>
16
#include <stdlib.h>
17
18
#include "src/dec/alphai_dec.h"
19
#include "src/dec/webpi_dec.h"
20
#include "src/dec/vp8i_dec.h"
21
#include "src/utils/utils.h"
22
23
// In append mode, buffer allocations increase as multiples of this value.
24
// Needs to be a power of 2.
25
#define CHUNK_SIZE 4096
26
#define MAX_MB_SIZE 4096
27
28
//------------------------------------------------------------------------------
29
// Data structures for memory and states
30
31
// Decoding states. State normally flows as:
32
// WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and
33
// WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image.
34
// If there is any error the decoder goes into state ERROR.
35
typedef enum {
36
STATE_WEBP_HEADER, // All the data before that of the VP8/VP8L chunk.
37
STATE_VP8_HEADER, // The VP8 Frame header (within the VP8 chunk).
38
STATE_VP8_PARTS0,
39
STATE_VP8_DATA,
40
STATE_VP8L_HEADER,
41
STATE_VP8L_DATA,
42
STATE_DONE,
43
STATE_ERROR
44
} DecState;
45
46
// Operating state for the MemBuffer
47
typedef enum {
48
MEM_MODE_NONE = 0,
49
MEM_MODE_APPEND,
50
MEM_MODE_MAP
51
} MemBufferMode;
52
53
// storage for partition #0 and partial data (in a rolling fashion)
54
typedef struct {
55
MemBufferMode mode_; // Operation mode
56
size_t start_; // start location of the data to be decoded
57
size_t end_; // end location
58
size_t buf_size_; // size of the allocated buffer
59
uint8_t* buf_; // We don't own this buffer in case WebPIUpdate()
60
61
size_t part0_size_; // size of partition #0
62
const uint8_t* part0_buf_; // buffer to store partition #0
63
} MemBuffer;
64
65
struct WebPIDecoder {
66
DecState state_; // current decoding state
67
WebPDecParams params_; // Params to store output info
68
int is_lossless_; // for down-casting 'dec_'.
69
void* dec_; // either a VP8Decoder or a VP8LDecoder instance
70
VP8Io io_;
71
72
MemBuffer mem_; // input memory buffer.
73
WebPDecBuffer output_; // output buffer (when no external one is supplied,
74
// 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
82
typedef struct {
83
VP8MB left_;
84
VP8MB info_;
85
VP8BitReader token_br_;
86
} MBContext;
87
88
//------------------------------------------------------------------------------
89
// MemBuffer: incoming data handling
90
91
static 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.
97
static 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
112
static 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.
165
static 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
204
static 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
220
static 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
228
static 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
236
static 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.
247
static 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
268
static 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
275
static 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
284
static 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
295
static 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
306
static 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
345
static 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
369
static 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
397
static 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
450
static 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
500
static 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
508
static 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
540
static 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
557
static 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
588
static 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
623
WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
624
return NewDecoder(output_buffer, NULL);
625
}
626
627
WebPIDecoder* 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
655
void 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
676
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE csp, 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 (csp >= 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 = csp;
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
700
WebPIDecoder* 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
743
WebPIDecoder* 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
754
static 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
765
VP8StatusCode 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
786
VP8StatusCode 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
809
static 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
822
const 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
838
uint8_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
854
uint8_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
877
int 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
894