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/SkAvifDecoder.h"
11 #include "include/codec/SkCodec.h"
12 #include "include/codec/SkCodecAnimation.h"
13 #include "include/core/SkColorType.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkSize.h"
16 #include "include/core/SkStream.h"
17 #include "include/core/SkTypes.h"
18 #include "modules/skcms/skcms.h"
19 #include "src/core/SkStreamPriv.h"
20
21 #include <cstdint>
22 #include <cstring>
23 #include <utility>
24
25 #include "avif/avif.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 SkASSERT(result);
48 if (!stream) {
49 *result = SkCodec::kInvalidInput;
50 return nullptr;
51 }
52 AvifDecoder avifDecoder(avifDecoderCreate());
53 if (avifDecoder == nullptr) {
54 *result = SkCodec::kInternalError;
55 return nullptr;
56 }
57 avifDecoder->ignoreXMP = AVIF_TRUE;
58 avifDecoder->ignoreExif = AVIF_TRUE;
59 avifDecoder->allowProgressive = AVIF_FALSE;
60 avifDecoder->allowIncremental = AVIF_FALSE;
61 avifDecoder->strictFlags = AVIF_STRICT_DISABLED;
62 // TODO(vigneshv): Enable threading based on number of CPU cores available.
63 avifDecoder->maxThreads = 1;
64
65 // libavif needs a contiguous data buffer.
66 sk_sp<SkData> data = nullptr;
67 if (stream->getMemoryBase()) {
68 // It is safe to make without copy because we'll hold onto the stream.
69 data = SkData::MakeWithoutCopy(stream->getMemoryBase(), stream->getLength());
70 } else {
71 data = SkCopyStreamToData(stream.get());
72 // If we are forced to copy the stream to a data, we can go ahead and
73 // delete the stream.
74 stream.reset(nullptr);
75 }
76
77 avifResult res = avifDecoderSetIOMemory(avifDecoder.get(), data->bytes(), data->size());
78 if (res != AVIF_RESULT_OK) {
79 *result = SkCodec::kInternalError;
80 return nullptr;
81 }
82
83 res = avifDecoderParse(avifDecoder.get());
84 if (res != AVIF_RESULT_OK) {
85 *result = SkCodec::kInvalidInput;
86 return nullptr;
87 }
88
89 std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
90 // TODO(vigneshv): Get ICC Profile from the avif decoder.
91
92 const int bitsPerComponent = avifDecoder->image->depth > 8 ? 16 : 8;
93 SkEncodedInfo::Color color;
94 SkEncodedInfo::Alpha alpha;
95 if (avifDecoder->alphaPresent) {
96 color = SkEncodedInfo::kRGBA_Color;
97 alpha = SkEncodedInfo::kUnpremul_Alpha;
98 } else {
99 color = SkEncodedInfo::kRGB_Color;
100 alpha = SkEncodedInfo::kOpaque_Alpha;
101 }
102 SkEncodedInfo info = SkEncodedInfo::Make(avifDecoder->image->width,
103 avifDecoder->image->height,
104 color,
105 alpha,
106 bitsPerComponent,
107 std::move(profile),
108 avifDecoder->image->depth);
109 bool animation = avifDecoder->imageCount > 1;
110 *result = kSuccess;
111 return std::unique_ptr<SkCodec>(new SkAvifCodec(std::move(info),
112 std::move(stream),
113 std::move(data),
114 std::move(avifDecoder),
115 kDefault_SkEncodedOrigin,
116 animation));
117 }
118
SkAvifCodec(SkEncodedInfo && info,std::unique_ptr<SkStream> stream,sk_sp<SkData> data,AvifDecoder avifDecoder,SkEncodedOrigin origin,bool useAnimation)119 SkAvifCodec::SkAvifCodec(SkEncodedInfo&& info,
120 std::unique_ptr<SkStream> stream,
121 sk_sp<SkData> data,
122 AvifDecoder avifDecoder,
123 SkEncodedOrigin origin,
124 bool useAnimation)
125 : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream), origin)
126 , fData(std::move(data))
127 , fAvifDecoder(std::move(avifDecoder))
128 , fUseAnimation(useAnimation) {}
129
onGetFrameCount()130 int SkAvifCodec::onGetFrameCount() {
131 if (!fUseAnimation) {
132 return 1;
133 }
134
135 if (fFrameHolder.size() == 0) {
136 if (fAvifDecoder->imageCount <= 1) {
137 fUseAnimation = false;
138 return 1;
139 }
140 fFrameHolder.reserve(fAvifDecoder->imageCount);
141 for (int i = 0; i < fAvifDecoder->imageCount; i++) {
142 Frame* frame = fFrameHolder.appendNewFrame(fAvifDecoder->alphaPresent == AVIF_TRUE);
143 frame->setXYWH(0, 0, fAvifDecoder->image->width, fAvifDecoder->image->height);
144 frame->setDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep);
145 avifImageTiming timing;
146 avifDecoderNthImageTiming(fAvifDecoder.get(), i, &timing);
147 frame->setDuration(timing.duration * 1000);
148 frame->setRequiredFrame(SkCodec::kNoFrame);
149 frame->setHasAlpha(fAvifDecoder->alphaPresent == AVIF_TRUE);
150 }
151 }
152
153 return fFrameHolder.size();
154 }
155
onGetFrame(int i) const156 const SkFrame* SkAvifCodec::FrameHolder::onGetFrame(int i) const {
157 return static_cast<const SkFrame*>(this->frame(i));
158 }
159
appendNewFrame(bool hasAlpha)160 SkAvifCodec::Frame* SkAvifCodec::FrameHolder::appendNewFrame(bool hasAlpha) {
161 const int i = this->size();
162 fFrames.emplace_back(i,
163 hasAlpha ? SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha);
164 return &fFrames[i];
165 }
166
frame(int i) const167 const SkAvifCodec::Frame* SkAvifCodec::FrameHolder::frame(int i) const {
168 SkASSERT(i >= 0 && i < this->size());
169 return &fFrames[i];
170 }
171
onGetFrameInfo(int i,FrameInfo * frameInfo) const172 bool SkAvifCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const {
173 if (i >= fFrameHolder.size()) {
174 return false;
175 }
176
177 const Frame* frame = fFrameHolder.frame(i);
178 if (!frame) {
179 return false;
180 }
181
182 if (frameInfo) {
183 frame->fillIn(frameInfo, true);
184 }
185
186 return true;
187 }
188
onGetRepetitionCount()189 int SkAvifCodec::onGetRepetitionCount() { return kRepetitionCountInfinite; }
190
onIsAnimated()191 SkCodec::IsAnimated SkAvifCodec::onIsAnimated() {
192 if (!fUseAnimation || fAvifDecoder->imageCount <= 1) {
193 return IsAnimated::kNo;
194 }
195 return IsAnimated::kYes;
196 }
197
onGetPixels(const SkImageInfo & dstInfo,void * dst,size_t dstRowBytes,const Options & options,int * rowsDecoded)198 SkCodec::Result SkAvifCodec::onGetPixels(const SkImageInfo& dstInfo,
199 void* dst,
200 size_t dstRowBytes,
201 const Options& options,
202 int* rowsDecoded) {
203 if (options.fSubset) {
204 return kUnimplemented;
205 }
206
207 const SkColorType dstColorType = dstInfo.colorType();
208 if (dstColorType != kRGBA_8888_SkColorType && dstColorType != kRGBA_F16_SkColorType) {
209 // TODO(vigneshv): Check if more color types need to be supported.
210 // Currently android supports at least RGB565 and BGRA8888 which is not
211 // supported here.
212 return kUnimplemented;
213 }
214
215 avifResult result = avifDecoderNthImage(fAvifDecoder.get(), options.fFrameIndex);
216 if (result != AVIF_RESULT_OK) {
217 return kInvalidInput;
218 }
219
220 if (this->dimensions() != dstInfo.dimensions()) {
221 result = avifImageScale(
222 fAvifDecoder->image, dstInfo.width(), dstInfo.height(), &fAvifDecoder->diag);
223 if (result != AVIF_RESULT_OK) {
224 return kInvalidInput;
225 }
226 }
227
228 avifRGBImage rgbImage;
229 avifRGBImageSetDefaults(&rgbImage, fAvifDecoder->image);
230
231 if (dstColorType == kRGBA_8888_SkColorType) {
232 rgbImage.depth = 8;
233 } else if (dstColorType == kRGBA_F16_SkColorType) {
234 rgbImage.depth = 16;
235 rgbImage.isFloat = AVIF_TRUE;
236 }
237
238 rgbImage.pixels = static_cast<uint8_t*>(dst);
239 rgbImage.rowBytes = dstRowBytes;
240 rgbImage.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST;
241
242 result = avifImageYUVToRGB(fAvifDecoder->image, &rgbImage);
243 if (result != AVIF_RESULT_OK) {
244 return kInvalidInput;
245 }
246
247 *rowsDecoded = fAvifDecoder->image->height;
248 return kSuccess;
249 }
250
251 namespace SkAvifDecoder {
252 namespace LibAvif {
253
IsAvif(const void * data,size_t len)254 bool IsAvif(const void* data, size_t len) {
255 return SkAvifCodec::IsAvif(data, len);
256 }
257
Decode(std::unique_ptr<SkStream> stream,SkCodec::Result * outResult,SkCodecs::DecodeContext)258 std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream> stream,
259 SkCodec::Result* outResult,
260 SkCodecs::DecodeContext) {
261 SkCodec::Result resultStorage;
262 if (!outResult) {
263 outResult = &resultStorage;
264 }
265 return SkAvifCodec::MakeFromStream(std::move(stream), outResult);
266 }
267
Decode(sk_sp<SkData> data,SkCodec::Result * outResult,SkCodecs::DecodeContext)268 std::unique_ptr<SkCodec> Decode(sk_sp<SkData> data,
269 SkCodec::Result* outResult,
270 SkCodecs::DecodeContext) {
271 if (!data) {
272 if (outResult) {
273 *outResult = SkCodec::kInvalidInput;
274 }
275 return nullptr;
276 }
277 return Decode(SkMemoryStream::Make(std::move(data)), outResult, nullptr);
278 }
279
280 } // namespace LibAvif
281 } // namespace SkAvifDecoder
282