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