diff options
author | Leon Scroggins III <scroggo@google.com> | 2017-04-12 10:49:52 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-04-12 15:22:43 +0000 |
commit | e132e7be5f9108692254c37db592ea7611abbc15 (patch) | |
tree | 44e7973680edc107da087f71d41619dd3aea178e /tests | |
parent | e5efa51b2acc86d1993132348d5b465855a653cc (diff) |
Add SkCodec methods for individual frames
Add a version of getFrameInfo that returns information about a single
frame, allowing a client to skip creating the entire vector.
Add getFrameCount, for determining the number of frames in the image.
Reimplement std::vector<FrameInfo> getFrameInfo with the new methods.
Updates to the test:
- getFrameInfo(size_t, FrameInfo*) fails before parsing
- Test both versions of getFrameInfo
- Recreate the codec between tests, to test parsing
Change-Id: I77c19087f2f8dcf2c536d80167b18ad1ca96ae94
Reviewed-on: https://skia-review.googlesource.com/13190
Reviewed-by: Matt Sarett <msarett@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Chris Blume <cblume@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/CodecAnimTest.cpp | 226 |
1 files changed, 136 insertions, 90 deletions
diff --git a/tests/CodecAnimTest.cpp b/tests/CodecAnimTest.cpp index dea4adbfd2..02253ef64f 100644 --- a/tests/CodecAnimTest.cpp +++ b/tests/CodecAnimTest.cpp @@ -94,20 +94,25 @@ DEF_TEST(Codec_frames, r) { #undef kUnpremul for (const auto& rec : gRecs) { - std::unique_ptr<SkStream> stream(GetResourceAsStream(rec.fName)); - if (!stream) { + sk_sp<SkData> data(GetResourceAsData(rec.fName)); + if (!data) { // Useful error statement, but sometimes people run tests without // resources, and they do not want to see these messages. //ERRORF(r, "Missing resources? Could not find '%s'", rec.fName); continue; } - std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release())); + std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data)); if (!codec) { ERRORF(r, "Failed to create an SkCodec from '%s'", rec.fName); continue; } + { + SkCodec::FrameInfo frameInfo; + REPORTER_ASSERT(r, !codec->getFrameInfo(0, &frameInfo)); + } + const int repetitionCount = codec->getRepetitionCount(); if (repetitionCount != rec.fRepetitionCount) { ERRORF(r, "%s repetition count does not match! expected: %i\tactual: %i", @@ -115,112 +120,153 @@ DEF_TEST(Codec_frames, r) { } const size_t expected = rec.fFrameCount; - const auto frameInfos = codec->getFrameInfo(); - // getFrameInfo returns empty set for non-animated. - const size_t frameCount = frameInfos.size() == 0 ? 1 : frameInfos.size(); - if (frameCount != expected) { - ERRORF(r, "'%s' expected frame count: %i\tactual: %i", rec.fName, expected, frameCount); - continue; - } - if (rec.fRequiredFrames.size() + 1 != expected) { ERRORF(r, "'%s' has wrong number entries in fRequiredFrames; expected: %i\tactual: %i", rec.fName, expected, rec.fRequiredFrames.size() + 1); continue; } - if (1 == frameCount) { + if (rec.fDurations.size() != expected) { + ERRORF(r, "'%s' has wrong number entries in fDurations; expected: %i\tactual: %i", + rec.fName, expected, rec.fDurations.size()); continue; } - auto to_string = [](SkAlphaType type) { - switch (type) { - case kUnpremul_SkAlphaType: - return "unpremul"; - case kOpaque_SkAlphaType: - return "opaque"; - default: - return "other"; - } + enum class TestMode { + kVector, + kIndividual, }; - // From here on, we are only concerned with animated images. - REPORTER_ASSERT(r, frameInfos[0].fRequiredFrame == SkCodec::kNone); - REPORTER_ASSERT(r, frameInfos[0].fAlphaType == codec->getInfo().alphaType()); - for (size_t i = 1; i < frameCount; i++) { - if (rec.fRequiredFrames[i-1] != frameInfos[i].fRequiredFrame) { - ERRORF(r, "%s's frame %i has wrong dependency! expected: %i\tactual: %i", - rec.fName, i, rec.fRequiredFrames[i-1], frameInfos[i].fRequiredFrame); + + for (auto mode : { TestMode::kVector, TestMode::kIndividual }) { + // Re-create the codec to reset state and test parsing. + codec.reset(SkCodec::NewFromData(data)); + + size_t frameCount; + std::vector<SkCodec::FrameInfo> frameInfos; + switch (mode) { + case TestMode::kVector: + frameInfos = codec->getFrameInfo(); + // getFrameInfo returns empty set for non-animated. + frameCount = frameInfos.empty() ? 1 : frameInfos.size(); + break; + case TestMode::kIndividual: + frameCount = codec->getFrameCount(); + break; } - auto expectedAlpha = rec.fAlphaTypes[i-1]; - auto alpha = frameInfos[i].fAlphaType; - if (expectedAlpha != alpha) { - ERRORF(r, "%s's frame %i has wrong alpha type! expected: %s\tactual: %s", - rec.fName, i, to_string(expectedAlpha), to_string(alpha)); + + if (frameCount != expected) { + ERRORF(r, "'%s' expected frame count: %i\tactual: %i", + rec.fName, expected, frameCount); + continue; } - } - // Compare decoding in two ways: - // 1. Provide the frame that a frame depends on, so the codec just has to blend. - // (in the array cachedFrames) - // 2. Do not provide the frame that a frame depends on, so the codec has to decode all the - // way back to a key-frame. (in a local variable uncachedFrame) - // The two should look the same. - std::vector<SkBitmap> cachedFrames(frameCount); - const auto& info = codec->getInfo().makeColorType(kN32_SkColorType); - - auto decode = [&](SkBitmap* bm, bool cached, size_t index) { - bm->allocPixels(info); - if (cached) { - // First copy the pixels from the cached frame - const size_t requiredFrame = frameInfos[index].fRequiredFrame; - if (requiredFrame != SkCodec::kNone) { - const bool success = cachedFrames[requiredFrame].copyTo(bm); - REPORTER_ASSERT(r, success); - } + // From here on, we are only concerned with animated images. + if (1 == frameCount) { + continue; } - SkCodec::Options opts; - opts.fFrameIndex = index; - opts.fHasPriorFrame = cached; - const SkCodec::Result result = codec->getPixels(info, bm->getPixels(), bm->rowBytes(), - &opts, nullptr, nullptr); - REPORTER_ASSERT(r, result == SkCodec::kSuccess); - }; - for (size_t i = 0; i < frameCount; i++) { - SkBitmap& cachedFrame = cachedFrames[i]; - decode(&cachedFrame, true, i); - SkBitmap uncachedFrame; - decode(&uncachedFrame, false, i); - - // Now verify they're equal. - const size_t rowLen = info.bytesPerPixel() * info.width(); - for (int y = 0; y < info.height(); y++) { - const void* cachedAddr = cachedFrame.getAddr(0, y); - SkASSERT(cachedAddr != nullptr); - const void* uncachedAddr = uncachedFrame.getAddr(0, y); - SkASSERT(uncachedAddr != nullptr); - const bool lineMatches = memcmp(cachedAddr, uncachedAddr, rowLen) == 0; - if (!lineMatches) { - SkString name = SkStringPrintf("cached_%i", i); - write_bm(name.c_str(), cachedFrame); - name = SkStringPrintf("uncached_%i", i); - write_bm(name.c_str(), uncachedFrame); - ERRORF(r, "%s's frame %i is different depending on caching!", rec.fName, i); - break; + for (size_t i = 0; i < frameCount; i++) { + SkCodec::FrameInfo frameInfo; + switch (mode) { + case TestMode::kVector: + frameInfo = frameInfos[i]; + break; + case TestMode::kIndividual: + REPORTER_ASSERT(r, codec->getFrameInfo(i, nullptr)); + REPORTER_ASSERT(r, codec->getFrameInfo(i, &frameInfo)); + break; + } + + if (rec.fDurations[i] != frameInfo.fDuration) { + ERRORF(r, "%s frame %i's durations do not match! expected: %i\tactual: %i", + rec.fName, i, rec.fDurations[i], frameInfo.fDuration); + } + + if (0 == i) { + REPORTER_ASSERT(r, frameInfo.fRequiredFrame == SkCodec::kNone); + REPORTER_ASSERT(r, frameInfo.fAlphaType == codec->getInfo().alphaType()); + continue; + } + + if (rec.fRequiredFrames[i-1] != frameInfo.fRequiredFrame) { + ERRORF(r, "%s's frame %i has wrong dependency! expected: %i\tactual: %i", + rec.fName, i, rec.fRequiredFrames[i-1], frameInfo.fRequiredFrame); + } + + auto to_string = [](SkAlphaType type) { + switch (type) { + case kUnpremul_SkAlphaType: + return "unpremul"; + case kOpaque_SkAlphaType: + return "opaque"; + default: + return "other"; + } + }; + + auto expectedAlpha = rec.fAlphaTypes[i-1]; + auto alpha = frameInfo.fAlphaType; + if (expectedAlpha != alpha) { + ERRORF(r, "%s's frame %i has wrong alpha type! expected: %s\tactual: %s", + rec.fName, i, to_string(expectedAlpha), to_string(alpha)); } } - } - if (rec.fDurations.size() != expected) { - ERRORF(r, "'%s' has wrong number entries in fDurations; expected: %i\tactual: %i", - rec.fName, expected, rec.fDurations.size()); - continue; - } + if (TestMode::kIndividual == mode) { + // No need to test decoding twice. + return; + } + + // Compare decoding in two ways: + // 1. Provide the frame that a frame depends on, so the codec just has to blend. + // (in the array cachedFrames) + // 2. Do not provide the frame that a frame depends on, so the codec has to decode + // all the way back to a key-frame. (in a local variable uncachedFrame) + // The two should look the same. + std::vector<SkBitmap> cachedFrames(frameCount); + const auto& info = codec->getInfo().makeColorType(kN32_SkColorType); - for (size_t i = 0; i < frameCount; i++) { - if (rec.fDurations[i] != frameInfos[i].fDuration) { - ERRORF(r, "%s frame %i's durations do not match! expected: %i\tactual: %i", - rec.fName, i, rec.fDurations[i], frameInfos[i].fDuration); + auto decode = [&](SkBitmap* bm, bool cached, size_t index) { + bm->allocPixels(info); + if (cached) { + // First copy the pixels from the cached frame + const size_t requiredFrame = frameInfos[index].fRequiredFrame; + if (requiredFrame != SkCodec::kNone) { + const bool success = cachedFrames[requiredFrame].copyTo(bm); + REPORTER_ASSERT(r, success); + } + } + SkCodec::Options opts; + opts.fFrameIndex = index; + opts.fHasPriorFrame = cached; + auto result = codec->getPixels(info, bm->getPixels(), bm->rowBytes(), + &opts, nullptr, nullptr); + REPORTER_ASSERT(r, result == SkCodec::kSuccess); + }; + + for (size_t i = 0; i < frameCount; i++) { + SkBitmap& cachedFrame = cachedFrames[i]; + decode(&cachedFrame, true, i); + SkBitmap uncachedFrame; + decode(&uncachedFrame, false, i); + + // Now verify they're equal. + const size_t rowLen = info.bytesPerPixel() * info.width(); + for (int y = 0; y < info.height(); y++) { + const void* cachedAddr = cachedFrame.getAddr(0, y); + SkASSERT(cachedAddr != nullptr); + const void* uncachedAddr = uncachedFrame.getAddr(0, y); + SkASSERT(uncachedAddr != nullptr); + const bool lineMatches = memcmp(cachedAddr, uncachedAddr, rowLen) == 0; + if (!lineMatches) { + SkString name = SkStringPrintf("cached_%i", i); + write_bm(name.c_str(), cachedFrame); + name = SkStringPrintf("uncached_%i", i); + write_bm(name.c_str(), uncachedFrame); + ERRORF(r, "%s's frame %i is different depending on caching!", rec.fName, i); + break; + } + } } } } |