1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/codec/SkCodec.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkData.h"
11cb93a386Sopenharmony_ci#include "include/core/SkImage.h"
12cb93a386Sopenharmony_ci#include "include/utils/SkAnimCodecPlayer.h"
13cb93a386Sopenharmony_ci#include "src/codec/SkCodecImageGenerator.h"
14cb93a386Sopenharmony_ci#include "src/core/SkPixmapPriv.h"
15cb93a386Sopenharmony_ci#include <algorithm>
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ciSkAnimCodecPlayer::SkAnimCodecPlayer(std::unique_ptr<SkCodec> codec) : fCodec(std::move(codec)) {
18cb93a386Sopenharmony_ci    fImageInfo = fCodec->getInfo();
19cb93a386Sopenharmony_ci    fFrameInfos = fCodec->getFrameInfo();
20cb93a386Sopenharmony_ci    fImages.resize(fFrameInfos.size());
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci    // change the interpretation of fDuration to a end-time for that frame
23cb93a386Sopenharmony_ci    size_t dur = 0;
24cb93a386Sopenharmony_ci    for (auto& f : fFrameInfos) {
25cb93a386Sopenharmony_ci        dur += f.fDuration;
26cb93a386Sopenharmony_ci        f.fDuration = dur;
27cb93a386Sopenharmony_ci    }
28cb93a386Sopenharmony_ci    fTotalDuration = dur;
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci    if (!fTotalDuration) {
31cb93a386Sopenharmony_ci        // Static image -- may or may not have returned a single frame info.
32cb93a386Sopenharmony_ci        fFrameInfos.clear();
33cb93a386Sopenharmony_ci        fImages.clear();
34cb93a386Sopenharmony_ci        fImages.push_back(SkImage::MakeFromGenerator(
35cb93a386Sopenharmony_ci                              SkCodecImageGenerator::MakeFromCodec(std::move(fCodec))));
36cb93a386Sopenharmony_ci    }
37cb93a386Sopenharmony_ci}
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ciSkAnimCodecPlayer::~SkAnimCodecPlayer() {}
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ciSkISize SkAnimCodecPlayer::dimensions() const {
42cb93a386Sopenharmony_ci    if (!fCodec) {
43cb93a386Sopenharmony_ci        auto image = fImages.front();
44cb93a386Sopenharmony_ci        return image ? image->dimensions() : SkISize::MakeEmpty();
45cb93a386Sopenharmony_ci    }
46cb93a386Sopenharmony_ci    if (SkEncodedOriginSwapsWidthHeight(fCodec->getOrigin())) {
47cb93a386Sopenharmony_ci        return { fImageInfo.height(), fImageInfo.width() };
48cb93a386Sopenharmony_ci    }
49cb93a386Sopenharmony_ci    return { fImageInfo.width(), fImageInfo.height() };
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_cisk_sp<SkImage> SkAnimCodecPlayer::getFrameAt(int index) {
53cb93a386Sopenharmony_ci    SkASSERT((unsigned)index < fFrameInfos.size());
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci    if (fImages[index]) {
56cb93a386Sopenharmony_ci        return fImages[index];
57cb93a386Sopenharmony_ci    }
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci    size_t rb = fImageInfo.minRowBytes();
60cb93a386Sopenharmony_ci    size_t size = fImageInfo.computeByteSize(rb);
61cb93a386Sopenharmony_ci    auto data = SkData::MakeUninitialized(size);
62cb93a386Sopenharmony_ci
63cb93a386Sopenharmony_ci    SkCodec::Options opts;
64cb93a386Sopenharmony_ci    opts.fFrameIndex = index;
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_ci    const auto origin = fCodec->getOrigin();
67cb93a386Sopenharmony_ci    const auto orientedDims = this->dimensions();
68cb93a386Sopenharmony_ci    const auto originMatrix = SkEncodedOriginToMatrix(origin, orientedDims.width(),
69cb93a386Sopenharmony_ci                                                              orientedDims.height());
70cb93a386Sopenharmony_ci
71cb93a386Sopenharmony_ci    SkPaint paint;
72cb93a386Sopenharmony_ci    paint.setBlendMode(SkBlendMode::kSrc);
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci    auto imageInfo = fImageInfo;
75cb93a386Sopenharmony_ci    if (fFrameInfos[index].fAlphaType != kOpaque_SkAlphaType && imageInfo.isOpaque()) {
76cb93a386Sopenharmony_ci        imageInfo = imageInfo.makeAlphaType(kPremul_SkAlphaType);
77cb93a386Sopenharmony_ci    }
78cb93a386Sopenharmony_ci    const int requiredFrame = fFrameInfos[index].fRequiredFrame;
79cb93a386Sopenharmony_ci    if (requiredFrame != SkCodec::kNoFrame && fImages[requiredFrame]) {
80cb93a386Sopenharmony_ci        auto requiredImage = fImages[requiredFrame];
81cb93a386Sopenharmony_ci        auto canvas = SkCanvas::MakeRasterDirect(imageInfo, data->writable_data(), rb);
82cb93a386Sopenharmony_ci        if (origin != kDefault_SkEncodedOrigin) {
83cb93a386Sopenharmony_ci            // The required frame is stored after applying the origin. Undo that,
84cb93a386Sopenharmony_ci            // because the codec decodes prior to applying the origin.
85cb93a386Sopenharmony_ci            // FIXME: Another approach would be to decode the frame's delta on top
86cb93a386Sopenharmony_ci            // of transparent black, and then draw that through the origin matrix
87cb93a386Sopenharmony_ci            // onto the required frame. To do that, SkCodec needs to expose the
88cb93a386Sopenharmony_ci            // rectangle of the delta and the blend mode, so we can handle
89cb93a386Sopenharmony_ci            // kRestoreBGColor frames and Blend::kSrc.
90cb93a386Sopenharmony_ci            SkMatrix inverse;
91cb93a386Sopenharmony_ci            SkAssertResult(originMatrix.invert(&inverse));
92cb93a386Sopenharmony_ci            canvas->concat(inverse);
93cb93a386Sopenharmony_ci        }
94cb93a386Sopenharmony_ci        canvas->drawImage(requiredImage, 0, 0, SkSamplingOptions(), &paint);
95cb93a386Sopenharmony_ci        opts.fPriorFrame = requiredFrame;
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    if (SkCodec::kSuccess != fCodec->getPixels(imageInfo, data->writable_data(), rb, &opts)) {
99cb93a386Sopenharmony_ci        return nullptr;
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci    auto image = SkImage::MakeRasterData(imageInfo, std::move(data), rb);
103cb93a386Sopenharmony_ci    if (origin != kDefault_SkEncodedOrigin) {
104cb93a386Sopenharmony_ci        imageInfo = imageInfo.makeDimensions(orientedDims);
105cb93a386Sopenharmony_ci        rb = imageInfo.minRowBytes();
106cb93a386Sopenharmony_ci        size = imageInfo.computeByteSize(rb);
107cb93a386Sopenharmony_ci        data = SkData::MakeUninitialized(size);
108cb93a386Sopenharmony_ci        auto canvas = SkCanvas::MakeRasterDirect(imageInfo, data->writable_data(), rb);
109cb93a386Sopenharmony_ci        canvas->concat(originMatrix);
110cb93a386Sopenharmony_ci        canvas->drawImage(image, 0, 0, SkSamplingOptions(), &paint);
111cb93a386Sopenharmony_ci        image = SkImage::MakeRasterData(imageInfo, std::move(data), rb);
112cb93a386Sopenharmony_ci    }
113cb93a386Sopenharmony_ci    return fImages[index] = image;
114cb93a386Sopenharmony_ci}
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_cisk_sp<SkImage> SkAnimCodecPlayer::getFrame() {
117cb93a386Sopenharmony_ci    SkASSERT(fTotalDuration > 0 || fImages.size() == 1);
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    return fTotalDuration > 0
120cb93a386Sopenharmony_ci        ? this->getFrameAt(fCurrIndex)
121cb93a386Sopenharmony_ci        : fImages.front();
122cb93a386Sopenharmony_ci}
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_cibool SkAnimCodecPlayer::seek(uint32_t msec) {
125cb93a386Sopenharmony_ci    if (!fTotalDuration) {
126cb93a386Sopenharmony_ci        return false;
127cb93a386Sopenharmony_ci    }
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci    msec %= fTotalDuration;
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci    auto lower = std::lower_bound(fFrameInfos.begin(), fFrameInfos.end(), msec,
132cb93a386Sopenharmony_ci                                  [](const SkCodec::FrameInfo& info, uint32_t msec) {
133cb93a386Sopenharmony_ci                                      return (uint32_t)info.fDuration <= msec;
134cb93a386Sopenharmony_ci                                  });
135cb93a386Sopenharmony_ci    int prevIndex = fCurrIndex;
136cb93a386Sopenharmony_ci    fCurrIndex = lower - fFrameInfos.begin();
137cb93a386Sopenharmony_ci    return fCurrIndex != prevIndex;
138cb93a386Sopenharmony_ci}
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci
141