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