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