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

Side by Side Diff: dm/DMSrcSink.cpp

Issue 2045293002: Add support for multiple frames in SkCodec (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Various fixes Created 4 years, 2 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
« no previous file with comments | « dm/DMSrcSink.h ('k') | fuzz/fuzz.cpp » ('j') | gyp/codec.gyp » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "DMSrcSink.h" 8 #include "DMSrcSink.h"
9 #include "Resources.h" 9 #include "Resources.h"
10 #include "SkAndroidCodec.h" 10 #include "SkAndroidCodec.h"
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 403
404 // Visually inspecting very small output images is not necessary. We will 404 // Visually inspecting very small output images is not necessary. We will
405 // cover these cases in unit testing. 405 // cover these cases in unit testing.
406 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { 406 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) {
407 return Error::Nonfatal("Scaling very small images is uninteresting."); 407 return Error::Nonfatal("Scaling very small images is uninteresting.");
408 } 408 }
409 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); 409 decodeInfo = decodeInfo.makeWH(size.width(), size.height());
410 410
411 const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType()); 411 const int bpp = SkColorTypeBytesPerPixel(decodeInfo.colorType());
412 const size_t rowBytes = size.width() * bpp; 412 const size_t rowBytes = size.width() * bpp;
413 SkAutoMalloc pixels(decodeInfo.getSafeSize(rowBytes)); 413 const size_t safeSize = decodeInfo.getSafeSize(rowBytes);
414 SkAutoMalloc pixels(safeSize);
414 SkPMColor colorPtr[256]; 415 SkPMColor colorPtr[256];
415 int colorCount = 256; 416 int colorCount = 256;
416 417
417 SkCodec::Options options; 418 SkCodec::Options options;
418 if (kCodecZeroInit_Mode == fMode) { 419 if (kCodecZeroInit_Mode == fMode) {
419 memset(pixels.get(), 0, size.height() * rowBytes); 420 memset(pixels.get(), 0, size.height() * rowBytes);
420 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; 421 options.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
421 } 422 }
422 423
423 SkImageInfo bitmapInfo = decodeInfo; 424 SkImageInfo bitmapInfo = decodeInfo;
424 if (kRGBA_8888_SkColorType == decodeInfo.colorType() || 425 if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
425 kBGRA_8888_SkColorType == decodeInfo.colorType()) { 426 kBGRA_8888_SkColorType == decodeInfo.colorType()) {
426 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); 427 bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
427 } 428 }
428 429
429 switch (fMode) { 430 switch (fMode) {
431 case kAnimated_Mode: {
432 std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo();
433 if (frameInfos.size() <= 1) {
434 return SkStringPrintf("%s is not an animated image.", fPath.c_st r());
435 }
436
437 SkAutoCanvasRestore acr(canvas, true);
438 // Used to cache a frame that future frames will depend on.
439 SkAutoMalloc priorFramePixels;
440 size_t cachedFrame = SkCodec::kIndependentFrame;
441 SkCodec::MultiFrameOptions multiOptions;
442 options.fFrameOptions = &multiOptions;
443 for (size_t i = 0; i < frameInfos.size(); i++) {
444 multiOptions.fIndex = i;
445 // Check for a prior frame
446 const size_t reqFrame = frameInfos[i].fRequiredFrame;
447 if (reqFrame != SkCodec::kIndependentFrame && reqFrame == cached Frame
cblume 2016/10/14 16:52:35 I wonder if we can find a better name than kIndepe
scroggo_chromium 2016/10/14 19:55:59 I understand your confusion, and I'm not opposed t
cblume 2016/10/18 21:57:32 I agree that I'm not a fan of kNotFound. It wasn't
scroggo_chromium 2016/10/20 17:57:12 Done.
448 && priorFramePixels.get()) {
449 // Copy into pixels
450 memcpy(pixels.get(), priorFramePixels.get(), safeSize);
451 multiOptions.fHasPriorFrame = true;
452 } else {
453 multiOptions.fHasPriorFrame = false;
454 }
455 const SkCodec::Result result = codec->getPixels(decodeInfo, pixe ls.get(),
456 rowBytes, &optio ns,
457 colorPtr, &color Count);
458 switch (result) {
459 case SkCodec::kSuccess:
460 case SkCodec::kIncompleteInput:
461 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowByte s,
462 colorPtr, colorCount, fDstColorType);
463 if (result == SkCodec::kIncompleteInput) {
464 return "";
465 }
466 break;
467 default:
468 return SkStringPrintf("Couldn't getPixels for frame %i i n %s.",
469 i, fPath.c_str());
470 }
471
472 // If a future frame depends on this one, store it in priorFrame .
473 // (Note that if i+1 does *not* depend on i, then no future fram e can.)
474 if (i+1 < frameInfos.size() && frameInfos[i+1].fRequiredFrame == i) {
475 memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeS ize);
476 cachedFrame = i;
477 }
cblume 2016/10/14 16:52:35 I like this way of dealing with DisposeOverwritePr
478
479 canvas->translate(SkIntToScalar(0), SkIntToScalar(decodeInfo.hei ght()));
480 }
481 break;
482 }
430 case kCodecZeroInit_Mode: 483 case kCodecZeroInit_Mode:
431 case kCodec_Mode: { 484 case kCodec_Mode: {
432 switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &option s, 485 switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &option s,
433 colorPtr, &colorCount)) { 486 colorPtr, &colorCount)) {
434 case SkCodec::kSuccess: 487 case SkCodec::kSuccess:
435 // We consider incomplete to be valid, since we should still decode what is 488 // We consider incomplete to be valid, since we should still decode what is
436 // available. 489 // available.
437 case SkCodec::kIncompleteInput: 490 case SkCodec::kIncompleteInput:
438 break; 491 break;
439 default: 492 default:
440 // Everything else is considered a failure. 493 // Everything else is considered a failure.
441 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str( )); 494 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str( ));
442 } 495 }
443 496
444 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount, 497 draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, colorPtr, colorCount,
445 fDstColorType); 498 fDstColorType);
446 break; 499 break;
447 } 500 }
448 case kScanline_Mode: { 501 case kScanline_Mode: {
449 void* dst = pixels.get(); 502 void* dst = pixels.get();
450 uint32_t height = decodeInfo.height(); 503 uint32_t height = decodeInfo.height();
451 const bool png = fPath.endsWith("png"); 504 const bool useIncremental = fPath.endsWith("png") || fPath.endsWith( "gif") || fPath.endsWith("GIF");
msarett 2016/10/14 14:58:50 nit: 100 chars nit: Should we defensively add PNG
cblume 2016/10/14 16:52:35 or just toLower
scroggo_chromium 2016/10/14 19:55:59 done
505 // ico may use the old scanline method or the new one, depending on whether it
506 // internally holds a bmp or a png.
452 const bool ico = fPath.endsWith("ico"); 507 const bool ico = fPath.endsWith("ico");
453 bool useOldScanlineMethod = !png && !ico; 508 bool useOldScanlineMethod = !useIncremental && !ico;
454 if (png || ico) { 509 if (useIncremental || ico) {
455 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInf o, dst, 510 if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInf o, dst,
456 rowBytes, nullptr, colorPtr, &colorCount)) { 511 rowBytes, nullptr, colorPtr, &colorCount)) {
457 int rowsDecoded; 512 int rowsDecoded;
458 if (SkCodec::kIncompleteInput == codec->incrementalDecode(&r owsDecoded)) { 513 if (SkCodec::kIncompleteInput == codec->incrementalDecode(&r owsDecoded)) {
459 codec->fillIncompleteImage(decodeInfo, dst, rowBytes, 514 codec->fillIncompleteImage(decodeInfo, dst, rowBytes,
460 SkCodec::kNo_ZeroInitialized, height, 515 SkCodec::kNo_ZeroInitialized, height,
461 rowsDecoded); 516 rowsDecoded);
462 } 517 }
463 } else { 518 } else {
464 if (png) { 519 if (useIncremental) {
465 // Error: PNG should support incremental decode. 520 // Error: These should support incremental decode.
466 return "Could not start incremental decode"; 521 return "Could not start incremental decode";
467 } 522 }
468 // Otherwise, this is an ICO. Since incremental failed, it m ust contain a BMP, 523 // Otherwise, this is an ICO. Since incremental failed, it m ust contain a BMP,
469 // which should work via startScanlineDecode 524 // which should work via startScanlineDecode
470 useOldScanlineMethod = true; 525 useOldScanlineMethod = true;
471 } 526 }
472 } 527 }
473 528
474 if (useOldScanlineMethod) { 529 if (useOldScanlineMethod) {
475 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr, 530 if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, NULL, colorPtr,
476 &colorCount) ) { 531 &colorCount) ) {
477 return "Could not start scanline decoder"; 532 return "Could not start scanline decoder";
478 } 533 }
479 534
480 switch (codec->getScanlineOrder()) { 535 switch (codec->getScanlineOrder()) {
481 case SkCodec::kTopDown_SkScanlineOrder: 536 case SkCodec::kTopDown_SkScanlineOrder:
482 case SkCodec::kBottomUp_SkScanlineOrder: 537 case SkCodec::kBottomUp_SkScanlineOrder:
483 // We do not need to check the return value. On an inco mplete 538 // We do not need to check the return value. On an inco mplete
484 // image, memory will be filled with a default value. 539 // image, memory will be filled with a default value.
485 codec->getScanlines(dst, height, rowBytes); 540 codec->getScanlines(dst, height, rowBytes);
486 break; 541 break;
487 case SkCodec::kOutOfOrder_SkScanlineOrder: {
488 for (int y = 0; y < decodeInfo.height(); y++) {
489 int dstY = codec->outputScanline(y);
490 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * ds tY);
491 // We complete the loop, even if this call begins to fail
492 // due to an incomplete image. This ensures any uni nitialized
493 // memory will be filled with the proper value.
494 codec->getScanlines(dstPtr, 1, rowBytes);
495 }
496 break;
497 }
498 } 542 }
499 } 543 }
500 544
501 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCou nt, fDstColorType); 545 draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, colorPtr, colorCou nt, fDstColorType);
502 break; 546 break;
503 } 547 }
504 case kStripe_Mode: { 548 case kStripe_Mode: {
505 const int height = decodeInfo.height(); 549 const int height = decodeInfo.height();
506 // This value is chosen arbitrarily. We exercise more cases by choo sing a value that 550 // This value is chosen arbitrarily. We exercise more cases by choo sing a value that
507 // does not align with image blocks. 551 // does not align with image blocks.
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
653 } 697 }
654 return ""; 698 return "";
655 } 699 }
656 700
657 SkISize CodecSrc::size() const { 701 SkISize CodecSrc::size() const {
658 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); 702 sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str()));
659 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 703 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
660 if (nullptr == codec) { 704 if (nullptr == codec) {
661 return SkISize::Make(0, 0); 705 return SkISize::Make(0, 0);
662 } 706 }
663 return codec->getScaledDimensions(fScale); 707
708 auto imageSize = codec->getScaledDimensions(fScale);
709 if (fMode == kAnimated_Mode) {
710 // We'll draw one of each frame, so make it big enough to hold them all.
711 const size_t count = codec->getFrameInfo().size();
712 imageSize.fHeight = imageSize.fHeight * count;
713 }
714 return imageSize;
664 } 715 }
665 716
666 Name CodecSrc::name() const { 717 Name CodecSrc::name() const {
667 if (1.0f == fScale) { 718 if (1.0f == fScale) {
668 return SkOSPath::Basename(fPath.c_str()); 719 return SkOSPath::Basename(fPath.c_str());
669 } 720 }
670 return get_scaled_name(fPath, fScale); 721 return get_scaled_name(fPath, fScale);
671 } 722 }
672 723
673 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/ 724 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/
(...skipping 1034 matching lines...) Expand 10 before | Expand all | Expand 10 after
1708 Error err = src.draw(&rec); 1759 Error err = src.draw(&rec);
1709 if (!err.isEmpty()) { 1760 if (!err.isEmpty()) {
1710 return err; 1761 return err;
1711 } 1762 }
1712 dl->draw(canvas); 1763 dl->draw(canvas);
1713 return check_against_reference(bitmap, src, fSink); 1764 return check_against_reference(bitmap, src, fSink);
1714 }); 1765 });
1715 } 1766 }
1716 1767
1717 } // namespace DM 1768 } // namespace DM
OLDNEW
« no previous file with comments | « dm/DMSrcSink.h ('k') | fuzz/fuzz.cpp » ('j') | gyp/codec.gyp » ('J')

Powered by Google App Engine
This is Rietveld 408576698