1/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "include/codec/SkCodec.h"
9#include "include/core/SkData.h"
10#include "include/core/SkImage.h"
11#include "include/utils/SkAnimCodecPlayer.h"
12#include "src/codec/SkCodecImageGenerator.h"
13#include <algorithm>
14
15SkAnimCodecPlayer::SkAnimCodecPlayer(std::unique_ptr<SkCodec> codec) : fCodec(std::move(codec)) {
16 fImageInfo = fCodec->getInfo();
17 fFrameInfos = fCodec->getFrameInfo();
18 fImages.resize(fFrameInfos.size());
19
20 // change the interpretation of fDuration to a end-time for that frame
21 size_t dur = 0;
22 for (auto& f : fFrameInfos) {
23 dur += f.fDuration;
24 f.fDuration = dur;
25 }
26 fTotalDuration = dur;
27
28 if (!fTotalDuration) {
29 // Static image -- may or may not have returned a single frame info.
30 fFrameInfos.clear();
31 fImages.clear();
32 fImages.push_back(SkImage::MakeFromGenerator(
33 SkCodecImageGenerator::MakeFromCodec(std::move(fCodec))));
34 }
35}
36
37SkAnimCodecPlayer::~SkAnimCodecPlayer() {}
38
39SkISize SkAnimCodecPlayer::dimensions() {
40 return { fImageInfo.width(), fImageInfo.height() };
41}
42
43sk_sp<SkImage> SkAnimCodecPlayer::getFrameAt(int index) {
44 SkASSERT((unsigned)index < fFrameInfos.size());
45
46 if (fImages[index]) {
47 return fImages[index];
48 }
49
50 size_t rb = fImageInfo.minRowBytes();
51 size_t size = fImageInfo.computeByteSize(rb);
52 auto data = SkData::MakeUninitialized(size);
53
54 SkCodec::Options opts;
55 opts.fFrameIndex = index;
56
57 const int requiredFrame = fFrameInfos[index].fRequiredFrame;
58 if (requiredFrame != SkCodec::kNoFrame) {
59 auto requiredImage = fImages[requiredFrame];
60 SkPixmap requiredPM;
61 if (requiredImage && requiredImage->peekPixels(&requiredPM)) {
62 sk_careful_memcpy(data->writable_data(), requiredPM.addr(), size);
63 opts.fPriorFrame = requiredFrame;
64 }
65 }
66 if (SkCodec::kSuccess == fCodec->getPixels(fImageInfo, data->writable_data(), rb, &opts)) {
67 return fImages[index] = SkImage::MakeRasterData(fImageInfo, std::move(data), rb);
68 }
69 return nullptr;
70}
71
72sk_sp<SkImage> SkAnimCodecPlayer::getFrame() {
73 SkASSERT(fTotalDuration > 0 || fImages.size() == 1);
74
75 return fTotalDuration > 0
76 ? this->getFrameAt(fCurrIndex)
77 : fImages.front();
78}
79
80bool SkAnimCodecPlayer::seek(uint32_t msec) {
81 if (!fTotalDuration) {
82 return false;
83 }
84
85 msec %= fTotalDuration;
86
87 auto lower = std::lower_bound(fFrameInfos.begin(), fFrameInfos.end(), msec,
88 [](const SkCodec::FrameInfo& info, uint32_t msec) {
89 return (uint32_t)info.fDuration < msec;
90 });
91 int prevIndex = fCurrIndex;
92 fCurrIndex = lower - fFrameInfos.begin();
93 return fCurrIndex != prevIndex;
94}
95
96
97