1 /*
2  * Copyright 2017 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 "include/core/SkTypes.h"
9 
10 #ifdef SK_HAS_HEIF_LIBRARY
11 #include "include/codec/SkCodec.h"
12 #include "include/core/SkEncodedImageFormat.h"
13 #include "include/core/SkStream.h"
14 #include "include/private/SkColorData.h"
15 #include "include/private/base/SkTemplates.h"
16 #include "src/codec/SkCodecPriv.h"
17 #include "src/codec/SkHeifCodec.h"
18 #include "src/core/SkEndian.h"
19 
20 #define FOURCC(c1, c2, c3, c4) \
21     ((c1) << 24 | (c2) << 16 | (c3) << 8 | (c4))
22 
IsSupported(const void * buffer,size_t bytesRead,SkEncodedImageFormat * format)23 bool SkHeifCodec::IsSupported(const void* buffer, size_t bytesRead,
24                               SkEncodedImageFormat* format) {
25     // Parse the ftyp box up to bytesRead to determine if this is HEIF or AVIF.
26     // Any valid ftyp box should have at least 8 bytes.
27     if (bytesRead < 8) {
28         return false;
29     }
30 
31     uint32_t* ptr = (uint32_t*)buffer;
32     uint64_t chunkSize = SkEndian_SwapBE32(ptr[0]);
33     uint32_t chunkType = SkEndian_SwapBE32(ptr[1]);
34 
35     if (chunkType != FOURCC('f', 't', 'y', 'p')) {
36         return false;
37     }
38 
39     int64_t offset = 8;
40     if (chunkSize == 1) {
41         // This indicates that the next 8 bytes represent the chunk size,
42         // and chunk data comes after that.
43         if (bytesRead < 16) {
44             return false;
45         }
46         auto* chunkSizePtr = SkTAddOffset<const uint64_t>(buffer, offset);
47         chunkSize = SkEndian_SwapBE64(*chunkSizePtr);
48         if (chunkSize < 16) {
49             // The smallest valid chunk is 16 bytes long in this case.
50             return false;
51         }
52         offset += 8;
53     } else if (chunkSize < 8) {
54         // The smallest valid chunk is 8 bytes long.
55         return false;
56     }
57 
58     if (chunkSize > bytesRead) {
59         chunkSize = bytesRead;
60     }
61     int64_t chunkDataSize = chunkSize - offset;
62     // It should at least have major brand (4-byte) and minor version (4-bytes).
63     // The rest of the chunk (if any) is a list of (4-byte) compatible brands.
64     if (chunkDataSize < 8) {
65         return false;
66     }
67 
68     uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4;
69     bool isHeif = false;
70     for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
71         if (i == 1) {
72             // Skip this index, it refers to the minorVersion,
73             // not a brand.
74             continue;
75         }
76         auto* brandPtr = SkTAddOffset<const uint32_t>(buffer, offset + 4 * i);
77         uint32_t brand = SkEndian_SwapBE32(*brandPtr);
78         if (brand == FOURCC('m', 'i', 'f', '1') || brand == FOURCC('h', 'e', 'i', 'c')
79          || brand == FOURCC('m', 's', 'f', '1') || brand == FOURCC('h', 'e', 'v', 'c')
80          || brand == FOURCC('a', 'v', 'i', 'f') || brand == FOURCC('a', 'v', 'i', 's')) {
81             // AVIF files could have "mif1" as the major brand. So we cannot
82             // distinguish whether the image is AVIF or HEIC just based on the
83             // "mif1" brand. So wait until we see a specific avif brand to
84             // determine whether it is AVIF or HEIC.
85             isHeif = true;
86             if (brand == FOURCC('a', 'v', 'i', 'f')
87               || brand == FOURCC('a', 'v', 'i', 's')) {
88                 if (format != nullptr) {
89                     *format = SkEncodedImageFormat::kAVIF;
90                 }
91                 return true;
92             }
93         }
94     }
95     if (isHeif) {
96         if (format != nullptr) {
97             *format = SkEncodedImageFormat::kHEIF;
98         }
99         return true;
100     }
101     return false;
102 }
103 
get_orientation(const HeifFrameInfo & frameInfo)104 static SkEncodedOrigin get_orientation(const HeifFrameInfo& frameInfo) {
105     switch (frameInfo.mRotationAngle) {
106         case 0:   return kTopLeft_SkEncodedOrigin;
107         case 90:  return kRightTop_SkEncodedOrigin;
108         case 180: return kBottomRight_SkEncodedOrigin;
109         case 270: return kLeftBottom_SkEncodedOrigin;
110     }
111     return kDefault_SkEncodedOrigin;
112 }
113 
114 struct SkHeifStreamWrapper : public HeifStream {
SkHeifStreamWrapperSkHeifStreamWrapper115     SkHeifStreamWrapper(SkStream* stream) : fStream(stream) {}
116 
~SkHeifStreamWrapperSkHeifStreamWrapper117     ~SkHeifStreamWrapper() override {}
118 
readSkHeifStreamWrapper119     size_t read(void* buffer, size_t size) override {
120         return fStream->read(buffer, size);
121     }
122 
rewindSkHeifStreamWrapper123     bool rewind() override {
124         return fStream->rewind();
125     }
126 
seekSkHeifStreamWrapper127     bool seek(size_t position) override {
128         return fStream->seek(position);
129     }
130 
hasLengthSkHeifStreamWrapper131     bool hasLength() const override {
132         return fStream->hasLength();
133     }
134 
getLengthSkHeifStreamWrapper135     size_t getLength() const override {
136         return fStream->getLength();
137     }
138 
139 private:
140     std::unique_ptr<SkStream> fStream;
141 };
142 
releaseProc(const void * ptr,void * context)143 static void releaseProc(const void* ptr, void* context) {
144     delete reinterpret_cast<std::vector<uint8_t>*>(context);
145 }
146 
MakeFromStream(std::unique_ptr<SkStream> stream,SkCodec::SelectionPolicy selectionPolicy,SkEncodedImageFormat format,Result * result)147 std::unique_ptr<SkCodec> SkHeifCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
148         SkCodec::SelectionPolicy selectionPolicy, SkEncodedImageFormat format, Result* result) {
149     std::unique_ptr<HeifDecoder> heifDecoder(createHeifDecoder());
150     if (heifDecoder == nullptr) {
151         *result = kInternalError;
152         return nullptr;
153     }
154 
155     HeifFrameInfo heifInfo;
156     if (!heifDecoder->init(new SkHeifStreamWrapper(stream.release()), &heifInfo)) {
157         *result = kInvalidInput;
158         return nullptr;
159     }
160 
161     size_t frameCount = 1;
162     if (selectionPolicy == SkCodec::SelectionPolicy::kPreferAnimation) {
163         HeifFrameInfo sequenceInfo;
164         if (heifDecoder->getSequenceInfo(&sequenceInfo, &frameCount) &&
165                 frameCount > 1) {
166             heifInfo = std::move(sequenceInfo);
167         }
168     }
169 
170     std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
171     if (heifInfo.mIccData.size() > 0) {
172         auto iccData = new std::vector<uint8_t>(std::move(heifInfo.mIccData));
173         auto icc = SkData::MakeWithProc(iccData->data(), iccData->size(), releaseProc, iccData);
174         profile = SkEncodedInfo::ICCProfile::Make(std::move(icc));
175     }
176     if (profile && profile->profile()->data_color_space != skcms_Signature_RGB) {
177         // This will result in sRGB.
178         profile = nullptr;
179     }
180 
181     uint8_t colorDepth = heifDecoder->getColorDepth();
182 
183     SkEncodedInfo info = SkEncodedInfo::Make(heifInfo.mWidth, heifInfo.mHeight,
184             SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha,
185             /*bitsPerComponent*/ 8, std::move(profile), colorDepth);
186     SkEncodedOrigin orientation = get_orientation(heifInfo);
187 
188     *result = kSuccess;
189     return std::unique_ptr<SkCodec>(new SkHeifCodec(
190             std::move(info), heifDecoder.release(), orientation, frameCount > 1, format));
191 }
192 
SkHeifCodec(SkEncodedInfo && info,HeifDecoder * heifDecoder,SkEncodedOrigin origin,bool useAnimation,SkEncodedImageFormat format)193 SkHeifCodec::SkHeifCodec(
194         SkEncodedInfo&& info,
195         HeifDecoder* heifDecoder,
196         SkEncodedOrigin origin,
197         bool useAnimation,
198         SkEncodedImageFormat format)
199     : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, nullptr, origin)
200     , fHeifDecoder(heifDecoder)
201     , fSwizzleSrcRow(nullptr)
202     , fColorXformSrcRow(nullptr)
203     , fUseAnimation(useAnimation)
204     , fFormat(format)
205 {}
206 
conversionSupported(const SkImageInfo & dstInfo,bool srcIsOpaque,bool needsColorXform)207 bool SkHeifCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque,
208                                       bool needsColorXform) {
209     SkASSERT(srcIsOpaque);
210 
211     if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
212         return false;
213     }
214 
215     if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
216         SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
217                 "- it is being decoded as non-opaque, which will draw slower\n");
218     }
219 
220     uint8_t colorDepth = fHeifDecoder->getColorDepth();
221     switch (dstInfo.colorType()) {
222         case kRGBA_8888_SkColorType:
223             this->setSrcXformFormat(skcms_PixelFormat_RGBA_8888);
224             return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
225 
226         case kBGRA_8888_SkColorType:
227             this->setSrcXformFormat(skcms_PixelFormat_RGBA_8888);
228             return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888);
229 
230         case kRGB_565_SkColorType:
231             this->setSrcXformFormat(skcms_PixelFormat_RGBA_8888);
232             if (needsColorXform) {
233                 return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
234             } else {
235                 return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565);
236             }
237 
238         case kRGBA_1010102_SkColorType:
239             this->setSrcXformFormat(skcms_PixelFormat_RGBA_1010102);
240             return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_1010102);
241 
242         case kRGBA_F16_SkColorType:
243             SkASSERT(needsColorXform);
244             if (srcIsOpaque && colorDepth == 10) {
245                 this->setSrcXformFormat(skcms_PixelFormat_RGBA_1010102);
246                 return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_1010102);
247             } else {
248                 this->setSrcXformFormat(skcms_PixelFormat_RGBA_8888);
249                 return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
250             }
251 
252         default:
253             return false;
254     }
255 }
256 
readRows(const SkImageInfo & dstInfo,void * dst,size_t rowBytes,int count,const Options & opts)257 int SkHeifCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count,
258                           const Options& opts) {
259     // When fSwizzleSrcRow is non-null, it means that we need to swizzle.  In this case,
260     // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
261     // We can never swizzle "in place" because the swizzler may perform sampling and/or
262     // subsetting.
263     // When fColorXformSrcRow is non-null, it means that we need to color xform and that
264     // we cannot color xform "in place" (many times we can, but not when the dst is F16).
265     // In this case, we will color xform from fColorXformSrcRow into the dst.
266     uint8_t* decodeDst = (uint8_t*) dst;
267     uint32_t* swizzleDst = (uint32_t*) dst;
268     size_t decodeDstRowBytes = rowBytes;
269     size_t swizzleDstRowBytes = rowBytes;
270     int dstWidth = opts.fSubset ? opts.fSubset->width() : dstInfo.width();
271     if (fSwizzleSrcRow && fColorXformSrcRow) {
272         decodeDst = fSwizzleSrcRow;
273         swizzleDst = fColorXformSrcRow;
274         decodeDstRowBytes = 0;
275         swizzleDstRowBytes = 0;
276         dstWidth = fSwizzler->swizzleWidth();
277     } else if (fColorXformSrcRow) {
278         decodeDst = (uint8_t*) fColorXformSrcRow;
279         swizzleDst = fColorXformSrcRow;
280         decodeDstRowBytes = 0;
281         swizzleDstRowBytes = 0;
282     } else if (fSwizzleSrcRow) {
283         decodeDst = fSwizzleSrcRow;
284         decodeDstRowBytes = 0;
285         dstWidth = fSwizzler->swizzleWidth();
286     }
287 
288     for (int y = 0; y < count; y++) {
289         if (!fHeifDecoder->getScanline(decodeDst)) {
290             return y;
291         }
292 
293         if (fSwizzler) {
294             fSwizzler->swizzle(swizzleDst, decodeDst);
295         }
296 
297         if (this->colorXform()) {
298             this->applyColorXform(dst, swizzleDst, dstWidth);
299             dst = SkTAddOffset<void>(dst, rowBytes);
300         }
301 
302         decodeDst = SkTAddOffset<uint8_t>(decodeDst, decodeDstRowBytes);
303         swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
304     }
305 
306     return count;
307 }
308 
onGetFrameCount()309 int SkHeifCodec::onGetFrameCount() {
310     if (!fUseAnimation) {
311         return 1;
312     }
313 
314     if (fFrameHolder.size() == 0) {
315         size_t frameCount;
316         HeifFrameInfo frameInfo;
317         if (!fHeifDecoder->getSequenceInfo(&frameInfo, &frameCount)
318                 || frameCount <= 1) {
319             fUseAnimation = false;
320             return 1;
321         }
322         fFrameHolder.reserve(frameCount);
323         for (size_t i = 0; i < frameCount; i++) {
324             Frame* frame = fFrameHolder.appendNewFrame();
325             frame->setXYWH(0, 0, frameInfo.mWidth, frameInfo.mHeight);
326             frame->setDisposalMethod(SkCodecAnimation::DisposalMethod::kKeep);
327             // Currently we don't know the duration until the frame is actually
328             // decoded (onGetFrameInfo is also called before frame is decoded).
329             // For now, fill it base on the value reported for the sequence.
330             frame->setDuration(frameInfo.mDurationUs / 1000);
331             frame->setRequiredFrame(SkCodec::kNoFrame);
332             frame->setHasAlpha(false);
333         }
334     }
335 
336     return fFrameHolder.size();
337 }
338 
onGetFrame(int i) const339 const SkFrame* SkHeifCodec::FrameHolder::onGetFrame(int i) const {
340     return static_cast<const SkFrame*>(this->frame(i));
341 }
342 
appendNewFrame()343 SkHeifCodec::Frame* SkHeifCodec::FrameHolder::appendNewFrame() {
344     const int i = this->size();
345     fFrames.emplace_back(i); // TODO: need to handle frame duration here
346     return &fFrames[i];
347 }
348 
frame(int i) const349 const SkHeifCodec::Frame* SkHeifCodec::FrameHolder::frame(int i) const {
350     SkASSERT(i >= 0 && i < this->size());
351     return &fFrames[i];
352 }
353 
editFrameAt(int i)354 SkHeifCodec::Frame* SkHeifCodec::FrameHolder::editFrameAt(int i) {
355     SkASSERT(i >= 0 && i < this->size());
356     return &fFrames[i];
357 }
358 
onGetFrameInfo(int i,FrameInfo * frameInfo) const359 bool SkHeifCodec::onGetFrameInfo(int i, FrameInfo* frameInfo) const {
360     if (i >= fFrameHolder.size()) {
361         return false;
362     }
363 
364     const Frame* frame = fFrameHolder.frame(i);
365     if (!frame) {
366         return false;
367     }
368 
369     if (frameInfo) {
370         frame->fillIn(frameInfo, true);
371     }
372 
373     return true;
374 }
375 
onGetRepetitionCount()376 int SkHeifCodec::onGetRepetitionCount() {
377     return kRepetitionCountInfinite;
378 }
379 
380 /*
381  * Performs the heif decode
382  */
onGetPixels(const SkImageInfo & dstInfo,void * dst,size_t dstRowBytes,const Options & options,int * rowsDecoded)383 SkCodec::Result SkHeifCodec::onGetPixels(const SkImageInfo& dstInfo,
384                                          void* dst, size_t dstRowBytes,
385                                          const Options& options,
386                                          int* rowsDecoded) {
387     if (options.fSubset) {
388         // Not supporting subsets on this path for now.
389         // TODO: if the heif has tiles, we can support subset here, but
390         // need to retrieve tile config from metadata retriever first.
391         return kUnimplemented;
392     }
393 
394     bool success;
395     if (fUseAnimation) {
396         success = fHeifDecoder->decodeSequence(options.fFrameIndex, &fFrameInfo);
397         fFrameHolder.editFrameAt(options.fFrameIndex)->setDuration(
398                 fFrameInfo.mDurationUs / 1000);
399     } else {
400         success = fHeifDecoder->decode(&fFrameInfo);
401     }
402 
403     if (!success) {
404         return kInvalidInput;
405     }
406 
407     fSwizzler.reset(nullptr);
408     this->allocateStorage(dstInfo);
409 
410     int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options);
411     if (rows < dstInfo.height()) {
412         *rowsDecoded = rows;
413         return kIncompleteInput;
414     }
415 
416     return kSuccess;
417 }
418 
allocateStorage(const SkImageInfo & dstInfo)419 void SkHeifCodec::allocateStorage(const SkImageInfo& dstInfo) {
420     int dstWidth = dstInfo.width();
421 
422     size_t swizzleBytes = 0;
423     if (fSwizzler) {
424         swizzleBytes = fFrameInfo.mBytesPerPixel * fFrameInfo.mWidth;
425         dstWidth = fSwizzler->swizzleWidth();
426         SkASSERT(!this->colorXform() || SkIsAlign4(swizzleBytes));
427     }
428 
429     size_t xformBytes = 0;
430     if (this->colorXform() && (kRGBA_F16_SkColorType == dstInfo.colorType() ||
431                                kRGB_565_SkColorType == dstInfo.colorType())) {
432         xformBytes = dstWidth * sizeof(uint32_t);
433     }
434 
435     size_t totalBytes = swizzleBytes + xformBytes;
436     fStorage.reset(totalBytes);
437     if (totalBytes > 0) {
438         fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
439         fColorXformSrcRow = (xformBytes > 0) ?
440                 SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
441     }
442 }
443 
initializeSwizzler(const SkImageInfo & dstInfo,const Options & options)444 void SkHeifCodec::initializeSwizzler(
445         const SkImageInfo& dstInfo, const Options& options) {
446     SkImageInfo swizzlerDstInfo = dstInfo;
447     switch (this->getSrcXformFormat()) {
448         case skcms_PixelFormat_RGBA_8888:
449             swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
450             break;
451         case skcms_PixelFormat_RGBA_1010102:
452             swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_1010102_SkColorType);
453             break;
454         default:
455             SkASSERT(false);
456     }
457 
458     int srcBPP = 4;
459     if (dstInfo.colorType() == kRGB_565_SkColorType && !this->colorXform()) {
460         srcBPP = 2;
461     }
462 
463     fSwizzler = SkSwizzler::MakeSimple(srcBPP, swizzlerDstInfo, options);
464     SkASSERT(fSwizzler);
465 }
466 
getSampler(bool createIfNecessary)467 SkSampler* SkHeifCodec::getSampler(bool createIfNecessary) {
468     if (!createIfNecessary || fSwizzler) {
469         SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
470         return fSwizzler.get();
471     }
472 
473     this->initializeSwizzler(this->dstInfo(), this->options());
474     this->allocateStorage(this->dstInfo());
475     return fSwizzler.get();
476 }
477 
onRewind()478 bool SkHeifCodec::onRewind() {
479     fSwizzler.reset(nullptr);
480     fSwizzleSrcRow = nullptr;
481     fColorXformSrcRow = nullptr;
482     fStorage.reset();
483 
484     return true;
485 }
486 
onStartScanlineDecode(const SkImageInfo & dstInfo,const Options & options)487 SkCodec::Result SkHeifCodec::onStartScanlineDecode(
488         const SkImageInfo& dstInfo, const Options& options) {
489     // TODO: For now, just decode the whole thing even when there is a subset.
490     // If the heif image has tiles, we could potentially do this much faster,
491     // but the tile configuration needs to be retrieved from the metadata.
492     if (!fHeifDecoder->decode(&fFrameInfo)) {
493         return kInvalidInput;
494     }
495 
496     if (options.fSubset) {
497         this->initializeSwizzler(dstInfo, options);
498     } else {
499         fSwizzler.reset(nullptr);
500     }
501 
502     this->allocateStorage(dstInfo);
503 
504     return kSuccess;
505 }
506 
onGetScanlines(void * dst,int count,size_t dstRowBytes)507 int SkHeifCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
508     return this->readRows(this->dstInfo(), dst, dstRowBytes, count, this->options());
509 }
510 
onSkipScanlines(int count)511 bool SkHeifCodec::onSkipScanlines(int count) {
512     return count == (int) fHeifDecoder->skipScanlines(count);
513 }
514 
515 #endif // SK_HAS_HEIF_LIBRARY
516