xref: /aosp_15_r20/external/skia/src/codec/SkAvifCodec.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
onGetPixels(const SkImageInfo & dstInfo,void * dst,size_t dstRowBytes,const Options & options,int * rowsDecoded)191 SkCodec::Result SkAvifCodec::onGetPixels(const SkImageInfo& dstInfo,
192                                          void* dst,
193                                          size_t dstRowBytes,
194                                          const Options& options,
195                                          int* rowsDecoded) {
196     if (options.fSubset) {
197         return kUnimplemented;
198     }
199 
200     const SkColorType dstColorType = dstInfo.colorType();
201     if (dstColorType != kRGBA_8888_SkColorType && dstColorType != kRGBA_F16_SkColorType) {
202         // TODO(vigneshv): Check if more color types need to be supported.
203         // Currently android supports at least RGB565 and BGRA8888 which is not
204         // supported here.
205         return kUnimplemented;
206     }
207 
208     avifResult result = avifDecoderNthImage(fAvifDecoder.get(), options.fFrameIndex);
209     if (result != AVIF_RESULT_OK) {
210         return kInvalidInput;
211     }
212 
213     if (this->dimensions() != dstInfo.dimensions()) {
214         result = avifImageScale(
215                 fAvifDecoder->image, dstInfo.width(), dstInfo.height(), &fAvifDecoder->diag);
216         if (result != AVIF_RESULT_OK) {
217             return kInvalidInput;
218         }
219     }
220 
221     avifRGBImage rgbImage;
222     avifRGBImageSetDefaults(&rgbImage, fAvifDecoder->image);
223 
224     if (dstColorType == kRGBA_8888_SkColorType) {
225         rgbImage.depth = 8;
226     } else if (dstColorType == kRGBA_F16_SkColorType) {
227         rgbImage.depth = 16;
228         rgbImage.isFloat = AVIF_TRUE;
229     }
230 
231     rgbImage.pixels = static_cast<uint8_t*>(dst);
232     rgbImage.rowBytes = dstRowBytes;
233     rgbImage.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST;
234 
235     result = avifImageYUVToRGB(fAvifDecoder->image, &rgbImage);
236     if (result != AVIF_RESULT_OK) {
237         return kInvalidInput;
238     }
239 
240     *rowsDecoded = fAvifDecoder->image->height;
241     return kSuccess;
242 }
243 
244 namespace SkAvifDecoder {
245 namespace LibAvif {
246 
IsAvif(const void * data,size_t len)247 bool IsAvif(const void* data, size_t len) {
248     return SkAvifCodec::IsAvif(data, len);
249 }
250 
Decode(std::unique_ptr<SkStream> stream,SkCodec::Result * outResult,SkCodecs::DecodeContext)251 std::unique_ptr<SkCodec> Decode(std::unique_ptr<SkStream> stream,
252                                 SkCodec::Result* outResult,
253                                 SkCodecs::DecodeContext) {
254     SkCodec::Result resultStorage;
255     if (!outResult) {
256         outResult = &resultStorage;
257     }
258     return SkAvifCodec::MakeFromStream(std::move(stream), outResult);
259 }
260 
Decode(sk_sp<SkData> data,SkCodec::Result * outResult,SkCodecs::DecodeContext)261 std::unique_ptr<SkCodec> Decode(sk_sp<SkData> data,
262                                 SkCodec::Result* outResult,
263                                 SkCodecs::DecodeContext) {
264     if (!data) {
265         if (outResult) {
266             *outResult = SkCodec::kInvalidInput;
267         }
268         return nullptr;
269     }
270     return Decode(SkMemoryStream::Make(std::move(data)), outResult, nullptr);
271 }
272 
273 }  // namespace LibAvif
274 }  // namespace SkAvifDecoder
275