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

Side by Side Diff: Source/core/platform/image-decoders/webp/WEBPImageDecoder.cpp

Issue 23068027: Animated WebP: Optimize decoding in case of seeking (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@add_noblend_image
Patch Set: Fix assert fail on debug Created 7 years, 3 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
OLDNEW
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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 Vector<size_t> framesToDecode; 120 Vector<size_t> framesToDecode;
121 size_t frameToDecode = index; 121 size_t frameToDecode = index;
122 do { 122 do {
123 framesToDecode.append(frameToDecode); 123 framesToDecode.append(frameToDecode);
124 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFr ameIndex(); 124 frameToDecode = m_frameBufferCache[frameToDecode].requiredPreviousFr ameIndex();
125 } while (frameToDecode != notFound && m_frameBufferCache[frameToDecode]. status() != ImageFrame::FrameComplete); 125 } while (frameToDecode != notFound && m_frameBufferCache[frameToDecode]. status() != ImageFrame::FrameComplete);
126 126
127 ASSERT(m_demux); 127 ASSERT(m_demux);
128 for (size_t i = framesToDecode.size(); i > 0; --i) { 128 for (size_t i = framesToDecode.size(); i > 0; --i) {
129 size_t frameIndex = framesToDecode[i - 1]; 129 size_t frameIndex = framesToDecode[i - 1];
130 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(frameIndex) )
131 return 0;
130 WebPIterator webpFrame; 132 WebPIterator webpFrame;
131 if (!WebPDemuxGetFrame(m_demux, frameIndex + 1, &webpFrame)) 133 if (!WebPDemuxGetFrame(m_demux, frameIndex + 1, &webpFrame))
132 return 0; 134 return 0;
133 if ((m_formatFlags & ANIMATION_FLAG) && !initFrameBuffer(webpFrame, frameIndex)) {
134 WebPDemuxReleaseIterator(&webpFrame);
135 return 0;
136 }
137 PlatformInstrumentation::willDecodeImage("WEBP"); 135 PlatformInstrumentation::willDecodeImage("WEBP");
138 decode(webpFrame.fragment.bytes, webpFrame.fragment.size, false, fra meIndex); 136 decode(webpFrame.fragment.bytes, webpFrame.fragment.size, false, fra meIndex);
139 PlatformInstrumentation::didDecodeImage(); 137 PlatformInstrumentation::didDecodeImage();
140 WebPDemuxReleaseIterator(&webpFrame); 138 WebPDemuxReleaseIterator(&webpFrame);
141 139
142 // We need more data to continue decoding. 140 // We need more data to continue decoding.
143 if (m_frameBufferCache[frameIndex].status() != ImageFrame::FrameComp lete) 141 if (m_frameBufferCache[frameIndex].status() != ImageFrame::FrameComp lete)
144 break; 142 break;
145 } 143 }
146 144
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 if (!hasAnimation) { 238 if (!hasAnimation) {
241 ASSERT(!i); 239 ASSERT(!i);
242 m_frameBufferCache[i].setRequiredPreviousFrameIndex(notFound); 240 m_frameBufferCache[i].setRequiredPreviousFrameIndex(notFound);
243 continue; 241 continue;
244 } 242 }
245 WebPIterator animatedFrame; 243 WebPIterator animatedFrame;
246 WebPDemuxGetFrame(m_demux, i + 1, &animatedFrame); 244 WebPDemuxGetFrame(m_demux, i + 1, &animatedFrame);
247 ASSERT(animatedFrame.complete == 1); 245 ASSERT(animatedFrame.complete == 1);
248 m_frameBufferCache[i].setDuration(animatedFrame.duration); 246 m_frameBufferCache[i].setDuration(animatedFrame.duration);
249 m_frameBufferCache[i].setDisposalMethod(animatedFrame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? ImageFrame::DisposeOverwriteBgcolor : ImageFra me::DisposeKeep); 247 m_frameBufferCache[i].setDisposalMethod(animatedFrame.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? ImageFrame::DisposeOverwriteBgcolor : ImageFra me::DisposeKeep);
248 m_frameBufferCache[i].setAlphaBlendSource(animatedFrame.blend_method == WEBP_MUX_BLEND ? ImageFrame::BlendAtopPreviousFrame : ImageFrame::BlendAtopB gcolor);
249 IntRect frameRect(animatedFrame.x_offset, animatedFrame.y_offset, an imatedFrame.width, animatedFrame.height);
250 // Make sure the frameRect doesn't extend outside the buffer.
251 if (frameRect.maxX() > size().width())
252 frameRect.setWidth(size().width() - animatedFrame.x_offset);
253 if (frameRect.maxY() > size().height())
254 frameRect.setHeight(size().height() - animatedFrame.y_offset);
255 m_frameBufferCache[i].setOriginalFrameRect(frameRect);
256 m_frameBufferCache[i].setRequiredPreviousFrameIndex(findRequiredPrev iousFrame(i, !animatedFrame.has_alpha));
250 WebPDemuxReleaseIterator(&animatedFrame); 257 WebPDemuxReleaseIterator(&animatedFrame);
251 m_frameBufferCache[i].setRequiredPreviousFrameIndex(findRequiredPrev iousFrame(i));
252 } 258 }
253 } 259 }
254 260
255 return true; 261 return true;
256 } 262 }
257 263
258 bool WEBPImageDecoder::initFrameBuffer(const WebPIterator& frame, size_t frameIn dex) 264 bool WEBPImageDecoder::initFrameBuffer(size_t frameIndex)
259 { 265 {
260 ImageFrame& buffer = m_frameBufferCache[frameIndex]; 266 ImageFrame& buffer = m_frameBufferCache[frameIndex];
261 if (buffer.status() != ImageFrame::FrameEmpty) // Already initialized. 267 if (buffer.status() != ImageFrame::FrameEmpty) // Already initialized.
262 return true; 268 return true;
263 269
264 // Initialize the frame rect in our buffer.
265 IntRect frameRect(frame.x_offset, frame.y_offset, frame.width, frame.height) ;
266
267 // Make sure the frameRect doesn't extend outside the buffer.
268 if (frameRect.maxX() > size().width())
269 frameRect.setWidth(size().width() - frame.x_offset);
270 if (frameRect.maxY() > size().height())
271 frameRect.setHeight(size().height() - frame.y_offset);
272 buffer.setOriginalFrameRect(frameRect);
273
274 const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex( ); 270 const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex( );
275 if (requiredPreviousFrameIndex == notFound) { 271 if (requiredPreviousFrameIndex == notFound) {
276 // This frame doesn't rely on any previous data. 272 // This frame doesn't rely on any previous data.
277 if (!buffer.setSize(size().width(), size().height())) 273 if (!buffer.setSize(size().width(), size().height()))
278 return setFailed(); 274 return setFailed();
279 m_frameBackgroundHasAlpha = !frameRect.contains(IntRect(IntPoint(), size ())); 275 m_frameBackgroundHasAlpha = !buffer.originalFrameRect().contains(IntRect (IntPoint(), size()));
280 } else { 276 } else {
281 const ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameI ndex]; 277 const ImageFrame& prevBuffer = m_frameBufferCache[requiredPreviousFrameI ndex];
282 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); 278 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete);
283 279
284 // Preserve the last frame as the starting state for this frame. 280 // Preserve the last frame as the starting state for this frame.
285 if (!buffer.copyBitmapData(prevBuffer)) 281 if (!buffer.copyBitmapData(prevBuffer))
286 return setFailed(); 282 return setFailed();
287 283
288 if (prevBuffer.disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) { 284 if (prevBuffer.disposalMethod() == ImageFrame::DisposeOverwriteBgcolor) {
289 // We want to clear the previous frame to transparent, without 285 // We want to clear the previous frame to transparent, without
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 for (int x = 0; x < width; ++x, pixel += 4) { 404 for (int x = 0; x < width; ++x, pixel += 4) {
409 const int canvasX = left + x; 405 const int canvasX = left + x;
410 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], p ixel[3]); 406 buffer.setRGBA(canvasX, canvasY, pixel[0], pixel[1], pixel[2], p ixel[3]);
411 } 407 }
412 } 408 }
413 } 409 }
414 #endif // USE(QCMSLIB) 410 #endif // USE(QCMSLIB)
415 411
416 // During the decoding of current frame, we may have set some pixels to be t ransparent (i.e. alpha < 255). 412 // During the decoding of current frame, we may have set some pixels to be t ransparent (i.e. alpha < 255).
417 // However, the value of each of these pixels should have been determined by blending it against the value 413 // However, the value of each of these pixels should have been determined by blending it against the value
418 // of that pixel in the previous frame. So, we correct these pixels based on disposal method of the previous 414 // of that pixel in the previous frame if alpha blend source was 'BlendAtopP reviousFrame'. So, we correct these
419 // frame and the previous frame buffer. 415 // pixels based on disposal method of the previous frame and the previous fr ame buffer.
420 // FIXME: This could be avoided if libwebp decoder had an API that used the previous required frame 416 // FIXME: This could be avoided if libwebp decoder had an API that used the previous required frame
421 // to do the alpha-blending by itself. 417 // to do the alpha-blending by itself.
422 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex) { 418 if ((m_formatFlags & ANIMATION_FLAG) && frameIndex && buffer.alphaBlendSourc e() == ImageFrame::BlendAtopPreviousFrame && buffer.requiredPreviousFrameIndex() != notFound) {
423 ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1]; 419 ImageFrame& prevBuffer = m_frameBufferCache[frameIndex - 1];
424 ImageFrame::FrameDisposalMethod prevMethod = prevBuffer.disposalMethod() ; 420 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete);
425 if (prevMethod == ImageFrame::DisposeKeep) { // Restore transparent pixe ls to pixels in previous canvas. 421 ImageFrame::DisposalMethod prevDisposalMethod = prevBuffer.disposalMetho d();
426 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete); 422 if (prevDisposalMethod == ImageFrame::DisposeKeep) { // Restore transpar ent pixels to pixels in previous canvas.
427 for (int y = m_decodedHeight; y < decodedHeight; ++y) { 423 for (int y = m_decodedHeight; y < decodedHeight; ++y) {
428 const int canvasY = top + y; 424 const int canvasY = top + y;
429 for (int x = 0; x < width; ++x) { 425 for (int x = 0; x < width; ++x) {
430 const int canvasX = left + x; 426 const int canvasX = left + x;
431 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv asY); 427 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv asY);
432 // FIXME: Use alpha-blending when alpha is between 0 and 255 . 428 // FIXME: Use alpha-blending when alpha is between 0 and 255 .
433 // Alpha-blending is being implemented in: https://bugs.webk it.org/show_bug.cgi?id=17022 429 // Alpha-blending is being implemented in: https://bugs.webk it.org/show_bug.cgi?id=17022
434 if (!((pixel >> SK_A32_SHIFT) & 0xff)) { 430 if (!((pixel >> SK_A32_SHIFT) & 0xff)) {
435 ImageFrame::PixelData prevPixel = *prevBuffer.getAddr(ca nvasX, canvasY); 431 ImageFrame::PixelData prevPixel = *prevBuffer.getAddr(ca nvasX, canvasY);
436 pixel = prevPixel; 432 pixel = prevPixel;
437 } 433 }
438 } 434 }
439 } 435 }
440 } else if (prevMethod == ImageFrame::DisposeOverwriteBgcolor && buffer.r equiredPreviousFrameIndex() != notFound) { 436 } else if (prevDisposalMethod == ImageFrame::DisposeOverwriteBgcolor) {
441 // Note: if the requiredPreviousFrameIndex is |notFound|, there's no thing to do.
442 ASSERT(prevBuffer.status() == ImageFrame::FrameComplete);
443 const IntRect& prevRect = prevBuffer.originalFrameRect(); 437 const IntRect& prevRect = prevBuffer.originalFrameRect();
444 // We need to restore transparent pixels to as they were just after initFrame() call. That is: 438 // We need to restore transparent pixels to as they were just after initFrame() call. That is:
445 // * Transparent if it belongs to prevRect <-- This is a no-op. 439 // * Transparent if it belongs to prevRect <-- This is a no-op.
446 // * Pixel in the previous canvas otherwise <-- Need to restore. 440 // * Pixel in the previous canvas otherwise <-- Need to restore.
447 for (int y = m_decodedHeight; y < decodedHeight; ++y) { 441 for (int y = m_decodedHeight; y < decodedHeight; ++y) {
448 const int canvasY = top + y; 442 const int canvasY = top + y;
449 for (int x = 0; x < width; ++x) { 443 for (int x = 0; x < width; ++x) {
450 const int canvasX = left + x; 444 const int canvasX = left + x;
451 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv asY); 445 ImageFrame::PixelData& pixel = *buffer.getAddr(canvasX, canv asY);
452 // FIXME: Use alpha-blending when alpha is between 0 and 255 . 446 // FIXME: Use alpha-blending when alpha is between 0 and 255 .
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 case VP8_STATUS_SUSPENDED: 525 case VP8_STATUS_SUSPENDED:
532 applyPostProcessing(frameIndex); 526 applyPostProcessing(frameIndex);
533 return false; 527 return false;
534 default: 528 default:
535 clear(); 529 clear();
536 return setFailed(); 530 return setFailed();
537 } 531 }
538 } 532 }
539 533
540 } // namespace WebCore 534 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698