Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(398)

Side by Side Diff: third_party/libwebp/dec/idec.c

Issue 10832153: libwebp: update snapshot to v0.2.0-rc1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2011 Google Inc. 1 // Copyright 2011 Google Inc. All Rights Reserved.
2 // 2 //
3 // This code is licensed under the same terms as WebM: 3 // This code is licensed under the same terms as WebM:
4 // Software License Agreement: http://www.webmproject.org/license/software/ 4 // Software License Agreement: http://www.webmproject.org/license/software/
5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/ 5 // Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6 // ----------------------------------------------------------------------------- 6 // -----------------------------------------------------------------------------
7 // 7 //
8 // Incremental decoding 8 // Incremental decoding
9 // 9 //
10 // Author: somnath@google.com (Somnath Banerjee) 10 // Author: somnath@google.com (Somnath Banerjee)
11 11
12 #include <assert.h> 12 #include <assert.h>
13 #include <string.h> 13 #include <string.h>
14 #include <stdlib.h> 14 #include <stdlib.h>
15 15
16 #include "webpi.h" 16 #include "./webpi.h"
17 #include "vp8i.h" 17 #include "./vp8i.h"
18 #include "../utils/utils.h"
18 19
19 #if defined(__cplusplus) || defined(c_plusplus) 20 #if defined(__cplusplus) || defined(c_plusplus)
20 extern "C" { 21 extern "C" {
21 #endif 22 #endif
22 23
24 // In append mode, buffer allocations increase as multiples of this value.
25 // Needs to be a power of 2.
23 #define CHUNK_SIZE 4096 26 #define CHUNK_SIZE 4096
24 #define MAX_MB_SIZE 4096 27 #define MAX_MB_SIZE 4096
25 28
26 //------------------------------------------------------------------------------ 29 //------------------------------------------------------------------------------
27 // Data structures for memory and states 30 // Data structures for memory and states
28 31
29 // Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE. 32 // Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE.
30 // If there is any error the decoder goes into state ERROR. 33 // If there is any error the decoder goes into state ERROR.
31 typedef enum { 34 typedef enum {
32 STATE_PRE_VP8, // All data before that of the first VP8 chunk. 35 STATE_PRE_VP8, // All data before that of the first VP8 chunk.
33 STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk). 36 STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk).
34 STATE_VP8_PARTS0, 37 STATE_VP8_PARTS0,
35 STATE_VP8_DATA, 38 STATE_VP8_DATA,
39 STATE_VP8L_HEADER,
40 STATE_VP8L_DATA,
36 STATE_DONE, 41 STATE_DONE,
37 STATE_ERROR 42 STATE_ERROR
38 } DecState; 43 } DecState;
39 44
40 // Operating state for the MemBuffer 45 // Operating state for the MemBuffer
41 typedef enum { 46 typedef enum {
42 MEM_MODE_NONE = 0, 47 MEM_MODE_NONE = 0,
43 MEM_MODE_APPEND, 48 MEM_MODE_APPEND,
44 MEM_MODE_MAP 49 MEM_MODE_MAP
45 } MemBufferMode; 50 } MemBufferMode;
46 51
47 // storage for partition #0 and partial data (in a rolling fashion) 52 // storage for partition #0 and partial data (in a rolling fashion)
48 typedef struct { 53 typedef struct {
49 MemBufferMode mode_; // Operation mode 54 MemBufferMode mode_; // Operation mode
50 uint32_t start_; // start location of the data to be decoded 55 size_t start_; // start location of the data to be decoded
51 uint32_t end_; // end location 56 size_t end_; // end location
52 size_t buf_size_; // size of the allocated buffer 57 size_t buf_size_; // size of the allocated buffer
53 uint8_t* buf_; // We don't own this buffer in case WebPIUpdate() 58 uint8_t* buf_; // We don't own this buffer in case WebPIUpdate()
54 59
55 size_t part0_size_; // size of partition #0 60 size_t part0_size_; // size of partition #0
56 const uint8_t* part0_buf_; // buffer to store partition #0 61 const uint8_t* part0_buf_; // buffer to store partition #0
57 } MemBuffer; 62 } MemBuffer;
58 63
59 struct WebPIDecoder { 64 struct WebPIDecoder {
60 DecState state_; // current decoding state 65 DecState state_; // current decoding state
61 WebPDecParams params_; // Params to store output info 66 WebPDecParams params_; // Params to store output info
62 VP8Decoder* dec_; 67 int is_lossless_; // for down-casting 'dec_'.
68 void* dec_; // either a VP8Decoder or a VP8LDecoder instance
63 VP8Io io_; 69 VP8Io io_;
64 70
65 MemBuffer mem_; // input memory buffer. 71 MemBuffer mem_; // input memory buffer.
66 WebPDecBuffer output_; // output buffer (when no external one is supplied) 72 WebPDecBuffer output_; // output buffer (when no external one is supplied)
67 uint32_t vp8_size_; // VP8 size extracted from VP8 Header. 73 size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header.
68 }; 74 };
69 75
70 // MB context to restore in case VP8DecodeMB() fails 76 // MB context to restore in case VP8DecodeMB() fails
71 typedef struct { 77 typedef struct {
72 VP8MB left_; 78 VP8MB left_;
73 VP8MB info_; 79 VP8MB info_;
74 uint8_t intra_t_[4]; 80 uint8_t intra_t_[4];
75 uint8_t intra_l_[4]; 81 uint8_t intra_l_[4];
76 VP8BitReader br_; 82 VP8BitReader br_;
77 VP8BitReader token_br_; 83 VP8BitReader token_br_;
78 } MBContext; 84 } MBContext;
79 85
80 //------------------------------------------------------------------------------ 86 //------------------------------------------------------------------------------
81 // MemBuffer: incoming data handling 87 // MemBuffer: incoming data handling
82 88
83 #define REMAP(PTR, OLD_BASE, NEW_BASE) (PTR) = (NEW_BASE) + ((PTR) - OLD_BASE) 89 static void RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
90 if (br->buf_ != NULL) {
91 br->buf_ += offset;
92 br->buf_end_ += offset;
93 }
94 }
84 95
85 static inline size_t MemDataSize(const MemBuffer* mem) { 96 static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
86 return (mem->end_ - mem->start_); 97 return (mem->end_ - mem->start_);
87 } 98 }
88 99
100 static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
101 MemBuffer* const mem = &idec->mem_;
102 const uint8_t* const new_base = mem->buf_ + mem->start_;
103 // note: for VP8, setting up idec->io_ is only really needed at the beginning
104 // of the decoding, till partition #0 is complete.
105 idec->io_.data = new_base;
106 idec->io_.data_size = MemDataSize(mem);
107
108 if (idec->dec_ != NULL) {
109 if (!idec->is_lossless_) {
110 VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
111 const int last_part = dec->num_parts_ - 1;
112 if (offset != 0) {
113 int p;
114 for (p = 0; p <= last_part; ++p) {
115 RemapBitReader(dec->parts_ + p, offset);
116 }
117 // Remap partition #0 data pointer to new offset, but only in MAP
118 // mode (in APPEND mode, partition #0 is copied into a fixed memory).
119 if (mem->mode_ == MEM_MODE_MAP) {
120 RemapBitReader(&dec->br_, offset);
121 }
122 }
123 assert(last_part >= 0);
124 dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
125 } else { // Resize lossless bitreader
126 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
127 VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem));
128 }
129 }
130 }
131
89 // Appends data to the end of MemBuffer->buf_. It expands the allocated memory 132 // Appends data to the end of MemBuffer->buf_. It expands the allocated memory
90 // size if required and also updates VP8BitReader's if new memory is allocated. 133 // size if required and also updates VP8BitReader's if new memory is allocated.
91 static int AppendToMemBuffer(WebPIDecoder* const idec, 134 static int AppendToMemBuffer(WebPIDecoder* const idec,
92 const uint8_t* const data, size_t data_size) { 135 const uint8_t* const data, size_t data_size) {
93 MemBuffer* const mem = &idec->mem_; 136 MemBuffer* const mem = &idec->mem_;
94 VP8Decoder* const dec = idec->dec_; 137 const uint8_t* const old_base = mem->buf_ + mem->start_;
95 const int last_part = dec->num_parts_ - 1;
96 assert(mem->mode_ == MEM_MODE_APPEND); 138 assert(mem->mode_ == MEM_MODE_APPEND);
139 if (data_size > MAX_CHUNK_PAYLOAD) {
140 // security safeguard: trying to allocate more than what the format
141 // allows for a chunk should be considered a smoke smell.
142 return 0;
143 }
97 144
98 if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory 145 if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory
99 int p; 146 const size_t current_size = MemDataSize(mem);
100 uint8_t* new_buf = NULL; 147 const uint64_t new_size = (uint64_t)current_size + data_size;
101 const int num_chunks = (MemDataSize(mem) + data_size + CHUNK_SIZE - 1) 148 const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
102 / CHUNK_SIZE; 149 uint8_t* const new_buf =
103 const size_t new_size = num_chunks * CHUNK_SIZE; 150 (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
104 const uint8_t* const base = mem->buf_ + mem->start_; 151 if (new_buf == NULL) return 0;
105 152 memcpy(new_buf, old_base, current_size);
106 new_buf = (uint8_t*)malloc(new_size);
107 if (!new_buf) return 0;
108 memcpy(new_buf, base, MemDataSize(mem));
109
110 // adjust VP8BitReader pointers
111 for (p = 0; p <= last_part; ++p) {
112 if (dec->parts_[p].buf_) {
113 REMAP(dec->parts_[p].buf_, base, new_buf);
114 REMAP(dec->parts_[p].buf_end_, base, new_buf);
115 }
116 }
117
118 // adjust memory pointers
119 free(mem->buf_); 153 free(mem->buf_);
120 mem->buf_ = new_buf; 154 mem->buf_ = new_buf;
121 mem->buf_size_ = new_size; 155 mem->buf_size_ = (size_t)extra_size;
122
123 mem->end_ = MemDataSize(mem);
124 mem->start_ = 0; 156 mem->start_ = 0;
157 mem->end_ = current_size;
125 } 158 }
126 159
127 memcpy(mem->buf_ + mem->end_, data, data_size); 160 memcpy(mem->buf_ + mem->end_, data, data_size);
128 mem->end_ += data_size; 161 mem->end_ += data_size;
129 assert(mem->end_ <= mem->buf_size_); 162 assert(mem->end_ <= mem->buf_size_);
130 assert(last_part >= 0);
131 dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
132 163
133 // note: setting up idec->io_ is only really needed at the beginning 164 DoRemap(idec, mem->buf_ + mem->start_ - old_base);
134 // of the decoding, till partition #0 is complete.
135 idec->io_.data = mem->buf_ + mem->start_;
136 idec->io_.data_size = MemDataSize(mem);
137 return 1; 165 return 1;
138 } 166 }
139 167
140 static int RemapMemBuffer(WebPIDecoder* const idec, 168 static int RemapMemBuffer(WebPIDecoder* const idec,
141 const uint8_t* const data, size_t data_size) { 169 const uint8_t* const data, size_t data_size) {
142 int p;
143 MemBuffer* const mem = &idec->mem_; 170 MemBuffer* const mem = &idec->mem_;
144 VP8Decoder* const dec = idec->dec_; 171 const uint8_t* const old_base = mem->buf_ + mem->start_;
145 const int last_part = dec->num_parts_ - 1; 172 assert(mem->mode_ == MEM_MODE_MAP);
146 const uint8_t* base = mem->buf_;
147 173
148 assert(mem->mode_ == MEM_MODE_MAP); 174 if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
149 if (data_size < mem->buf_size_) {
150 return 0; // we cannot remap to a shorter buffer!
151 }
152
153 for (p = 0; p <= last_part; ++p) {
154 if (dec->parts_[p].buf_) {
155 REMAP(dec->parts_[p].buf_, base, data);
156 REMAP(dec->parts_[p].buf_end_, base, data);
157 }
158 }
159 assert(last_part >= 0);
160 dec->parts_[last_part].buf_end_ = data + data_size;
161
162 // Remap partition #0 data pointer to new offset.
163 if (dec->br_.buf_) {
164 REMAP(dec->br_.buf_, base, data);
165 REMAP(dec->br_.buf_end_, base, data);
166 }
167 175
168 mem->buf_ = (uint8_t*)data; 176 mem->buf_ = (uint8_t*)data;
169 mem->end_ = mem->buf_size_ = data_size; 177 mem->end_ = mem->buf_size_ = data_size;
170 178
171 idec->io_.data = data; 179 DoRemap(idec, mem->buf_ + mem->start_ - old_base);
172 idec->io_.data_size = data_size;
173 return 1; 180 return 1;
174 } 181 }
175 182
176 static void InitMemBuffer(MemBuffer* const mem) { 183 static void InitMemBuffer(MemBuffer* const mem) {
177 mem->mode_ = MEM_MODE_NONE; 184 mem->mode_ = MEM_MODE_NONE;
178 mem->buf_ = 0; 185 mem->buf_ = NULL;
179 mem->buf_size_ = 0; 186 mem->buf_size_ = 0;
180 mem->part0_buf_ = 0; 187 mem->part0_buf_ = NULL;
181 mem->part0_size_ = 0; 188 mem->part0_size_ = 0;
182 } 189 }
183 190
184 static void ClearMemBuffer(MemBuffer* const mem) { 191 static void ClearMemBuffer(MemBuffer* const mem) {
185 assert(mem); 192 assert(mem);
186 if (mem->mode_ == MEM_MODE_APPEND) { 193 if (mem->mode_ == MEM_MODE_APPEND) {
187 free(mem->buf_); 194 free(mem->buf_);
188 free((void*)mem->part0_buf_); 195 free((void*)mem->part0_buf_);
189 } 196 }
190 } 197 }
191 198
192 static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) { 199 static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
193 if (mem->mode_ == MEM_MODE_NONE) { 200 if (mem->mode_ == MEM_MODE_NONE) {
194 mem->mode_ = expected; // switch to the expected mode 201 mem->mode_ = expected; // switch to the expected mode
195 } else if (mem->mode_ != expected) { 202 } else if (mem->mode_ != expected) {
196 return 0; // we mixed the modes => error 203 return 0; // we mixed the modes => error
197 } 204 }
198 assert(mem->mode_ == expected); // mode is ok 205 assert(mem->mode_ == expected); // mode is ok
199 return 1; 206 return 1;
200 } 207 }
201 208
202 #undef REMAP
203
204 //------------------------------------------------------------------------------ 209 //------------------------------------------------------------------------------
205 // Macroblock-decoding contexts 210 // Macroblock-decoding contexts
206 211
207 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br, 212 static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
208 MBContext* const context) { 213 MBContext* const context) {
209 const VP8BitReader* const br = &dec->br_; 214 const VP8BitReader* const br = &dec->br_;
210 const VP8MB* const left = dec->mb_info_ - 1; 215 const VP8MB* const left = dec->mb_info_ - 1;
211 const VP8MB* const info = dec->mb_info_ + dec->mb_x_; 216 const VP8MB* const info = dec->mb_info_ + dec->mb_x_;
212 217
213 context->left_ = *left; 218 context->left_ = *left;
(...skipping 25 matching lines...) Expand all
239 VP8Io* const io = &idec->io_; 244 VP8Io* const io = &idec->io_;
240 if (io->teardown) { 245 if (io->teardown) {
241 io->teardown(io); 246 io->teardown(io);
242 } 247 }
243 } 248 }
244 idec->state_ = STATE_ERROR; 249 idec->state_ = STATE_ERROR;
245 return error; 250 return error;
246 } 251 }
247 252
248 static void ChangeState(WebPIDecoder* const idec, DecState new_state, 253 static void ChangeState(WebPIDecoder* const idec, DecState new_state,
249 uint32_t consumed_bytes) { 254 size_t consumed_bytes) {
255 MemBuffer* const mem = &idec->mem_;
250 idec->state_ = new_state; 256 idec->state_ = new_state;
251 idec->mem_.start_ += consumed_bytes; 257 mem->start_ += consumed_bytes;
252 assert(idec->mem_.start_ <= idec->mem_.end_); 258 assert(mem->start_ <= mem->end_);
259 idec->io_.data = mem->buf_ + mem->start_;
260 idec->io_.data_size = MemDataSize(mem);
253 } 261 }
254 262
255 // Headers 263 // Headers
256 static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) { 264 static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
257 const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; 265 MemBuffer* const mem = &idec->mem_;
258 uint32_t curr_size = MemDataSize(&idec->mem_); 266 const uint8_t* data = mem->buf_ + mem->start_;
259 uint32_t vp8_size; 267 size_t curr_size = MemDataSize(mem);
260 uint32_t bytes_skipped;
261 VP8StatusCode status; 268 VP8StatusCode status;
269 WebPHeaderStructure headers;
262 270
263 status = WebPParseHeaders(&data, &curr_size, &vp8_size, &bytes_skipped); 271 headers.data = data;
272 headers.data_size = curr_size;
273 status = WebPParseHeaders(&headers);
264 if (status == VP8_STATUS_NOT_ENOUGH_DATA) { 274 if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
265 return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet. 275 return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet.
266 } else if (status == VP8_STATUS_OK) { 276 } else if (status != VP8_STATUS_OK) {
267 idec->vp8_size_ = vp8_size;
268 ChangeState(idec, STATE_VP8_FRAME_HEADER, bytes_skipped);
269 return VP8_STATUS_OK; // We have skipped all pre-VP8 chunks.
270 } else {
271 return IDecError(idec, status); 277 return IDecError(idec, status);
272 } 278 }
279
280 idec->chunk_size_ = headers.compressed_size;
281 idec->is_lossless_ = headers.is_lossless;
282 if (!idec->is_lossless_) {
283 VP8Decoder* const dec = VP8New();
284 if (dec == NULL) {
285 return VP8_STATUS_OUT_OF_MEMORY;
286 }
287 idec->dec_ = dec;
288 #ifdef WEBP_USE_THREAD
289 dec->use_threads_ = (idec->params_.options != NULL) &&
290 (idec->params_.options->use_threads > 0);
291 #else
292 dec->use_threads_ = 0;
293 #endif
294 dec->alpha_data_ = headers.alpha_data;
295 dec->alpha_data_size_ = headers.alpha_data_size;
296 ChangeState(idec, STATE_VP8_FRAME_HEADER, headers.offset);
297 } else {
298 VP8LDecoder* const dec = VP8LNew();
299 if (dec == NULL) {
300 return VP8_STATUS_OUT_OF_MEMORY;
301 }
302 idec->dec_ = dec;
303 ChangeState(idec, STATE_VP8L_HEADER, headers.offset);
304 }
305 return VP8_STATUS_OK;
273 } 306 }
274 307
275 static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) { 308 static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
276 const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_; 309 const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_;
277 const uint32_t curr_size = MemDataSize(&idec->mem_); 310 const size_t curr_size = MemDataSize(&idec->mem_);
278 uint32_t bits; 311 uint32_t bits;
279 312
280 if (curr_size < VP8_FRAME_HEADER_SIZE) { 313 if (curr_size < VP8_FRAME_HEADER_SIZE) {
281 // Not enough data bytes to extract VP8 Frame Header. 314 // Not enough data bytes to extract VP8 Frame Header.
282 return VP8_STATUS_SUSPENDED; 315 return VP8_STATUS_SUSPENDED;
283 } 316 }
284 if (!VP8GetInfo(data, curr_size, idec->vp8_size_, NULL, NULL, NULL)) { 317 if (!VP8GetInfo(data, curr_size, idec->chunk_size_, NULL, NULL)) {
285 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR); 318 return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
286 } 319 }
287 320
288 bits = data[0] | (data[1] << 8) | (data[2] << 16); 321 bits = data[0] | (data[1] << 8) | (data[2] << 16);
289 idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE; 322 idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE;
290 323
324 idec->io_.data = data;
291 idec->io_.data_size = curr_size; 325 idec->io_.data_size = curr_size;
292 idec->io_.data = data;
293 idec->state_ = STATE_VP8_PARTS0; 326 idec->state_ = STATE_VP8_PARTS0;
294 return VP8_STATUS_OK; 327 return VP8_STATUS_OK;
295 } 328 }
296 329
297 // Partition #0 330 // Partition #0
298 static int CopyParts0Data(WebPIDecoder* idec) { 331 static int CopyParts0Data(WebPIDecoder* const idec) {
299 VP8BitReader* const br = &idec->dec_->br_; 332 VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
333 VP8BitReader* const br = &dec->br_;
300 const size_t psize = br->buf_end_ - br->buf_; 334 const size_t psize = br->buf_end_ - br->buf_;
301 MemBuffer* const mem = &idec->mem_; 335 MemBuffer* const mem = &idec->mem_;
302 assert(!mem->part0_buf_); 336 assert(!idec->is_lossless_);
337 assert(mem->part0_buf_ == NULL);
303 assert(psize > 0); 338 assert(psize > 0);
304 assert(psize <= mem->part0_size_); 339 assert(psize <= mem->part0_size_); // Format limit: no need for runtime check
305 if (mem->mode_ == MEM_MODE_APPEND) { 340 if (mem->mode_ == MEM_MODE_APPEND) {
306 // We copy and grab ownership of the partition #0 data. 341 // We copy and grab ownership of the partition #0 data.
307 uint8_t* const part0_buf = (uint8_t*)malloc(psize); 342 uint8_t* const part0_buf = (uint8_t*)malloc(psize);
308 if (!part0_buf) { 343 if (part0_buf == NULL) {
309 return 0; 344 return 0;
310 } 345 }
311 memcpy(part0_buf, br->buf_, psize); 346 memcpy(part0_buf, br->buf_, psize);
312 mem->part0_buf_ = part0_buf; 347 mem->part0_buf_ = part0_buf;
313 br->buf_ = part0_buf; 348 br->buf_ = part0_buf;
314 br->buf_end_ = part0_buf + psize; 349 br->buf_end_ = part0_buf + psize;
315 } else { 350 } else {
316 // Else: just keep pointers to the partition #0's data in dec_->br_. 351 // Else: just keep pointers to the partition #0's data in dec_->br_.
317 } 352 }
318 mem->start_ += psize; 353 mem->start_ += psize;
319 return 1; 354 return 1;
320 } 355 }
321 356
322 static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) { 357 static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
323 VP8Decoder* const dec = idec->dec_; 358 VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
324 VP8Io* const io = &idec->io_; 359 VP8Io* const io = &idec->io_;
325 const WebPDecParams* const params = &idec->params_; 360 const WebPDecParams* const params = &idec->params_;
326 WebPDecBuffer* const output = params->output; 361 WebPDecBuffer* const output = params->output;
327 362
328 // Wait till we have enough data for the whole partition #0 363 // Wait till we have enough data for the whole partition #0
329 if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) { 364 if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) {
330 return VP8_STATUS_SUSPENDED; 365 return VP8_STATUS_SUSPENDED;
331 } 366 }
332 367
333 if (!VP8GetHeaders(dec, io)) { 368 if (!VP8GetHeaders(dec, io)) {
(...skipping 27 matching lines...) Expand all
361 idec->state_ = STATE_VP8_DATA; 396 idec->state_ = STATE_VP8_DATA;
362 // Allocate memory and prepare everything. 397 // Allocate memory and prepare everything.
363 if (!VP8InitFrame(dec, io)) { 398 if (!VP8InitFrame(dec, io)) {
364 return IDecError(idec, dec->status_); 399 return IDecError(idec, dec->status_);
365 } 400 }
366 return VP8_STATUS_OK; 401 return VP8_STATUS_OK;
367 } 402 }
368 403
369 // Remaining partitions 404 // Remaining partitions
370 static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) { 405 static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
371 VP8BitReader* br; 406 VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
372 VP8Decoder* const dec = idec->dec_;
373 VP8Io* const io = &idec->io_; 407 VP8Io* const io = &idec->io_;
374 408
375 assert(dec->ready_); 409 assert(dec->ready_);
376 410
377 br = &dec->br_;
378 for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) { 411 for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
379 VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)]; 412 VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
380 if (dec->mb_x_ == 0) { 413 if (dec->mb_x_ == 0) {
381 VP8InitScanline(dec); 414 VP8InitScanline(dec);
382 } 415 }
383 for (; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) { 416 for (; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
384 MBContext context; 417 MBContext context;
385 SaveContext(dec, token_br, &context); 418 SaveContext(dec, token_br, &context);
386 419
387 if (!VP8DecodeMB(dec, token_br)) { 420 if (!VP8DecodeMB(dec, token_br)) {
(...skipping 22 matching lines...) Expand all
410 // Synchronize the thread and check for errors. 443 // Synchronize the thread and check for errors.
411 if (!VP8ExitCritical(dec, io)) { 444 if (!VP8ExitCritical(dec, io)) {
412 return IDecError(idec, VP8_STATUS_USER_ABORT); 445 return IDecError(idec, VP8_STATUS_USER_ABORT);
413 } 446 }
414 dec->ready_ = 0; 447 dec->ready_ = 0;
415 idec->state_ = STATE_DONE; 448 idec->state_ = STATE_DONE;
416 449
417 return VP8_STATUS_OK; 450 return VP8_STATUS_OK;
418 } 451 }
419 452
453 static int ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) {
454 if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
455 return VP8_STATUS_SUSPENDED;
456 }
457 return IDecError(idec, status);
458 }
459
460 static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) {
461 VP8Io* const io = &idec->io_;
462 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
463 const WebPDecParams* const params = &idec->params_;
464 WebPDecBuffer* const output = params->output;
465 size_t curr_size = MemDataSize(&idec->mem_);
466 assert(idec->is_lossless_);
467
468 // Wait until there's enough data for decoding header.
469 if (curr_size < (idec->chunk_size_ >> 3)) {
470 return VP8_STATUS_SUSPENDED;
471 }
472 if (!VP8LDecodeHeader(dec, io)) {
473 return ErrorStatusLossless(idec, dec->status_);
474 }
475 // Allocate/verify output buffer now.
476 dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options,
477 output);
478 if (dec->status_ != VP8_STATUS_OK) {
479 return IDecError(idec, dec->status_);
480 }
481
482 idec->state_ = STATE_VP8L_DATA;
483 return VP8_STATUS_OK;
484 }
485
486 static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
487 VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
488 const size_t curr_size = MemDataSize(&idec->mem_);
489 assert(idec->is_lossless_);
490
491 // At present Lossless decoder can't decode image incrementally. So wait till
492 // all the image data is aggregated before image can be decoded.
493 if (curr_size < idec->chunk_size_) {
494 return VP8_STATUS_SUSPENDED;
495 }
496
497 if (!VP8LDecodeImage(dec)) {
498 return ErrorStatusLossless(idec, dec->status_);
499 }
500
501 idec->state_ = STATE_DONE;
502
503 return VP8_STATUS_OK;
504 }
505
420 // Main decoding loop 506 // Main decoding loop
421 static VP8StatusCode IDecode(WebPIDecoder* idec) { 507 static VP8StatusCode IDecode(WebPIDecoder* idec) {
422 VP8StatusCode status = VP8_STATUS_SUSPENDED; 508 VP8StatusCode status = VP8_STATUS_SUSPENDED;
423 assert(idec->dec_);
424 509
425 if (idec->state_ == STATE_PRE_VP8) { 510 if (idec->state_ == STATE_PRE_VP8) {
426 status = DecodeWebPHeaders(idec); 511 status = DecodeWebPHeaders(idec);
512 } else {
513 if (idec->dec_ == NULL) {
514 return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
515 }
427 } 516 }
428 if (idec->state_ == STATE_VP8_FRAME_HEADER) { 517 if (idec->state_ == STATE_VP8_FRAME_HEADER) {
429 status = DecodeVP8FrameHeader(idec); 518 status = DecodeVP8FrameHeader(idec);
430 } 519 }
431 if (idec->state_ == STATE_VP8_PARTS0) { 520 if (idec->state_ == STATE_VP8_PARTS0) {
432 status = DecodePartition0(idec); 521 status = DecodePartition0(idec);
433 } 522 }
434 if (idec->state_ == STATE_VP8_DATA) { 523 if (idec->state_ == STATE_VP8_DATA) {
435 status = DecodeRemaining(idec); 524 status = DecodeRemaining(idec);
436 } 525 }
526 if (idec->state_ == STATE_VP8L_HEADER) {
527 status = DecodeVP8LHeader(idec);
528 }
529 if (idec->state_ == STATE_VP8L_DATA) {
530 status = DecodeVP8LData(idec);
531 }
437 return status; 532 return status;
438 } 533 }
439 534
440 //------------------------------------------------------------------------------ 535 //------------------------------------------------------------------------------
441 // Public functions 536 // Public functions
442 537
443 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* const output_buffer) { 538 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
444 WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(WebPIDecoder)); 539 WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec));
445 if (idec == NULL) { 540 if (idec == NULL) {
446 return NULL; 541 return NULL;
447 } 542 }
448 543
449 idec->dec_ = VP8New();
450 if (idec->dec_ == NULL) {
451 free(idec);
452 return NULL;
453 }
454
455 idec->state_ = STATE_PRE_VP8; 544 idec->state_ = STATE_PRE_VP8;
545 idec->chunk_size_ = 0;
456 546
457 InitMemBuffer(&idec->mem_); 547 InitMemBuffer(&idec->mem_);
458 WebPInitDecBuffer(&idec->output_); 548 WebPInitDecBuffer(&idec->output_);
459 VP8InitIo(&idec->io_); 549 VP8InitIo(&idec->io_);
460 550
461 WebPResetDecParams(&idec->params_); 551 WebPResetDecParams(&idec->params_);
462 idec->params_.output = output_buffer ? output_buffer : &idec->output_; 552 idec->params_.output = output_buffer ? output_buffer : &idec->output_;
463 WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions. 553 WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions.
464 554
465 #ifdef WEBP_USE_THREAD
466 idec->dec_->use_threads_ = idec->params_.options &&
467 (idec->params_.options->use_threads > 0);
468 #else
469 idec->dec_->use_threads_ = 0;
470 #endif
471 idec->vp8_size_ = 0;
472
473 return idec; 555 return idec;
474 } 556 }
475 557
476 WebPIDecoder* WebPIDecode(const uint8_t* data, uint32_t data_size, 558 WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
477 WebPDecoderConfig* const config) { 559 WebPDecoderConfig* config) {
478 WebPIDecoder* idec; 560 WebPIDecoder* idec;
479 561
480 // Parse the bitstream's features, if requested: 562 // Parse the bitstream's features, if requested:
481 if (data != NULL && data_size > 0 && config != NULL) { 563 if (data != NULL && data_size > 0 && config != NULL) {
482 if (WebPGetFeatures(data, data_size, &config->input) != VP8_STATUS_OK) { 564 if (WebPGetFeatures(data, data_size, &config->input) != VP8_STATUS_OK) {
483 return NULL; 565 return NULL;
484 } 566 }
485 } 567 }
486 // Create an instance of the incremental decoder 568 // Create an instance of the incremental decoder
487 idec = WebPINewDecoder(config ? &config->output : NULL); 569 idec = WebPINewDecoder(config ? &config->output : NULL);
488 if (!idec) { 570 if (idec == NULL) {
489 return NULL; 571 return NULL;
490 } 572 }
491 // Finish initialization 573 // Finish initialization
492 if (config != NULL) { 574 if (config != NULL) {
493 idec->params_.options = &config->options; 575 idec->params_.options = &config->options;
494 } 576 }
495 return idec; 577 return idec;
496 } 578 }
497 579
498 void WebPIDelete(WebPIDecoder* const idec) { 580 void WebPIDelete(WebPIDecoder* idec) {
499 if (!idec) return; 581 if (idec == NULL) return;
500 VP8Delete(idec->dec_); 582 if (idec->dec_ != NULL) {
583 if (!idec->is_lossless_) {
584 VP8Delete(idec->dec_);
585 } else {
586 VP8LDelete(idec->dec_);
587 }
588 }
501 ClearMemBuffer(&idec->mem_); 589 ClearMemBuffer(&idec->mem_);
502 WebPFreeDecBuffer(&idec->output_); 590 WebPFreeDecBuffer(&idec->output_);
503 free(idec); 591 free(idec);
504 } 592 }
505 593
506 //------------------------------------------------------------------------------ 594 //------------------------------------------------------------------------------
507 // Wrapper toward WebPINewDecoder 595 // Wrapper toward WebPINewDecoder
508 596
509 WebPIDecoder* WebPINew(WEBP_CSP_MODE mode) {
510 WebPIDecoder* const idec = WebPINewDecoder(NULL);
511 if (!idec) return NULL;
512 idec->output_.colorspace = mode;
513 return idec;
514 }
515
516 WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer, 597 WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
517 int output_buffer_size, int output_stride) { 598 size_t output_buffer_size, int output_stride) {
518 WebPIDecoder* idec; 599 WebPIDecoder* idec;
519 if (mode >= MODE_YUV) return NULL; 600 if (mode >= MODE_YUV) return NULL;
520 idec = WebPINewDecoder(NULL); 601 idec = WebPINewDecoder(NULL);
521 if (!idec) return NULL; 602 if (idec == NULL) return NULL;
522 idec->output_.colorspace = mode; 603 idec->output_.colorspace = mode;
523 idec->output_.is_external_memory = 1; 604 idec->output_.is_external_memory = 1;
524 idec->output_.u.RGBA.rgba = output_buffer; 605 idec->output_.u.RGBA.rgba = output_buffer;
525 idec->output_.u.RGBA.stride = output_stride; 606 idec->output_.u.RGBA.stride = output_stride;
526 idec->output_.u.RGBA.size = output_buffer_size; 607 idec->output_.u.RGBA.size = output_buffer_size;
527 return idec; 608 return idec;
528 } 609 }
529 610
530 WebPIDecoder* WebPINewYUV(uint8_t* luma, int luma_size, int luma_stride, 611 WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
531 uint8_t* u, int u_size, int u_stride, 612 uint8_t* u, size_t u_size, int u_stride,
532 uint8_t* v, int v_size, int v_stride) { 613 uint8_t* v, size_t v_size, int v_stride,
614 uint8_t* a, size_t a_size, int a_stride) {
533 WebPIDecoder* const idec = WebPINewDecoder(NULL); 615 WebPIDecoder* const idec = WebPINewDecoder(NULL);
534 if (!idec) return NULL; 616 if (idec == NULL) return NULL;
535 idec->output_.colorspace = MODE_YUV; 617 idec->output_.colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
536 idec->output_.is_external_memory = 1; 618 idec->output_.is_external_memory = 1;
537 idec->output_.u.YUVA.y = luma; 619 idec->output_.u.YUVA.y = luma;
538 idec->output_.u.YUVA.y_stride = luma_stride; 620 idec->output_.u.YUVA.y_stride = luma_stride;
539 idec->output_.u.YUVA.y_size = luma_size; 621 idec->output_.u.YUVA.y_size = luma_size;
540 idec->output_.u.YUVA.u = u; 622 idec->output_.u.YUVA.u = u;
541 idec->output_.u.YUVA.u_stride = u_stride; 623 idec->output_.u.YUVA.u_stride = u_stride;
542 idec->output_.u.YUVA.u_size = u_size; 624 idec->output_.u.YUVA.u_size = u_size;
543 idec->output_.u.YUVA.v = v; 625 idec->output_.u.YUVA.v = v;
544 idec->output_.u.YUVA.v_stride = v_stride; 626 idec->output_.u.YUVA.v_stride = v_stride;
545 idec->output_.u.YUVA.v_size = v_size; 627 idec->output_.u.YUVA.v_size = v_size;
628 idec->output_.u.YUVA.a = a;
629 idec->output_.u.YUVA.a_stride = a_stride;
630 idec->output_.u.YUVA.a_size = a_size;
546 return idec; 631 return idec;
547 } 632 }
548 633
634 WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
635 uint8_t* u, size_t u_size, int u_stride,
636 uint8_t* v, size_t v_size, int v_stride) {
637 return WebPINewYUVA(luma, luma_size, luma_stride,
638 u, u_size, u_stride,
639 v, v_size, v_stride,
640 NULL, 0, 0);
641 }
642
549 //------------------------------------------------------------------------------ 643 //------------------------------------------------------------------------------
550 644
551 static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) { 645 static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
552 assert(idec); 646 assert(idec);
553 if (idec->dec_ == NULL) {
554 return VP8_STATUS_USER_ABORT;
555 }
556 if (idec->state_ == STATE_ERROR) { 647 if (idec->state_ == STATE_ERROR) {
557 return VP8_STATUS_BITSTREAM_ERROR; 648 return VP8_STATUS_BITSTREAM_ERROR;
558 } 649 }
559 if (idec->state_ == STATE_DONE) { 650 if (idec->state_ == STATE_DONE) {
560 return VP8_STATUS_OK; 651 return VP8_STATUS_OK;
561 } 652 }
562 return VP8_STATUS_SUSPENDED; 653 return VP8_STATUS_SUSPENDED;
563 } 654 }
564 655
565 VP8StatusCode WebPIAppend(WebPIDecoder* const idec, const uint8_t* data, 656 VP8StatusCode WebPIAppend(WebPIDecoder* idec,
566 uint32_t data_size) { 657 const uint8_t* data, size_t data_size) {
567 VP8StatusCode status; 658 VP8StatusCode status;
568 if (idec == NULL || data == NULL) { 659 if (idec == NULL || data == NULL) {
569 return VP8_STATUS_INVALID_PARAM; 660 return VP8_STATUS_INVALID_PARAM;
570 } 661 }
571 status = IDecCheckStatus(idec); 662 status = IDecCheckStatus(idec);
572 if (status != VP8_STATUS_SUSPENDED) { 663 if (status != VP8_STATUS_SUSPENDED) {
573 return status; 664 return status;
574 } 665 }
575 // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. 666 // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
576 if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) { 667 if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) {
577 return VP8_STATUS_INVALID_PARAM; 668 return VP8_STATUS_INVALID_PARAM;
578 } 669 }
579 // Append data to memory buffer 670 // Append data to memory buffer
580 if (!AppendToMemBuffer(idec, data, data_size)) { 671 if (!AppendToMemBuffer(idec, data, data_size)) {
581 return VP8_STATUS_OUT_OF_MEMORY; 672 return VP8_STATUS_OUT_OF_MEMORY;
582 } 673 }
583 return IDecode(idec); 674 return IDecode(idec);
584 } 675 }
585 676
586 VP8StatusCode WebPIUpdate(WebPIDecoder* const idec, const uint8_t* data, 677 VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
587 uint32_t data_size) { 678 const uint8_t* data, size_t data_size) {
588 VP8StatusCode status; 679 VP8StatusCode status;
589 if (idec == NULL || data == NULL) { 680 if (idec == NULL || data == NULL) {
590 return VP8_STATUS_INVALID_PARAM; 681 return VP8_STATUS_INVALID_PARAM;
591 } 682 }
592 status = IDecCheckStatus(idec); 683 status = IDecCheckStatus(idec);
593 if (status != VP8_STATUS_SUSPENDED) { 684 if (status != VP8_STATUS_SUSPENDED) {
594 return status; 685 return status;
595 } 686 }
596 // Check mixed calls between RemapMemBuffer and AppendToMemBuffer. 687 // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
597 if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) { 688 if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) {
598 return VP8_STATUS_INVALID_PARAM; 689 return VP8_STATUS_INVALID_PARAM;
599 } 690 }
600 // Make the memory buffer point to the new buffer 691 // Make the memory buffer point to the new buffer
601 if (!RemapMemBuffer(idec, data, data_size)) { 692 if (!RemapMemBuffer(idec, data, data_size)) {
602 return VP8_STATUS_INVALID_PARAM; 693 return VP8_STATUS_INVALID_PARAM;
603 } 694 }
604 return IDecode(idec); 695 return IDecode(idec);
605 } 696 }
606 697
607 //------------------------------------------------------------------------------ 698 //------------------------------------------------------------------------------
608 699
609 static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) { 700 static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) {
610 if (!idec || !idec->dec_ || idec->state_ <= STATE_VP8_PARTS0) { 701 if (idec == NULL || idec->dec_ == NULL) {
702 return NULL;
703 }
704 if (idec->state_ <= STATE_VP8_PARTS0) {
611 return NULL; 705 return NULL;
612 } 706 }
613 return idec->params_.output; 707 return idec->params_.output;
614 } 708 }
615 709
616 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* const idec, 710 const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
617 int* const left, int* const top, 711 int* left, int* top,
618 int* const width, int* const height) { 712 int* width, int* height) {
619 const WebPDecBuffer* const src = GetOutputBuffer(idec); 713 const WebPDecBuffer* const src = GetOutputBuffer(idec);
620 if (left) *left = 0; 714 if (left != NULL) *left = 0;
621 if (top) *top = 0; 715 if (top != NULL) *top = 0;
622 // TODO(skal): later include handling of rotations. 716 // TODO(skal): later include handling of rotations.
623 if (src) { 717 if (src) {
624 if (width) *width = src->width; 718 if (width != NULL) *width = src->width;
625 if (height) *height = idec->params_.last_y; 719 if (height != NULL) *height = idec->params_.last_y;
626 } else { 720 } else {
627 if (width) *width = 0; 721 if (width != NULL) *width = 0;
628 if (height) *height = 0; 722 if (height != NULL) *height = 0;
629 } 723 }
630 return src; 724 return src;
631 } 725 }
632 726
633 uint8_t* WebPIDecGetRGB(const WebPIDecoder* const idec, int* last_y, 727 uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
634 int* width, int* height, int* stride) { 728 int* width, int* height, int* stride) {
635 const WebPDecBuffer* const src = GetOutputBuffer(idec); 729 const WebPDecBuffer* const src = GetOutputBuffer(idec);
636 if (!src) return NULL; 730 if (src == NULL) return NULL;
637 if (src->colorspace >= MODE_YUV) { 731 if (src->colorspace >= MODE_YUV) {
638 return NULL; 732 return NULL;
639 } 733 }
640 734
641 if (last_y) *last_y = idec->params_.last_y; 735 if (last_y != NULL) *last_y = idec->params_.last_y;
642 if (width) *width = src->width; 736 if (width != NULL) *width = src->width;
643 if (height) *height = src->height; 737 if (height != NULL) *height = src->height;
644 if (stride) *stride = src->u.RGBA.stride; 738 if (stride != NULL) *stride = src->u.RGBA.stride;
645 739
646 return src->u.RGBA.rgba; 740 return src->u.RGBA.rgba;
647 } 741 }
648 742
649 uint8_t* WebPIDecGetYUV(const WebPIDecoder* const idec, int* last_y, 743 uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
650 uint8_t** u, uint8_t** v, 744 uint8_t** u, uint8_t** v, uint8_t** a,
651 int* width, int* height, int *stride, int* uv_stride) { 745 int* width, int* height,
746 int* stride, int* uv_stride, int* a_stride) {
652 const WebPDecBuffer* const src = GetOutputBuffer(idec); 747 const WebPDecBuffer* const src = GetOutputBuffer(idec);
653 if (!src) return NULL; 748 if (src == NULL) return NULL;
654 if (src->colorspace < MODE_YUV) { 749 if (src->colorspace < MODE_YUV) {
655 return NULL; 750 return NULL;
656 } 751 }
657 752
658 if (last_y) *last_y = idec->params_.last_y; 753 if (last_y != NULL) *last_y = idec->params_.last_y;
659 if (u) *u = src->u.YUVA.u; 754 if (u != NULL) *u = src->u.YUVA.u;
660 if (v) *v = src->u.YUVA.v; 755 if (v != NULL) *v = src->u.YUVA.v;
661 if (width) *width = src->width; 756 if (a != NULL) *a = src->u.YUVA.a;
662 if (height) *height = src->height; 757 if (width != NULL) *width = src->width;
663 if (stride) *stride = src->u.YUVA.y_stride; 758 if (height != NULL) *height = src->height;
664 if (uv_stride) *uv_stride = src->u.YUVA.u_stride; 759 if (stride != NULL) *stride = src->u.YUVA.y_stride;
760 if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride;
761 if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride;
665 762
666 return src->u.YUVA.y; 763 return src->u.YUVA.y;
667 } 764 }
668 765
669 int WebPISetIOHooks(WebPIDecoder* const idec, 766 int WebPISetIOHooks(WebPIDecoder* const idec,
670 VP8IoPutHook put, 767 VP8IoPutHook put,
671 VP8IoSetupHook setup, 768 VP8IoSetupHook setup,
672 VP8IoTeardownHook teardown, 769 VP8IoTeardownHook teardown,
673 void* user_data) { 770 void* user_data) {
674 if (!idec || !idec->dec_ || idec->state_ > STATE_PRE_VP8) { 771 if (idec == NULL || idec->state_ > STATE_PRE_VP8) {
675 return 0; 772 return 0;
676 } 773 }
677 774
678 idec->io_.put = put; 775 idec->io_.put = put;
679 idec->io_.setup = setup; 776 idec->io_.setup = setup;
680 idec->io_.teardown = teardown; 777 idec->io_.teardown = teardown;
681 idec->io_.opaque = user_data; 778 idec->io_.opaque = user_data;
682 779
683 return 1; 780 return 1;
684 } 781 }
685 782
686 #if defined(__cplusplus) || defined(c_plusplus) 783 #if defined(__cplusplus) || defined(c_plusplus)
687 } // extern "C" 784 } // extern "C"
688 #endif 785 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698