diff options
author | Mike Reed <reed@google.com> | 2018-10-03 10:16:55 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-10-03 14:43:18 +0000 |
commit | 964aedb5e3ffcf814ccbb37adf2a9a02c7235b3c (patch) | |
tree | e91ad29ef8b5c4cf101c7e8e549a77842227d6e1 | |
parent | 3093a17128192b1b058ac67b796cbb0afaca1c9f (diff) | |
download | skqp-964aedb5e3ffcf814ccbb37adf2a9a02c7235b3c.tar.gz |
play with animated gif
Bug: skia:
Change-Id: If86314cda6aa84f4824958cca30cde88a78d4b59
Reviewed-on: https://skia-review.googlesource.com/c/158562
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
-rw-r--r-- | gm/animatedGif.cpp | 58 | ||||
-rw-r--r-- | gn/utils.gni | 2 | ||||
-rw-r--r-- | include/utils/SkAnimCodecPlayer.h | 60 | ||||
-rw-r--r-- | src/utils/SkAnimCodecPlayer.cpp | 79 |
4 files changed, 198 insertions, 1 deletions
diff --git a/gm/animatedGif.cpp b/gm/animatedGif.cpp index 6e9789e074..f2fb09d71b 100644 --- a/gm/animatedGif.cpp +++ b/gm/animatedGif.cpp @@ -182,6 +182,62 @@ private: return true; } }; - DEF_GM(return new AnimatedGifGM); + +#include "SkAnimCodecPlayer.h" +#include "SkOSFile.h" +#include "SkMakeUnique.h" + +static std::unique_ptr<SkCodec> load_codec(const char filename[]) { + return SkCodec::MakeFromData(SkData::MakeFromFileName(filename)); +} + +class AnimCodecPlayerGM : public skiagm::GM { +private: + std::vector<std::unique_ptr<SkAnimCodecPlayer> > fPlayers; + uint32_t fBaseMSec = 0; + +public: + AnimCodecPlayerGM() { + const char* root = "/skia/anim/"; + SkOSFile::Iter iter(root); + SkString path; + while (iter.next(&path)) { + SkString completepath; + completepath.printf("%s%s", root, path.c_str()); + auto codec = load_codec(completepath.c_str()); + if (codec) { + fPlayers.push_back(skstd::make_unique<SkAnimCodecPlayer>(std::move(codec))); + } + } + } + +private: + SkString onShortName() override { + return SkString("AnimCodecPlayer"); + } + + SkISize onISize() override { + return { 1024, 768 }; + } + + void onDraw(SkCanvas* canvas) override { + canvas->scale(0.25f, 0.25f); + for (auto& p : fPlayers) { + canvas->drawImage(p->getFrame(), 0, 0, nullptr); + canvas->translate(p->dimensions().width(), 0); + } + } + + bool onAnimate(const SkAnimTimer& timer) override { + if (fBaseMSec == 0) { + fBaseMSec = timer.msec(); + } + for (auto& p : fPlayers) { + (void)p->seek(timer.msec() - fBaseMSec); + } + return true; + } +}; +DEF_GM(return new AnimCodecPlayerGM); diff --git a/gn/utils.gni b/gn/utils.gni index 6f59ff2c71..742d1c2612 100644 --- a/gn/utils.gni +++ b/gn/utils.gni @@ -8,6 +8,7 @@ _src = get_path_info("../src", "abspath") _include = get_path_info("../include", "abspath") skia_utils_sources = [ + "$_include/utils/SkAnimCodecPlayer.h", "$_include/utils/SkFrontBufferedStream.h", "$_include/utils/SkCamera.h", "$_include/utils/SkCanvasStateUtils.h", @@ -23,6 +24,7 @@ skia_utils_sources = [ "$_include/utils/SkShadowUtils.h", "$_src/utils/Sk3D.cpp", + "$_src/utils/SkAnimCodecPlayer.cpp", "$_src/utils/SkBase64.cpp", "$_src/utils/SkBase64.h", "$_src/utils/SkBitSet.h", diff --git a/include/utils/SkAnimCodecPlayer.h b/include/utils/SkAnimCodecPlayer.h new file mode 100644 index 0000000000..4b8855699b --- /dev/null +++ b/include/utils/SkAnimCodecPlayer.h @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkAnimCodecPlayer_DEFINED +#define SkAnimCodecPlayer_DEFINED + +#include "SkCodec.h" + +class SkImage; + +class SkAnimCodecPlayer { +public: + SkAnimCodecPlayer(std::unique_ptr<SkCodec> codec); + ~SkAnimCodecPlayer(); + + /** + * Returns the current frame of the animation. This defaults to the first frame for + * animated codecs (i.e. msec = 0). Calling this multiple times (without calling seek()) + * will always return the same image object (or null if there was an error). + */ + sk_sp<SkImage> getFrame(); + + /** + * Return the size of the image(s) that will be returned by getFrame(). + */ + SkISize dimensions(); + + /** + * Returns the total duration of the animation in milliseconds. Returns 0 for a single-frame + * image. + */ + uint32_t duration() { return fTotalDuration; } + + /** + * Finds the closest frame associated with the time code (in milliseconds) and sets that + * to be the current frame (call getFrame() to retrieve that image). + * Returns true iff this call to seek() changed the "current frame" for the animation. + * Thus if seek() returns false, then getFrame() will return the same image as it did + * before this call to seek(). + */ + bool seek(uint32_t msec); + + +private: + std::unique_ptr<SkCodec> fCodec; + SkImageInfo fImageInfo; + std::vector<SkCodec::FrameInfo> fFrameInfos; + std::vector<sk_sp<SkImage> > fImages; + int fCurrIndex = 0; + uint32_t fTotalDuration; + + sk_sp<SkImage> getFrameAt(int index); +}; + +#endif + diff --git a/src/utils/SkAnimCodecPlayer.cpp b/src/utils/SkAnimCodecPlayer.cpp new file mode 100644 index 0000000000..0a9bbc0171 --- /dev/null +++ b/src/utils/SkAnimCodecPlayer.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkAnimCodecPlayer.h" +#include "SkCodec.h" +#include "SkData.h" +#include "SkImage.h" +#include <algorithm> + +SkAnimCodecPlayer::SkAnimCodecPlayer(std::unique_ptr<SkCodec> codec) : fCodec(std::move(codec)) { + fImageInfo = fCodec->getInfo(); + fFrameInfos = fCodec->getFrameInfo(); + fImages.resize(fFrameInfos.size()); + + // change the interpretation of fDuration to a end-time for that frame + size_t dur = 0; + for (auto& f : fFrameInfos) { + dur += f.fDuration; + f.fDuration = dur; + } + fTotalDuration = dur; +} + +SkAnimCodecPlayer::~SkAnimCodecPlayer() {} + +SkISize SkAnimCodecPlayer::dimensions() { + return { fImageInfo.width(), fImageInfo.height() }; +} + +sk_sp<SkImage> SkAnimCodecPlayer::getFrameAt(int index) { + SkASSERT((unsigned)index < fFrameInfos.size()); + + if (fImages[index]) { + return fImages[index]; + } + + size_t rb = fImageInfo.minRowBytes(); + size_t size = fImageInfo.computeByteSize(rb); + auto data = SkData::MakeUninitialized(size); + + SkCodec::Options opts; + opts.fFrameIndex = index; + + const int requiredFrame = fFrameInfos[index].fRequiredFrame; + if (requiredFrame != SkCodec::kNoFrame) { + auto requiredImage = fImages[requiredFrame]; + SkPixmap requiredPM; + if (requiredImage && requiredImage->peekPixels(&requiredPM)) { + sk_careful_memcpy(data->writable_data(), requiredPM.addr(), size); + opts.fPriorFrame = requiredFrame; + } + } + if (SkCodec::kSuccess == fCodec->getPixels(fImageInfo, data->writable_data(), rb, &opts)) { + return fImages[index] = SkImage::MakeRasterData(fImageInfo, std::move(data), rb); + } + return nullptr; +} + +sk_sp<SkImage> SkAnimCodecPlayer::getFrame() { + return this->getFrameAt(fCurrIndex); +} + +bool SkAnimCodecPlayer::seek(uint32_t msec) { + msec %= fTotalDuration; + + auto lower = std::lower_bound(fFrameInfos.begin(), fFrameInfos.end(), msec, + [](const SkCodec::FrameInfo& info, uint32_t msec) { + return (uint32_t)info.fDuration < msec; + }); + int prevIndex = fCurrIndex; + fCurrIndex = lower - fFrameInfos.begin(); + return fCurrIndex != prevIndex; +} + + |