1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #include "include/HeifDecoderAPI.h"
19 #define LOG_TAG "HeifDecoderImpl"
20 
21 #include "HeifDecoderImpl.h"
22 
23 #include <stdio.h>
24 
25 #include <android/IDataSource.h>
26 #include <binder/IMemory.h>
27 #include <binder/MemoryDealer.h>
28 #include <drm/drm_framework_common.h>
29 #include <media/mediametadataretriever.h>
30 #include <media/stagefright/MediaSource.h>
31 #include <media/stagefright/foundation/ADebug.h>
32 #include <private/media/VideoFrame.h>
33 #include <utils/Log.h>
34 #include <utils/RefBase.h>
35 #include <algorithm>
36 #include <vector>
37 
createHeifDecoder()38 HeifDecoder* createHeifDecoder() {
39     return new android::HeifDecoderImpl();
40 }
41 
42 namespace android {
43 
initFrameInfo(HeifFrameInfo * info,const VideoFrame * videoFrame)44 void initFrameInfo(HeifFrameInfo *info, const VideoFrame *videoFrame) {
45     info->mWidth = videoFrame->mDisplayWidth;
46     // Number of scanlines is mDisplayHeight. Clamp it to mHeight to guard
47     // against malformed streams claiming that mDisplayHeight is greater than
48     // mHeight.
49     info->mHeight = std::min(videoFrame->mDisplayHeight, videoFrame->mHeight);
50     info->mRotationAngle = videoFrame->mRotationAngle;
51     info->mBytesPerPixel = videoFrame->mBytesPerPixel;
52     info->mDurationUs = videoFrame->mDurationUs;
53     info->mBitDepth = videoFrame->mBitDepth;
54     if (videoFrame->mIccSize > 0) {
55         info->mIccData.assign(
56                 videoFrame->getFlattenedIccData(),
57                 videoFrame->getFlattenedIccData() + videoFrame->mIccSize);
58     } else {
59         // clear old Icc data if there is no Icc data.
60         info->mIccData.clear();
61     }
62 }
63 
64 /*
65  * HeifDataSource
66  *
67  * Proxies data requests over IDataSource interface from MediaMetadataRetriever
68  * to the HeifStream interface we received from the heif decoder client.
69  */
70 class HeifDataSource : public BnDataSource {
71 public:
72     /*
73      * Constructs HeifDataSource; will take ownership of |stream|.
74      */
HeifDataSource(HeifStream * stream)75     HeifDataSource(HeifStream* stream)
76         : mStream(stream), mEOS(false),
77           mCachedOffset(0), mCachedSize(0), mCacheBufferSize(0) {}
78 
~HeifDataSource()79     ~HeifDataSource() override {}
80 
81     /*
82      * Initializes internal resources.
83      */
84     bool init();
85 
getIMemory()86     sp<IMemory> getIMemory() override { return mMemory; }
87     ssize_t readAt(off64_t offset, size_t size) override;
88     status_t getSize(off64_t* size) override ;
close()89     void close() {}
getFlags()90     uint32_t getFlags() override { return 0; }
toString()91     String8 toString() override { return String8("HeifDataSource"); }
92 
93 private:
94     enum {
95         /*
96          * Buffer size for passing the read data to mediaserver. Set to 64K
97          * (which is what MediaDataSource Java API's jni implementation uses).
98          */
99         kBufferSize = 64 * 1024,
100         /*
101          * Initial and max cache buffer size.
102          */
103         kInitialCacheBufferSize = 4 * 1024 * 1024,
104         kMaxCacheBufferSize = 64 * 1024 * 1024,
105     };
106     sp<IMemory> mMemory;
107     std::unique_ptr<HeifStream> mStream;
108     bool mEOS;
109     std::unique_ptr<uint8_t[]> mCache;
110     off64_t mCachedOffset;
111     size_t mCachedSize;
112     size_t mCacheBufferSize;
113 };
114 
init()115 bool HeifDataSource::init() {
116     sp<MemoryDealer> memoryDealer =
117             new MemoryDealer(kBufferSize, "HeifDataSource");
118     mMemory = memoryDealer->allocate(kBufferSize);
119     if (mMemory == nullptr) {
120         ALOGE("Failed to allocate shared memory!");
121         return false;
122     }
123     mCache.reset(new uint8_t[kInitialCacheBufferSize]);
124     if (mCache.get() == nullptr) {
125         ALOGE("mFailed to allocate cache!");
126         return false;
127     }
128     mCacheBufferSize = kInitialCacheBufferSize;
129     return true;
130 }
131 
readAt(off64_t offset,size_t size)132 ssize_t HeifDataSource::readAt(off64_t offset, size_t size) {
133     ALOGV("readAt: offset=%lld, size=%zu", (long long)offset, size);
134 
135     if (offset < mCachedOffset) {
136         // try seek, then rewind/skip, fail if none worked
137         if (mStream->seek(offset)) {
138             ALOGV("readAt: seek to offset=%lld", (long long)offset);
139             mCachedOffset = offset;
140             mCachedSize = 0;
141             mEOS = false;
142         } else if (mStream->rewind()) {
143             ALOGV("readAt: rewind to offset=0");
144             mCachedOffset = 0;
145             mCachedSize = 0;
146             mEOS = false;
147         } else {
148             ALOGE("readAt: couldn't seek or rewind!");
149             mEOS = true;
150         }
151     }
152 
153     if (mEOS && (offset < mCachedOffset ||
154                  offset >= (off64_t)(mCachedOffset + mCachedSize))) {
155         ALOGV("readAt: EOS");
156         return ERROR_END_OF_STREAM;
157     }
158 
159     // at this point, offset must be >= mCachedOffset, other cases should
160     // have been caught above.
161     CHECK(offset >= mCachedOffset);
162 
163     off64_t resultOffset;
164     if (__builtin_add_overflow(offset, size, &resultOffset)) {
165         return ERROR_IO;
166     }
167 
168     if (size == 0) {
169         return 0;
170     }
171 
172     // Can only read max of kBufferSize
173     if (size > kBufferSize) {
174         size = kBufferSize;
175     }
176 
177     // copy from cache if the request falls entirely in cache
178     if (offset + size <= mCachedOffset + mCachedSize) {
179         memcpy(mMemory->unsecurePointer(), mCache.get() + offset - mCachedOffset, size);
180         return size;
181     }
182 
183     // need to fetch more, check if we need to expand the cache buffer.
184     if ((off64_t)(offset + size) > mCachedOffset + kMaxCacheBufferSize) {
185         // it's reaching max cache buffer size, need to roll window, and possibly
186         // expand the cache buffer.
187         size_t newCacheBufferSize = mCacheBufferSize;
188         std::unique_ptr<uint8_t[]> newCache;
189         uint8_t* dst = mCache.get();
190         if (newCacheBufferSize < kMaxCacheBufferSize) {
191             newCacheBufferSize = kMaxCacheBufferSize;
192             newCache.reset(new uint8_t[newCacheBufferSize]);
193             dst = newCache.get();
194         }
195 
196         // when rolling the cache window, try to keep about half the old bytes
197         // in case that the client goes back.
198         off64_t newCachedOffset = offset - (off64_t)(newCacheBufferSize / 2);
199         if (newCachedOffset < mCachedOffset) {
200             newCachedOffset = mCachedOffset;
201         }
202 
203         int64_t newCachedSize = (int64_t)(mCachedOffset + mCachedSize) - newCachedOffset;
204         if (newCachedSize > 0) {
205             // in this case, the new cache region partially overlop the old cache,
206             // move the portion of the cache we want to save to the beginning of
207             // the cache buffer.
208             memcpy(dst, mCache.get() + newCachedOffset - mCachedOffset, newCachedSize);
209         } else if (newCachedSize < 0){
210             // in this case, the new cache region is entirely out of the old cache,
211             // in order to guarantee sequential read, we need to skip a number of
212             // bytes before reading.
213             size_t bytesToSkip = -newCachedSize;
214             size_t bytesSkipped = mStream->read(nullptr, bytesToSkip);
215             if (bytesSkipped != bytesToSkip) {
216                 // bytesSkipped is invalid, there is not enough bytes to reach
217                 // the requested offset.
218                 ALOGE("readAt: skip failed, EOS");
219 
220                 mEOS = true;
221                 mCachedOffset = newCachedOffset;
222                 mCachedSize = 0;
223                 return ERROR_END_OF_STREAM;
224             }
225             // set cache size to 0, since we're not keeping any old cache
226             newCachedSize = 0;
227         }
228 
229         if (newCache.get() != nullptr) {
230             mCache.reset(newCache.release());
231             mCacheBufferSize = newCacheBufferSize;
232         }
233         mCachedOffset = newCachedOffset;
234         mCachedSize = newCachedSize;
235 
236         ALOGV("readAt: rolling cache window to (%lld, %zu), cache buffer size %zu",
237                 (long long)mCachedOffset, mCachedSize, mCacheBufferSize);
238     } else {
239         // expand cache buffer, but no need to roll the window
240         size_t newCacheBufferSize = mCacheBufferSize;
241         while (offset + size > mCachedOffset + newCacheBufferSize) {
242             newCacheBufferSize *= 2;
243         }
244         CHECK(newCacheBufferSize <= kMaxCacheBufferSize);
245         if (mCacheBufferSize < newCacheBufferSize) {
246             uint8_t* newCache = new uint8_t[newCacheBufferSize];
247             memcpy(newCache, mCache.get(), mCachedSize);
248             mCache.reset(newCache);
249             mCacheBufferSize = newCacheBufferSize;
250 
251             ALOGV("readAt: current cache window (%lld, %zu), new cache buffer size %zu",
252                     (long long) mCachedOffset, mCachedSize, mCacheBufferSize);
253         }
254     }
255     size_t bytesToRead = offset + size - mCachedOffset - mCachedSize;
256     size_t bytesRead = mStream->read(mCache.get() + mCachedSize, bytesToRead);
257     if (bytesRead > bytesToRead || bytesRead == 0) {
258         // bytesRead is invalid
259         mEOS = true;
260         bytesRead = 0;
261     } else if (bytesRead < bytesToRead) {
262         // read some bytes but not all, set EOS
263         mEOS = true;
264     }
265     mCachedSize += bytesRead;
266     ALOGV("readAt: current cache window (%lld, %zu)",
267             (long long) mCachedOffset, mCachedSize);
268 
269     // here bytesAvailable could be negative if offset jumped past EOS.
270     int64_t bytesAvailable = mCachedOffset + mCachedSize - offset;
271     if (bytesAvailable <= 0) {
272         return ERROR_END_OF_STREAM;
273     }
274     if (bytesAvailable < (int64_t)size) {
275         size = bytesAvailable;
276     }
277     memcpy(mMemory->unsecurePointer(), mCache.get() + offset - mCachedOffset, size);
278     return size;
279 }
280 
getSize(off64_t * size)281 status_t HeifDataSource::getSize(off64_t* size) {
282     if (!mStream->hasLength()) {
283         *size = -1;
284         ALOGE("getSize: not supported!");
285         return ERROR_UNSUPPORTED;
286     }
287     *size = mStream->getLength();
288     ALOGV("getSize: size=%lld", (long long)*size);
289     return OK;
290 }
291 
292 /////////////////////////////////////////////////////////////////////////
293 
294 struct HeifDecoderImpl::DecodeThread : public Thread {
DecodeThreadandroid::HeifDecoderImpl::DecodeThread295     explicit DecodeThread(HeifDecoderImpl *decoder) : mDecoder(decoder) {}
296 
297 private:
298     HeifDecoderImpl* mDecoder;
299 
300     bool threadLoop();
301 
302     DISALLOW_EVIL_CONSTRUCTORS(DecodeThread);
303 };
304 
threadLoop()305 bool HeifDecoderImpl::DecodeThread::threadLoop() {
306     return mDecoder->decodeAsync();
307 }
308 
309 /////////////////////////////////////////////////////////////////////////
310 
HeifDecoderImpl()311 HeifDecoderImpl::HeifDecoderImpl() :
312     // output color format should always be set via setOutputColor(), in case
313     // it's not, default to HAL_PIXEL_FORMAT_RGB_565.
314     mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
315     mCurScanline(0),
316     mTotalScanline(0),
317     mFrameDecoded(false),
318     mHasImage(false),
319     mHasVideo(false),
320     mSequenceLength(0),
321     mAvailableLines(0),
322     mNumSlices(1),
323     mSliceHeight(0),
324     mAsyncDecodeDone(false) {
325 }
326 
~HeifDecoderImpl()327 HeifDecoderImpl::~HeifDecoderImpl() {
328     if (mThread != nullptr) {
329         mThread->join();
330     }
331 }
332 
init(HeifStream * stream,HeifFrameInfo * frameInfo)333 bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
334     mFrameDecoded = false;
335     mFrameMemory.clear();
336 
337     sp<HeifDataSource> dataSource = new HeifDataSource(stream);
338     if (!dataSource->init()) {
339         return false;
340     }
341     mDataSource = dataSource;
342 
343     return reinit(frameInfo);
344 }
345 
reinit(HeifFrameInfo * frameInfo)346 bool HeifDecoderImpl::reinit(HeifFrameInfo* frameInfo) {
347     mFrameDecoded = false;
348     mFrameMemory.clear();
349 
350     sp<MediaMetadataRetriever> retriever = new MediaMetadataRetriever();
351     status_t err = retriever->setDataSource(mDataSource, "image/heif");
352     if (err != OK) {
353         ALOGE("failed to set data source!");
354         mRetriever.clear();
355         mDataSource.clear();
356         return false;
357     }
358     {
359         Mutex::Autolock _l(mRetrieverLock);
360         mRetriever = retriever;
361     }
362     ALOGV("successfully set data source.");
363 
364     const char* hasImage = retriever->extractMetadata(METADATA_KEY_HAS_IMAGE);
365     const char* hasVideo = retriever->extractMetadata(METADATA_KEY_HAS_VIDEO);
366 
367     mHasImage = hasImage && !strcasecmp(hasImage, "yes");
368     mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
369 
370     HeifFrameInfo* defaultInfo = nullptr;
371     if (mHasImage) {
372         // image index < 0 to retrieve primary image
373         sp<IMemory> sharedMem = retriever->getImageAtIndex(
374                 -1, mOutputColor, true /*metaOnly*/);
375 
376         if (sharedMem == nullptr || sharedMem->unsecurePointer() == nullptr) {
377             ALOGE("init: videoFrame is a nullptr");
378             return false;
379         }
380 
381         // TODO: Using unsecurePointer() has some associated security pitfalls
382         //       (see declaration for details).
383         //       Either document why it is safe in this case or address the
384         //       issue (e.g. by copying).
385         VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->unsecurePointer());
386 
387         ALOGV("Image dimension %dx%d, display %dx%d, angle %d, iccSize %d, bitDepth %d",
388                 videoFrame->mWidth,
389                 videoFrame->mHeight,
390                 videoFrame->mDisplayWidth,
391                 videoFrame->mDisplayHeight,
392                 videoFrame->mRotationAngle,
393                 videoFrame->mIccSize,
394                 videoFrame->mBitDepth);
395 
396         initFrameInfo(&mImageInfo, videoFrame);
397 
398         if (videoFrame->mTileHeight >= 512) {
399             // Try decoding in slices only if the image has tiles and is big enough.
400             mSliceHeight = videoFrame->mTileHeight;
401             ALOGV("mSliceHeight %u", mSliceHeight);
402         }
403 
404         defaultInfo = &mImageInfo;
405     }
406 
407     if (mHasVideo) {
408         sp<IMemory> sharedMem = retriever->getFrameAtTime(0,
409                 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
410                 mOutputColor, true /*metaOnly*/);
411 
412         if (sharedMem == nullptr || sharedMem->unsecurePointer() == nullptr) {
413             ALOGE("init: videoFrame is a nullptr");
414             return false;
415         }
416 
417         // TODO: Using unsecurePointer() has some associated security pitfalls
418         //       (see declaration for details).
419         //       Either document why it is safe in this case or address the
420         //       issue (e.g. by copying).
421         VideoFrame* videoFrame = static_cast<VideoFrame*>(
422             sharedMem->unsecurePointer());
423 
424         ALOGV("Sequence dimension %dx%d, display %dx%d, angle %d, iccSize %d",
425                 videoFrame->mWidth,
426                 videoFrame->mHeight,
427                 videoFrame->mDisplayWidth,
428                 videoFrame->mDisplayHeight,
429                 videoFrame->mRotationAngle,
430                 videoFrame->mIccSize);
431 
432         initFrameInfo(&mSequenceInfo, videoFrame);
433 
434         const char* frameCount = retriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT);
435         if (frameCount == nullptr) {
436             android_errorWriteWithInfoLog(0x534e4554, "215002587", -1, NULL, 0);
437             ALOGD("No valid sequence information in metadata");
438             return false;
439         }
440         mSequenceLength = atoi(frameCount);
441 
442         if (defaultInfo == nullptr) {
443             defaultInfo = &mSequenceInfo;
444         }
445     }
446 
447     if (defaultInfo == nullptr) {
448         ALOGD("No valid image or sequence available");
449         return false;
450     }
451 
452     if (frameInfo != nullptr) {
453         *frameInfo = *defaultInfo;
454     }
455 
456     // default total scanline, this might change if decodeSequence() is used
457     mTotalScanline = defaultInfo->mHeight;
458 
459     return true;
460 }
461 
getSequenceInfo(HeifFrameInfo * frameInfo,size_t * frameCount)462 bool HeifDecoderImpl::getSequenceInfo(
463         HeifFrameInfo* frameInfo, size_t *frameCount) {
464     ALOGV("%s", __FUNCTION__);
465     if (!mHasVideo) {
466         return false;
467     }
468     if (frameInfo != nullptr) {
469         *frameInfo = mSequenceInfo;
470     }
471     if (frameCount != nullptr) {
472         *frameCount = mSequenceLength;
473     }
474     return true;
475 }
476 
getEncodedColor(HeifEncodedColor *) const477 bool HeifDecoderImpl::getEncodedColor(HeifEncodedColor* /*outColor*/) const {
478     ALOGW("getEncodedColor: not implemented!");
479     return false;
480 }
481 
setOutputColor(HeifColorFormat heifColor)482 bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) {
483     android_pixel_format_t outputColor;
484     switch(heifColor) {
485         case kHeifColorFormat_RGB565:
486         {
487             outputColor = HAL_PIXEL_FORMAT_RGB_565;
488             break;
489         }
490         case kHeifColorFormat_RGBA_8888:
491         {
492             outputColor = HAL_PIXEL_FORMAT_RGBA_8888;
493             break;
494         }
495         case kHeifColorFormat_BGRA_8888:
496         {
497             outputColor = HAL_PIXEL_FORMAT_BGRA_8888;
498             break;
499         }
500         case kHeifColorFormat_RGBA_1010102:
501         {
502             outputColor = HAL_PIXEL_FORMAT_RGBA_1010102;
503             break;
504         }
505         default:
506             ALOGE("Unsupported output color format %d", heifColor);
507             return false;
508     }
509     if (outputColor == mOutputColor) {
510         return true;
511     }
512 
513     mOutputColor = outputColor;
514 
515     if (mFrameDecoded) {
516         return reinit(nullptr);
517     }
518     return true;
519 }
520 
decodeAsync()521 bool HeifDecoderImpl::decodeAsync() {
522     wp<MediaMetadataRetriever> weakRetriever;
523     {
524         Mutex::Autolock _l(mRetrieverLock);
525         weakRetriever = mRetriever;
526     }
527 
528     for (size_t i = 1; i < mNumSlices; i++) {
529         sp<MediaMetadataRetriever> retriever = weakRetriever.promote();
530         if (retriever == nullptr) {
531             return false;
532         }
533 
534         ALOGV("decodeAsync(): decoding slice %zu", i);
535         size_t top = i * mSliceHeight;
536         size_t bottom = (i + 1) * mSliceHeight;
537         if (bottom > mImageInfo.mHeight) {
538             bottom = mImageInfo.mHeight;
539         }
540 
541         sp<IMemory> frameMemory = retriever->getImageRectAtIndex(
542                 -1, mOutputColor, 0, top, mImageInfo.mWidth, bottom);
543         {
544             Mutex::Autolock autolock(mLock);
545 
546             if (frameMemory == nullptr || frameMemory->unsecurePointer() == nullptr) {
547                 mAsyncDecodeDone = true;
548                 mScanlineReady.signal();
549                 break;
550             }
551             mFrameMemory = frameMemory;
552             mAvailableLines = bottom;
553             ALOGV("decodeAsync(): available lines %zu", mAvailableLines);
554             mScanlineReady.signal();
555         }
556     }
557     // Hold on to mDataSource in case the client wants to redecode.
558 
559     {
560         Mutex::Autolock _l(mRetrieverLock);
561         mRetriever.clear();
562     }
563 
564     return false;
565 }
566 
decode(HeifFrameInfo * frameInfo)567 bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) {
568     // reset scanline pointer
569     mCurScanline = 0;
570 
571     if (mFrameDecoded) {
572         return true;
573     }
574 
575     sp<MediaMetadataRetriever> retriever;
576     {
577         Mutex::Autolock _l(mRetrieverLock);
578         if (mRetriever == nullptr) {
579             ALOGE("Failed to get MediaMetadataRetriever!");
580             return false;
581         }
582 
583         retriever = mRetriever;
584     }
585 
586     // See if we want to decode in slices to allow client to start
587     // scanline processing in parallel with decode. If this fails
588     // we fallback to decoding the full frame.
589     if (mHasImage) {
590         if (mSliceHeight >= 512 &&
591                 mImageInfo.mWidth >= 3000 &&
592                 mImageInfo.mHeight >= 2000 ) {
593             // Try decoding in slices only if the image has tiles and is big enough.
594             mNumSlices = (mImageInfo.mHeight + mSliceHeight - 1) / mSliceHeight;
595             ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
596         }
597 
598         if (mNumSlices > 1) {
599             // get first slice and metadata
600             sp<IMemory> frameMemory = retriever->getImageRectAtIndex(
601                     -1, mOutputColor, 0, 0, mImageInfo.mWidth, mSliceHeight);
602 
603             if (frameMemory == nullptr || frameMemory->unsecurePointer() == nullptr) {
604                 ALOGE("decode: metadata is a nullptr");
605                 return false;
606             }
607 
608             // TODO: Using unsecurePointer() has some associated security pitfalls
609             //       (see declaration for details).
610             //       Either document why it is safe in this case or address the
611             //       issue (e.g. by copying).
612             VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->unsecurePointer());
613 
614             if (frameInfo != nullptr) {
615                 initFrameInfo(frameInfo, videoFrame);
616             }
617             mFrameMemory = frameMemory;
618             mAvailableLines = mSliceHeight;
619             mThread = new DecodeThread(this);
620             if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
621                 mFrameDecoded = true;
622                 return true;
623             }
624             // Fallback to decode without slicing
625             mThread.clear();
626             mNumSlices = 1;
627             mSliceHeight = 0;
628             mAvailableLines = 0;
629             mFrameMemory.clear();
630         }
631     }
632 
633     if (mHasImage) {
634         // image index < 0 to retrieve primary image
635         mFrameMemory = retriever->getImageAtIndex(-1, mOutputColor);
636     } else if (mHasVideo) {
637         mFrameMemory = retriever->getFrameAtTime(0,
638                 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
639     }
640 
641     if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
642         ALOGE("decode: videoFrame is a nullptr");
643         return false;
644     }
645 
646     // TODO: Using unsecurePointer() has some associated security pitfalls
647     //       (see declaration for details).
648     //       Either document why it is safe in this case or address the
649     //       issue (e.g. by copying).
650     VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
651     if (videoFrame->mSize == 0 ||
652             mFrameMemory->size() < videoFrame->getFlattenedSize()) {
653         ALOGE("decode: videoFrame size is invalid");
654         return false;
655     }
656 
657     ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
658             videoFrame->mWidth,
659             videoFrame->mHeight,
660             videoFrame->mDisplayWidth,
661             videoFrame->mDisplayHeight,
662             videoFrame->mRotationAngle,
663             videoFrame->mRowBytes,
664             videoFrame->mSize);
665 
666     if (frameInfo != nullptr) {
667         initFrameInfo(frameInfo, videoFrame);
668 
669     }
670     mFrameDecoded = true;
671 
672     // Aggressively clear to avoid holding on to resources
673     {
674         Mutex::Autolock _l(mRetrieverLock);
675         mRetriever.clear();
676     }
677 
678     // Hold on to mDataSource in case the client wants to redecode.
679     return true;
680 }
681 
decodeSequence(int frameIndex,HeifFrameInfo * frameInfo)682 bool HeifDecoderImpl::decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) {
683     ALOGV("%s: frame index %d", __FUNCTION__, frameIndex);
684     if (!mHasVideo) {
685         return false;
686     }
687 
688     if (frameIndex < 0 || frameIndex >= mSequenceLength) {
689         ALOGE("invalid frame index: %d, total frames %zu", frameIndex, mSequenceLength);
690         return false;
691     }
692 
693     mCurScanline = 0;
694 
695     // set total scanline to sequence height now
696     mTotalScanline = mSequenceInfo.mHeight;
697 
698     sp<MediaMetadataRetriever> retriever;
699     {
700         Mutex::Autolock _l(mRetrieverLock);
701         retriever = mRetriever;
702         if (retriever == nullptr) {
703             ALOGE("failed to get MediaMetadataRetriever!");
704             return false;
705         }
706     }
707 
708     mFrameMemory = retriever->getFrameAtIndex(frameIndex, mOutputColor);
709     if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
710         ALOGE("decode: videoFrame is a nullptr");
711         return false;
712     }
713 
714     // TODO: Using unsecurePointer() has some associated security pitfalls
715     //       (see declaration for details).
716     //       Either document why it is safe in this case or address the
717     //       issue (e.g. by copying).
718     VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
719     if (videoFrame->mSize == 0 ||
720             mFrameMemory->size() < videoFrame->getFlattenedSize()) {
721         ALOGE("decode: videoFrame size is invalid");
722         return false;
723     }
724 
725     ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
726             videoFrame->mWidth,
727             videoFrame->mHeight,
728             videoFrame->mDisplayWidth,
729             videoFrame->mDisplayHeight,
730             videoFrame->mRotationAngle,
731             videoFrame->mRowBytes,
732             videoFrame->mSize);
733 
734     if (frameInfo != nullptr) {
735         initFrameInfo(frameInfo, videoFrame);
736     }
737     return true;
738 }
739 
getScanlineInner(uint8_t * dst)740 bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) {
741     if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
742         return false;
743     }
744     // TODO: Using unsecurePointer() has some associated security pitfalls
745     //       (see declaration for details).
746     //       Either document why it is safe in this case or address the
747     //       issue (e.g. by copying).
748     VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
749     uint8_t* src = videoFrame->getFlattenedData() +
750                    (videoFrame->mRowBytes * (mCurScanline + videoFrame->mDisplayTop)) +
751                    (videoFrame->mBytesPerPixel * videoFrame->mDisplayLeft);
752     mCurScanline++;
753     // Do not try to copy more than |videoFrame->mWidth| pixels.
754     uint32_t width = std::min(videoFrame->mDisplayWidth, videoFrame->mWidth);
755     memcpy(dst, src, videoFrame->mBytesPerPixel * width);
756     return true;
757 }
758 
getScanline(uint8_t * dst)759 bool HeifDecoderImpl::getScanline(uint8_t* dst) {
760     if (mCurScanline >= mTotalScanline) {
761         ALOGE("no more scanline available");
762         return false;
763     }
764 
765     if (mNumSlices > 1) {
766         Mutex::Autolock autolock(mLock);
767 
768         while (!mAsyncDecodeDone && mCurScanline >= mAvailableLines) {
769             mScanlineReady.wait(mLock);
770         }
771         return (mCurScanline < mAvailableLines) ? getScanlineInner(dst) : false;
772     }
773 
774     return getScanlineInner(dst);
775 }
776 
skipScanlines(size_t count)777 size_t HeifDecoderImpl::skipScanlines(size_t count) {
778     uint32_t oldScanline = mCurScanline;
779     mCurScanline += count;
780     if (mCurScanline > mTotalScanline) {
781         mCurScanline = mTotalScanline;
782     }
783     return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
784 }
785 
getColorDepth()786 uint32_t HeifDecoderImpl::getColorDepth() {
787     HeifFrameInfo* info = &mImageInfo;
788     if (info != nullptr) {
789         return mImageInfo.mBitDepth;
790     } else {
791         return 0;
792     }
793 }
794 
795 } // namespace android
796