aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Reed <reed@google.com>2018-10-03 10:16:55 -0400
committerSkia Commit-Bot <skia-commit-bot@chromium.org>2018-10-03 14:43:18 +0000
commit964aedb5e3ffcf814ccbb37adf2a9a02c7235b3c (patch)
treee91ad29ef8b5c4cf101c7e8e549a77842227d6e1
parent3093a17128192b1b058ac67b796cbb0afaca1c9f (diff)
downloadskqp-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.cpp58
-rw-r--r--gn/utils.gni2
-rw-r--r--include/utils/SkAnimCodecPlayer.h60
-rw-r--r--src/utils/SkAnimCodecPlayer.cpp79
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;
+}
+
+