• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 "src/codec/SkAvifCodec.h"
9 
10 #include "include/codec/SkCodec.h"
11 #include "include/codec/SkCodecAnimation.h"
12 #include "include/core/SkColorType.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkSize.h"
15 #include "include/core/SkStream.h"
16 #include "include/core/SkTypes.h"
17 #include "modules/skcms/skcms.h"
18 #include "src/core/SkStreamPriv.h"
19 
20 #include <cstdint>
21 #include <cstring>
22 #include <utility>
23 
24 #include "avif/avif.h"
25 #include "avif/internal.h"
26 
operator ()(avifDecoder * decoder) const27 void AvifDecoderDeleter::operator()(avifDecoder* decoder) const {
28     if (decoder != nullptr) {
29         avifDecoderDestroy(decoder);
30     }
31 }
32 
IsAvif(const void * buffer,size_t bytesRead)33 bool SkAvifCodec::IsAvif(const void* buffer, size_t bytesRead) {
34     avifROData avifData = {static_cast<const uint8_t*>(buffer), bytesRead};
35     bool isAvif = avifPeekCompatibleFileType(&avifData) == AVIF_TRUE;
36     if (isAvif) return true;
37     // Peeking sometimes fails if the ftyp box is too large. Check the signature
38     // just to be sure.
39     const char* bytes = static_cast<const char*>(buffer);
40     isAvif = bytesRead >= 12 && !memcmp(&bytes[4], "ftyp", 4) &&
41              (!memcmp(&bytes[8], "avif", 4) || !memcmp(&bytes[8], "avis", 4));
42     return isAvif;
43 }
44 
MakeFromStream(std::unique_ptr<SkStream> stream,Result * result)45 std::unique_ptr<SkCodec> SkAvifCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
46                                                      Result* result) {
47     AvifDecoder avifDecoder(avifDecoderCreate());
48     if (avifDecoder == nullptr) {
49         *result = kInternalError;
50         return nullptr;
51     }
52     avifDecoder->ignoreXMP = AVIF_TRUE;
53     avifDecoder->ignoreExif = AVIF_TRUE;
54     avifDecoder->allowProgressive = AVIF_FALSE;
55     avifDecoder->allowIncremental = AVIF_FALSE;
56     avifDecoder->strictFlags = AVIF_STRICT_DISABLED;
57     // TODO(vigneshv): Enable threading based on number of CPU cores available.
58     avifDecoder->maxThreads = 1;
59 
60     // libavif needs a contiguous data buffer.
61     sk_sp<SkData> data = nullptr;
62     if (stream->getMemoryBase()) {
63         // It is safe to make without copy because we'll hold onto the stream.
64         data = SkData::MakeWithoutCopy(stream->getMemoryBase(), stream->getLength());
65     } else {
66         data = SkCopyStreamToData(stream.get());
67         // If we are forced to copy the stream to a data, we can go ahead and
68         // delete the stream.
69         stream.reset(nullptr);
70     }
71 
72     avifResult res = avifDecoderSetIOMemory(avifDecoder.get(), data->bytes(), data->size());
73     if (res != AVIF_RESULT_OK) {
74         *result = kInternalError;
75         return nullptr;
76     }
77 
78     res = avifDecoderParse(avifDecoder.get());
79     if (res != AVIF_RESULT_OK) {
80         *result = kInvalidInput;
81         return nullptr;
82     }
83 
84     std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
85     // TODO(vigneshv): Get ICC Profile from the avif decoder.
86 
87     const int bitsPerComponent = avifDecoder->image->depth > 8 ? 16 : 8;
88     SkEncodedInfo::Color color;
89     SkEncodedInfo::Alpha alpha;
90     if (avifDecoder->alphaPresent) {
91         color = SkEncodedInfo::kRGBA_Color;
92         alpha = SkEncodedInfo::kUnpremul_Alpha;
93     } else {
94         color = SkEncodedInfo::kRGB_Color;
95         alpha = SkEncodedInfo::kOpaque_Alpha;
96     }
97     SkEncodedInfo info = SkEncodedInfo::Make(avifDecoder->image->width,
98                                              avifDecoder->image->height,
99                                              color,
100                                              alpha,
101                                              bitsPerComponent,
102                                              std::move(profile),
103                                              avifDecoder->image->depth);
104     bool animation = avifDecoder->imageCount > 1;
105     *result = kSuccess;
106     return std::unique_ptr<SkCodec>(new SkAvifCodec(std::move(info),
107                                                     std::move(stream),
108                                                     std::move(data),
109                                                     std::move(avifDecoder),
110                                                     kDefault_SkEncodedOrigin,
111                                                     animation));
112 }
113 
SkAvifCodec(SkEncodedInfo && info,std::unique_ptr<SkStream> stream,sk_sp<SkData> data,AvifDecoder avifDecoder,SkEncodedOrigin origin,bool useAnimation)114 SkAvifCodec::SkAvifCodec(SkEncodedInfo&& info,
115                          std::unique_ptr<SkStream> stream,
116                          sk_sp<SkData> data,
117                          AvifDecoder avifDecoder,
118                          SkEncodedOrigin origin,
119                          bool useAnimation)
120         : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream), origin)
121         , fData(std::move(data))
122         , fAvifDecoder(std::move(avifDecoder))
123         , fUseAnimation(useAnimation) {}
124 
onGetFrameCount()125 int SkAvifCodec::onGetFrameCount() {
126     if (!fUseAnimation) {
127         return 1;
128     }
129 
130     if (fFrameHolder.size() == 0) {
131         if (fAvifDecoder->imageCount <= 1) {
132             fUseAnimation = false;
133             return 1;
134         }
135         fFrameHolder.reserve(fAvifDecoder->imageCount);
136         for (int i = 0; i < fAvifDecoder->imageCount; i++) {
137             Frame* frame = fFrameHolder.appendNewFrame(fAvifDecoder->alphaPresent == AVIF_TRUE);
138             frame->setXYWH(0, 0, fAvifDecoder->image->width, fAvifDecoder->image->height);
139             frame->setDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep);
140             avifImageTiming timing;
141             avifDecoderNthImageTiming(fAvifDecoder.get(), i, &timing);
142             frame->setDuration(timing.duration * 1000);
143             frame->setRequiredFrame(SkCodec::kNoFrame);
144             frame->setHasAlpha(fAvifDecoder->alphaPresent == AVIF_TRUE);
145         }
146     }
147 
148     return fFrameHolder.size();
149 }
150 
onGetFrame(int i) const151 const SkFrame* SkAvifCodec::FrameHolder::onGetFrame(int i) const {
152     return static_cast<const SkFrame*>(this->frame(i));
153 }
154 
appendNewFrame(bool hasAlpha)155 SkAvifCodec::Frame* SkAvifCodec::FrameHolder::appendNewFrame(bool hasAlpha) {
156     const int i = this->size();
157     fFrames.emplace_back(i,
158                          hasAlpha ? SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha);
159     return &fFrames[i];
160 }
161 
frame(int i) const162 const SkAvifCodec::Frame* SkAvifCodec::FrameHolder::frame(int i) const {
163     SkASSERT(i >= 0 && i < this->size());
164     return &fFrames[i];
165 }
166 
onGetFrameInfo(int i,FrameInfo * frameInfo) const167 bool SkAvifCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const {
168     if (i >= fFrameHolder.size()) {
169         return false;
170     }
171 
172     const Frame* frame = fFrameHolder.frame(i);
173     if (!frame) {
174         return false;
175     }
176 
177     if (frameInfo) {
178         frame->fillIn(frameInfo, true);
179     }
180 
181     return true;
182 }
183 
onGetRepetitionCount()184 int SkAvifCodec::onGetRepetitionCount() { return kRepetitionCountInfinite; }
185 
onGetPixels(const SkImageInfo & dstInfo,void * dst,size_t dstRowBytes,const Options & options,int * rowsDecoded)186 SkCodec::Result SkAvifCodec::onGetPixels(const SkImageInfo& dstInfo,
187                                          void* dst,
188                                          size_t dstRowBytes,
189                                          const Options& options,
190                                          int* rowsDecoded) {
191     if (options.fSubset) {
192         return kUnimplemented;
193     }
194 
195     const SkColorType dstColorType = dstInfo.colorType();
196     if (dstColorType != kRGBA_8888_SkColorType && dstColorType != kRGBA_F16_SkColorType) {
197         // TODO(vigneshv): Check if more color types need to be supported.
198         // Currently android supports at least RGB565 and BGRA8888 which is not
199         // supported here.
200         return kUnimplemented;
201     }
202 
203     avifResult result = avifDecoderNthImage(fAvifDecoder.get(), options.fFrameIndex);
204     if (result != AVIF_RESULT_OK) {
205         return kInvalidInput;
206     }
207 
208     if (this->dimensions() != dstInfo.dimensions()) {
209         if (!avifImageScale(fAvifDecoder->image,
210                             dstInfo.width(),
211                             dstInfo.height(),
212                             fAvifDecoder->imageSizeLimit,
213                             &fAvifDecoder->diag)) {
214             return kInvalidInput;
215         }
216     }
217 
218     avifRGBImage rgbImage;
219     avifRGBImageSetDefaults(&rgbImage, fAvifDecoder->image);
220 
221     if (dstColorType == kRGBA_8888_SkColorType) {
222         rgbImage.depth = 8;
223     } else if (dstColorType == kRGBA_F16_SkColorType) {
224         rgbImage.depth = 16;
225         rgbImage.isFloat = AVIF_TRUE;
226     }
227 
228     rgbImage.pixels = static_cast<uint8_t*>(dst);
229     rgbImage.rowBytes = dstRowBytes;
230     rgbImage.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST;
231 
232     result = avifImageYUVToRGB(fAvifDecoder->image, &rgbImage);
233     if (result != AVIF_RESULT_OK) {
234         return kInvalidInput;
235     }
236 
237     *rowsDecoded = fAvifDecoder->image->height;
238     return kSuccess;
239 }
240