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