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