OLD | NEW |
1 // Copyright 2015 Google Inc. All Rights Reserved. | 1 // Copyright 2015 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
4 // that can be found in the COPYING file in the root of the source | 4 // that can be found in the COPYING file in the root of the source |
5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
9 // | 9 // |
10 // AnimDecoder implementation. | 10 // AnimDecoder implementation. |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 | 105 |
106 dec->demux_ = WebPDemux(webp_data); | 106 dec->demux_ = WebPDemux(webp_data); |
107 if (dec->demux_ == NULL) goto Error; | 107 if (dec->demux_ == NULL) goto Error; |
108 | 108 |
109 dec->info_.canvas_width = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_WIDTH); | 109 dec->info_.canvas_width = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_WIDTH); |
110 dec->info_.canvas_height = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_HEIGHT); | 110 dec->info_.canvas_height = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_HEIGHT); |
111 dec->info_.loop_count = WebPDemuxGetI(dec->demux_, WEBP_FF_LOOP_COUNT); | 111 dec->info_.loop_count = WebPDemuxGetI(dec->demux_, WEBP_FF_LOOP_COUNT); |
112 dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR); | 112 dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR); |
113 dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT); | 113 dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT); |
114 | 114 |
115 { | 115 // Note: calloc() because we fill frame with zeroes as well. |
116 const int canvas_bytes = | 116 dec->curr_frame_ = (uint8_t*)WebPSafeCalloc( |
117 dec->info_.canvas_width * NUM_CHANNELS * dec->info_.canvas_height; | 117 dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height); |
118 // Note: calloc() because we fill frame with zeroes as well. | 118 if (dec->curr_frame_ == NULL) goto Error; |
119 dec->curr_frame_ = WebPSafeCalloc(1ULL, canvas_bytes); | 119 dec->prev_frame_disposed_ = (uint8_t*)WebPSafeCalloc( |
120 if (dec->curr_frame_ == NULL) goto Error; | 120 dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height); |
121 dec->prev_frame_disposed_ = WebPSafeCalloc(1ULL, canvas_bytes); | 121 if (dec->prev_frame_disposed_ == NULL) goto Error; |
122 if (dec->prev_frame_disposed_ == NULL) goto Error; | |
123 } | |
124 | 122 |
125 WebPAnimDecoderReset(dec); | 123 WebPAnimDecoderReset(dec); |
126 | |
127 return dec; | 124 return dec; |
128 | 125 |
129 Error: | 126 Error: |
130 WebPAnimDecoderDelete(dec); | 127 WebPAnimDecoderDelete(dec); |
131 return NULL; | 128 return NULL; |
132 } | 129 } |
133 | 130 |
134 int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) { | 131 int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) { |
135 if (dec == NULL || info == NULL) return 0; | 132 if (dec == NULL || info == NULL) return 0; |
136 *info = dec->info_; | 133 *info = dec->info_; |
137 return 1; | 134 return 1; |
138 } | 135 } |
139 | 136 |
140 // Returns true if the frame covers the full canvas. | 137 // Returns true if the frame covers the full canvas. |
141 static int IsFullFrame(int width, int height, int canvas_width, | 138 static int IsFullFrame(int width, int height, int canvas_width, |
142 int canvas_height) { | 139 int canvas_height) { |
143 return (width == canvas_width && height == canvas_height); | 140 return (width == canvas_width && height == canvas_height); |
144 } | 141 } |
145 | 142 |
146 // Clear the canvas to transparent. | 143 // Clear the canvas to transparent. |
147 static void ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width, | 144 static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width, |
148 uint32_t canvas_height) { | 145 uint32_t canvas_height) { |
149 memset(buf, 0, canvas_width * NUM_CHANNELS * canvas_height); | 146 const uint64_t size = |
| 147 (uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf); |
| 148 if (size != (size_t)size) return 0; |
| 149 memset(buf, 0, (size_t)size); |
| 150 return 1; |
150 } | 151 } |
151 | 152 |
152 // Clear given frame rectangle to transparent. | 153 // Clear given frame rectangle to transparent. |
153 static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset, | 154 static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset, |
154 int y_offset, int width, int height) { | 155 int y_offset, int width, int height) { |
155 int j; | 156 int j; |
156 assert(width * NUM_CHANNELS <= buf_stride); | 157 assert(width * NUM_CHANNELS <= buf_stride); |
157 buf += y_offset * buf_stride + x_offset * NUM_CHANNELS; | 158 buf += y_offset * buf_stride + x_offset * NUM_CHANNELS; |
158 for (j = 0; j < height; ++j) { | 159 for (j = 0; j < height; ++j) { |
159 memset(buf, 0, width * NUM_CHANNELS); | 160 memset(buf, 0, width * NUM_CHANNELS); |
160 buf += buf_stride; | 161 buf += buf_stride; |
161 } | 162 } |
162 } | 163 } |
163 | 164 |
164 // Copy width * height pixels from 'src' to 'dst'. | 165 // Copy width * height pixels from 'src' to 'dst'. |
165 static void CopyCanvas(const uint8_t* src, uint8_t* dst, | 166 static int CopyCanvas(const uint8_t* src, uint8_t* dst, |
166 uint32_t width, uint32_t height) { | 167 uint32_t width, uint32_t height) { |
| 168 const uint64_t size = (uint64_t)width * height * NUM_CHANNELS; |
| 169 if (size != (size_t)size) return 0; |
167 assert(src != NULL && dst != NULL); | 170 assert(src != NULL && dst != NULL); |
168 memcpy(dst, src, width * NUM_CHANNELS * height); | 171 memcpy(dst, src, (size_t)size); |
| 172 return 1; |
169 } | 173 } |
170 | 174 |
171 // Returns true if the current frame is a key-frame. | 175 // Returns true if the current frame is a key-frame. |
172 static int IsKeyFrame(const WebPIterator* const curr, | 176 static int IsKeyFrame(const WebPIterator* const curr, |
173 const WebPIterator* const prev, | 177 const WebPIterator* const prev, |
174 int prev_frame_was_key_frame, | 178 int prev_frame_was_key_frame, |
175 int canvas_width, int canvas_height) { | 179 int canvas_width, int canvas_height) { |
176 if (curr->frame_num == 1) { | 180 if (curr->frame_num == 1) { |
177 return 1; | 181 return 1; |
178 } else if ((!curr->has_alpha || curr->blend_method == WEBP_MUX_NO_BLEND) && | 182 } else if ((!curr->has_alpha || curr->blend_method == WEBP_MUX_NO_BLEND) && |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 // Get compressed frame. | 325 // Get compressed frame. |
322 if (!WebPDemuxGetFrame(dec->demux_, dec->next_frame_, &iter)) { | 326 if (!WebPDemuxGetFrame(dec->demux_, dec->next_frame_, &iter)) { |
323 return 0; | 327 return 0; |
324 } | 328 } |
325 timestamp = dec->prev_frame_timestamp_ + iter.duration; | 329 timestamp = dec->prev_frame_timestamp_ + iter.duration; |
326 | 330 |
327 // Initialize. | 331 // Initialize. |
328 is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_, | 332 is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_, |
329 dec->prev_frame_was_keyframe_, width, height); | 333 dec->prev_frame_was_keyframe_, width, height); |
330 if (is_key_frame) { | 334 if (is_key_frame) { |
331 ZeroFillCanvas(dec->curr_frame_, width, height); | 335 if (!ZeroFillCanvas(dec->curr_frame_, width, height)) { |
| 336 goto Error; |
| 337 } |
332 } else { | 338 } else { |
333 CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_, width, height); | 339 if (!CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_, |
| 340 width, height)) { |
| 341 goto Error; |
| 342 } |
334 } | 343 } |
335 | 344 |
336 // Decode. | 345 // Decode. |
337 { | 346 { |
338 const uint8_t* in = iter.fragment.bytes; | 347 const uint8_t* in = iter.fragment.bytes; |
339 const size_t in_size = iter.fragment.size; | 348 const size_t in_size = iter.fragment.size; |
340 const size_t out_offset = | 349 const size_t out_offset = |
341 (iter.y_offset * width + iter.x_offset) * NUM_CHANNELS; | 350 (iter.y_offset * width + iter.x_offset) * NUM_CHANNELS; |
342 WebPDecoderConfig* const config = &dec->config_; | 351 WebPDecoderConfig* const config = &dec->config_; |
343 WebPRGBABuffer* const buf = &config->output.u.RGBA; | 352 WebPRGBABuffer* const buf = &config->output.u.RGBA; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 const size_t offset2 = canvas_y * width + left2; | 395 const size_t offset2 = canvas_y * width + left2; |
387 blend_row((uint32_t*)dec->curr_frame_ + offset2, | 396 blend_row((uint32_t*)dec->curr_frame_ + offset2, |
388 (uint32_t*)dec->prev_frame_disposed_ + offset2, width2); | 397 (uint32_t*)dec->prev_frame_disposed_ + offset2, width2); |
389 } | 398 } |
390 } | 399 } |
391 } | 400 } |
392 } | 401 } |
393 | 402 |
394 // Update info of the previous frame and dispose it for the next iteration. | 403 // Update info of the previous frame and dispose it for the next iteration. |
395 dec->prev_frame_timestamp_ = timestamp; | 404 dec->prev_frame_timestamp_ = timestamp; |
| 405 WebPDemuxReleaseIterator(&dec->prev_iter_); |
396 dec->prev_iter_ = iter; | 406 dec->prev_iter_ = iter; |
397 dec->prev_frame_was_keyframe_ = is_key_frame; | 407 dec->prev_frame_was_keyframe_ = is_key_frame; |
398 CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height); | 408 CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height); |
399 if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { | 409 if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) { |
400 ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS, | 410 ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS, |
401 dec->prev_iter_.x_offset, dec->prev_iter_.y_offset, | 411 dec->prev_iter_.x_offset, dec->prev_iter_.y_offset, |
402 dec->prev_iter_.width, dec->prev_iter_.height); | 412 dec->prev_iter_.width, dec->prev_iter_.height); |
403 } | 413 } |
404 ++dec->next_frame_; | 414 ++dec->next_frame_; |
405 | 415 |
406 // All OK, fill in the values. | 416 // All OK, fill in the values. |
407 *buf_ptr = dec->curr_frame_; | 417 *buf_ptr = dec->curr_frame_; |
408 *timestamp_ptr = timestamp; | 418 *timestamp_ptr = timestamp; |
409 return 1; | 419 return 1; |
410 | 420 |
411 Error: | 421 Error: |
412 WebPDemuxReleaseIterator(&iter); | 422 WebPDemuxReleaseIterator(&iter); |
413 return 0; | 423 return 0; |
414 } | 424 } |
415 | 425 |
416 int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) { | 426 int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) { |
417 if (dec == NULL) return 0; | 427 if (dec == NULL) return 0; |
418 return (dec->next_frame_ <= (int)dec->info_.frame_count); | 428 return (dec->next_frame_ <= (int)dec->info_.frame_count); |
419 } | 429 } |
420 | 430 |
421 void WebPAnimDecoderReset(WebPAnimDecoder* dec) { | 431 void WebPAnimDecoderReset(WebPAnimDecoder* dec) { |
422 if (dec != NULL) { | 432 if (dec != NULL) { |
423 dec->prev_frame_timestamp_ = 0; | 433 dec->prev_frame_timestamp_ = 0; |
| 434 WebPDemuxReleaseIterator(&dec->prev_iter_); |
424 memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_)); | 435 memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_)); |
425 dec->prev_frame_was_keyframe_ = 0; | 436 dec->prev_frame_was_keyframe_ = 0; |
426 dec->next_frame_ = 1; | 437 dec->next_frame_ = 1; |
427 } | 438 } |
428 } | 439 } |
429 | 440 |
430 const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) { | 441 const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) { |
431 if (dec == NULL) return NULL; | 442 if (dec == NULL) return NULL; |
432 return dec->demux_; | 443 return dec->demux_; |
433 } | 444 } |
434 | 445 |
435 void WebPAnimDecoderDelete(WebPAnimDecoder* dec) { | 446 void WebPAnimDecoderDelete(WebPAnimDecoder* dec) { |
436 if (dec != NULL) { | 447 if (dec != NULL) { |
| 448 WebPDemuxReleaseIterator(&dec->prev_iter_); |
437 WebPDemuxDelete(dec->demux_); | 449 WebPDemuxDelete(dec->demux_); |
438 WebPSafeFree(dec->curr_frame_); | 450 WebPSafeFree(dec->curr_frame_); |
439 WebPSafeFree(dec->prev_frame_disposed_); | 451 WebPSafeFree(dec->prev_frame_disposed_); |
440 WebPSafeFree(dec); | 452 WebPSafeFree(dec); |
441 } | 453 } |
442 } | 454 } |
OLD | NEW |