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