Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 WEBPImageDecoder::WEBPImageDecoder(AlphaOption alphaOption, GammaAndColorProfile Option colorOptions, size_t maxDecodedBytes) | 124 WEBPImageDecoder::WEBPImageDecoder(AlphaOption alphaOption, GammaAndColorProfile Option colorOptions, size_t maxDecodedBytes) |
| 125 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) | 125 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) |
| 126 , m_decoder(0) | 126 , m_decoder(0) |
| 127 , m_formatFlags(0) | 127 , m_formatFlags(0) |
| 128 , m_frameBackgroundHasAlpha(false) | 128 , m_frameBackgroundHasAlpha(false) |
| 129 , m_demux(0) | 129 , m_demux(0) |
| 130 , m_demuxState(WEBP_DEMUX_PARSING_HEADER) | 130 , m_demuxState(WEBP_DEMUX_PARSING_HEADER) |
| 131 , m_haveAlreadyParsedThisData(false) | 131 , m_haveAlreadyParsedThisData(false) |
| 132 , m_repetitionCount(cAnimationLoopOnce) | 132 , m_repetitionCount(cAnimationLoopOnce) |
| 133 , m_decodedHeight(0) | 133 , m_decodedHeight(0) |
| 134 , m_purgeAggressively(false) | |
| 134 { | 135 { |
| 135 m_blendFunction = (alphaOption == AlphaPremultiplied) ? alphaBlendPremultipl ied : alphaBlendNonPremultiplied; | 136 m_blendFunction = (alphaOption == AlphaPremultiplied) ? alphaBlendPremultipl ied : alphaBlendNonPremultiplied; |
| 136 } | 137 } |
| 137 | 138 |
| 138 WEBPImageDecoder::~WEBPImageDecoder() | 139 WEBPImageDecoder::~WEBPImageDecoder() |
| 139 { | 140 { |
| 140 clear(); | 141 clear(); |
| 141 } | 142 } |
| 142 | 143 |
| 143 void WEBPImageDecoder::clear() | 144 void WEBPImageDecoder::clear() |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 405 buffer->setAlphaBlendSource(animatedFrame.blend_method == WEBP_MUX_BLEND ? I mageFrame::BlendAtopPreviousFrame : ImageFrame::BlendAtopBgcolor); | 406 buffer->setAlphaBlendSource(animatedFrame.blend_method == WEBP_MUX_BLEND ? I mageFrame::BlendAtopPreviousFrame : ImageFrame::BlendAtopBgcolor); |
| 406 buffer->setRequiredPreviousFrameIndex(findRequiredPreviousFrame(index, !anim atedFrame.has_alpha)); | 407 buffer->setRequiredPreviousFrameIndex(findRequiredPreviousFrame(index, !anim atedFrame.has_alpha)); |
| 407 WebPDemuxReleaseIterator(&animatedFrame); | 408 WebPDemuxReleaseIterator(&animatedFrame); |
| 408 } | 409 } |
| 409 | 410 |
| 410 void WEBPImageDecoder::decode(size_t index) | 411 void WEBPImageDecoder::decode(size_t index) |
| 411 { | 412 { |
| 412 if (failed()) | 413 if (failed()) |
| 413 return; | 414 return; |
| 414 | 415 |
| 416 updateAggressivePurging(index); | |
|
urvang
2016/10/03 21:07:23
You only need to call this method when number of f
cblume
2016/10/10 21:18:38
Sounds good.
It looks like updateDemuxer() is cal
urvang
2016/10/10 21:30:50
Yes, updateDemuxer() updates the demuxer and relat
| |
| 417 | |
| 415 Vector<size_t> framesToDecode; | 418 Vector<size_t> framesToDecode; |
| 416 size_t frameToDecode = index; | 419 size_t frameToDecode = index; |
| 417 do { | 420 do { |
| 418 framesToDecode.append(frameToDecode); | 421 framesToDecode.append(frameToDecode); |
| 419 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex(); | 422 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFrameI ndex(); |
| 420 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].get Status() != ImageFrame::FrameComplete); | 423 } while (frameToDecode != kNotFound && m_frameBufferCache[frameToDecode].get Status() != ImageFrame::FrameComplete); |
| 421 | 424 |
| 422 ASSERT(m_demux); | 425 ASSERT(m_demux); |
| 423 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { | 426 for (auto i = framesToDecode.rbegin(); i != framesToDecode.rend(); ++i) { |
| 424 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(*i)) | 427 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(*i)) |
| 425 return; | 428 return; |
| 426 WebPIterator webpFrame; | 429 WebPIterator webpFrame; |
| 427 if (!WebPDemuxGetFrame(m_demux, *i + 1, &webpFrame)) { | 430 if (!WebPDemuxGetFrame(m_demux, *i + 1, &webpFrame)) { |
| 428 setFailed(); | 431 setFailed(); |
| 429 } else { | 432 } else { |
| 430 decodeSingleFrame(webpFrame.fragment.bytes, webpFrame.fragment.size, *i); | 433 decodeSingleFrame(webpFrame.fragment.bytes, webpFrame.fragment.size, *i); |
| 431 WebPDemuxReleaseIterator(&webpFrame); | 434 WebPDemuxReleaseIterator(&webpFrame); |
| 432 } | 435 } |
| 433 if (failed()) | 436 if (failed()) |
| 434 return; | 437 return; |
| 435 | 438 |
| 439 if (m_purgeAggressively) | |
| 440 clearCacheExceptFrame(*i); | |
|
urvang
2016/09/26 18:37:05
I think you need to purge after line#444.
Otherwis
cblume
2016/10/01 11:06:23
Done.
I should do this on the GIF decoder as well.
urvang
2016/10/03 19:12:36
I don't see this change yet. Forgot to upload?
cblume
2016/10/10 21:18:38
Oh, yeah. Sorry.
| |
| 441 | |
| 436 // We need more data to continue decoding. | 442 // We need more data to continue decoding. |
| 437 if (m_frameBufferCache[*i].getStatus() != ImageFrame::FrameComplete) | 443 if (m_frameBufferCache[*i].getStatus() != ImageFrame::FrameComplete) |
| 438 break; | 444 break; |
| 439 } | 445 } |
| 440 | 446 |
| 441 // It is also a fatal error if all data is received and we have decoded all | 447 // It is also a fatal error if all data is received and we have decoded all |
| 442 // frames available but the file is truncated. | 448 // frames available but the file is truncated. |
| 443 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_demux && m_demuxState != WEBP_DEMUX_DONE) | 449 if (index >= m_frameBufferCache.size() - 1 && isAllDataReceived() && m_demux && m_demuxState != WEBP_DEMUX_DONE) |
| 444 setFailed(); | 450 setFailed(); |
| 445 } | 451 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 498 applyPostProcessing(frameIndex); | 504 applyPostProcessing(frameIndex); |
| 499 return false; | 505 return false; |
| 500 } | 506 } |
| 501 // FALLTHROUGH | 507 // FALLTHROUGH |
| 502 default: | 508 default: |
| 503 clear(); | 509 clear(); |
| 504 return setFailed(); | 510 return setFailed(); |
| 505 } | 511 } |
| 506 } | 512 } |
| 507 | 513 |
| 514 void WEBPImageDecoder::updateAggressivePurging(size_t index) | |
|
scroggo_chromium
2016/09/26 12:04:48
This looks to be the exact same method as in GIFIm
cblume
2016/10/01 11:06:23
Good call.
I've moved this into ImageDecoder in ht
| |
| 515 { | |
| 516 if (m_purgeAggressively) | |
| 517 return; | |
| 518 | |
| 519 // We don't want to cache so much that we cause a memory issue. | |
| 520 // | |
| 521 // If we used a LRU cache we would fill it and then on next animation loop | |
| 522 // we would need to decode all the frames again -- the LRU would give no | |
| 523 // benefit and would consume more memory. | |
| 524 // So instead, simply purge unused frames if caching all of the frames of | |
| 525 // the image would use more memory than the image decoder is allowed | |
| 526 // (m_maxDecodedBytes) or would overflow 32 bits.. | |
| 527 // | |
| 528 // As we decode we will learn the total number of frames, and thus total | |
| 529 // possible image memory used. | |
| 530 | |
| 531 const uint64_t frameArea = decodedSize().area(); | |
| 532 const uint64_t frameMemoryUsage = frameArea * 4; // 4 bytes per pixel | |
| 533 if (frameMemoryUsage / 4 != frameArea) { // overflow occurred | |
| 534 m_purgeAggressively = true; | |
| 535 return; | |
| 536 } | |
| 537 | |
| 538 const uint64_t totalMemoryUsage = frameMemoryUsage * index; | |
|
skal
2016/09/26 12:22:51
this multiply is still even more likely to overflo
cblume
2016/10/01 11:06:23
Ah, got ya. Fixed.
I've moved this into ImageDecod
| |
| 539 if (totalMemoryUsage > m_maxDecodedBytes) { | |
| 540 m_purgeAggressively = true; | |
| 541 } | |
| 542 } | |
| 508 } // namespace blink | 543 } // namespace blink |
| OLD | NEW |