blob: a7c0f845f0cc8a7928afe69785d2748a5a591119 [file] [log] [blame]
Chong Zhangea280cb2017-08-02 11:10:10 -07001/*
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 <binder/IMemory.h>
Dongwon Kang49ce6712018-01-24 10:16:25 -080025#include <binder/MemoryDealer.h>
Chong Zhangea280cb2017-08-02 11:10:10 -070026#include <drm/drm_framework_common.h>
27#include <media/IDataSource.h>
28#include <media/mediametadataretriever.h>
Dongwon Kangd91dc5a2017-10-10 00:07:09 -070029#include <media/MediaSource.h>
Chong Zhangd3e0d862017-10-03 13:17:13 -070030#include <media/stagefright/foundation/ADebug.h>
Chong Zhangea280cb2017-08-02 11:10:10 -070031#include <private/media/VideoFrame.h>
32#include <utils/Log.h>
33#include <utils/RefBase.h>
Chong Zhang8541d302019-07-12 11:19:47 -070034#include <vector>
Chong Zhangea280cb2017-08-02 11:10:10 -070035
36HeifDecoder* createHeifDecoder() {
37 return new android::HeifDecoderImpl();
38}
39
40namespace android {
41
Chong Zhang8541d302019-07-12 11:19:47 -070042void initFrameInfo(HeifFrameInfo *info, const VideoFrame *videoFrame) {
43 info->mWidth = videoFrame->mWidth;
44 info->mHeight = videoFrame->mHeight;
45 info->mRotationAngle = videoFrame->mRotationAngle;
46 info->mBytesPerPixel = videoFrame->mBytesPerPixel;
47 // TODO: retrieve per-frame duration from extractor/metadataretriever.
48 info->mDurationUs = 33333;
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
Chong Zhangea280cb2017-08-02 11:10:10 -070059/*
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 */
65class HeifDataSource : public BnDataSource {
66public:
67 /*
68 * Constructs HeifDataSource; will take ownership of |stream|.
69 */
70 HeifDataSource(HeifStream* stream)
Chong Zhang3f3ffab2017-08-23 13:51:59 -070071 : mStream(stream), mEOS(false),
72 mCachedOffset(0), mCachedSize(0), mCacheBufferSize(0) {}
Chong Zhangea280cb2017-08-02 11:10:10 -070073
74 ~HeifDataSource() override {}
75
76 /*
77 * Initializes internal resources.
78 */
79 bool init();
80
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 ;
84 void close() {}
85 uint32_t getFlags() override { return 0; }
86 String8 toString() override { return String8("HeifDataSource"); }
87 sp<DecryptHandle> DrmInitialization(const char*) override {
88 return nullptr;
89 }
90
91private:
Chong Zhangea280cb2017-08-02 11:10:10 -070092 enum {
Chong Zhang3f3ffab2017-08-23 13:51:59 -070093 /*
94 * Buffer size for passing the read data to mediaserver. Set to 64K
95 * (which is what MediaDataSource Java API's jni implementation uses).
96 */
Chong Zhangea280cb2017-08-02 11:10:10 -070097 kBufferSize = 64 * 1024,
Chong Zhang3f3ffab2017-08-23 13:51:59 -070098 /*
99 * Initial and max cache buffer size.
100 */
101 kInitialCacheBufferSize = 4 * 1024 * 1024,
102 kMaxCacheBufferSize = 64 * 1024 * 1024,
Chong Zhangea280cb2017-08-02 11:10:10 -0700103 };
104 sp<IMemory> mMemory;
105 std::unique_ptr<HeifStream> mStream;
Chong Zhangea280cb2017-08-02 11:10:10 -0700106 bool mEOS;
Chong Zhangcd031922018-08-24 13:03:19 -0700107 std::unique_ptr<uint8_t[]> mCache;
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700108 off64_t mCachedOffset;
109 size_t mCachedSize;
110 size_t mCacheBufferSize;
Chong Zhangea280cb2017-08-02 11:10:10 -0700111};
112
113bool HeifDataSource::init() {
114 sp<MemoryDealer> memoryDealer =
115 new MemoryDealer(kBufferSize, "HeifDataSource");
116 mMemory = memoryDealer->allocate(kBufferSize);
117 if (mMemory == nullptr) {
118 ALOGE("Failed to allocate shared memory!");
119 return false;
120 }
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700121 mCache.reset(new uint8_t[kInitialCacheBufferSize]);
122 if (mCache.get() == nullptr) {
123 ALOGE("mFailed to allocate cache!");
124 return false;
125 }
126 mCacheBufferSize = kInitialCacheBufferSize;
Chong Zhangea280cb2017-08-02 11:10:10 -0700127 return true;
128}
129
130ssize_t HeifDataSource::readAt(off64_t offset, size_t size) {
131 ALOGV("readAt: offset=%lld, size=%zu", (long long)offset, size);
132
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700133 if (offset < mCachedOffset) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700134 // try seek, then rewind/skip, fail if none worked
135 if (mStream->seek(offset)) {
136 ALOGV("readAt: seek to offset=%lld", (long long)offset);
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700137 mCachedOffset = offset;
138 mCachedSize = 0;
Chong Zhangea280cb2017-08-02 11:10:10 -0700139 mEOS = false;
140 } else if (mStream->rewind()) {
141 ALOGV("readAt: rewind to offset=0");
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700142 mCachedOffset = 0;
143 mCachedSize = 0;
Chong Zhangea280cb2017-08-02 11:10:10 -0700144 mEOS = false;
145 } else {
146 ALOGE("readAt: couldn't seek or rewind!");
147 mEOS = true;
148 }
149 }
150
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700151 if (mEOS && (offset < mCachedOffset ||
152 offset >= (off64_t)(mCachedOffset + mCachedSize))) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700153 ALOGV("readAt: EOS");
154 return ERROR_END_OF_STREAM;
155 }
156
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700157 // at this point, offset must be >= mCachedOffset, other cases should
158 // have been caught above.
159 CHECK(offset >= mCachedOffset);
160
Sungtak Lee237f9032018-03-05 15:21:33 -0800161 off64_t resultOffset;
162 if (__builtin_add_overflow(offset, size, &resultOffset)) {
163 return ERROR_IO;
164 }
165
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700166 if (size == 0) {
167 return 0;
Chong Zhangea280cb2017-08-02 11:10:10 -0700168 }
169
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700170 // Can only read max of kBufferSize
Chong Zhangea280cb2017-08-02 11:10:10 -0700171 if (size > kBufferSize) {
172 size = kBufferSize;
173 }
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700174
175 // copy from cache if the request falls entirely in cache
176 if (offset + size <= mCachedOffset + mCachedSize) {
177 memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
178 return size;
179 }
180
181 // need to fetch more, check if we need to expand the cache buffer.
182 if ((off64_t)(offset + size) > mCachedOffset + kMaxCacheBufferSize) {
183 // it's reaching max cache buffer size, need to roll window, and possibly
184 // expand the cache buffer.
185 size_t newCacheBufferSize = mCacheBufferSize;
Chong Zhangcd031922018-08-24 13:03:19 -0700186 std::unique_ptr<uint8_t[]> newCache;
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700187 uint8_t* dst = mCache.get();
188 if (newCacheBufferSize < kMaxCacheBufferSize) {
189 newCacheBufferSize = kMaxCacheBufferSize;
190 newCache.reset(new uint8_t[newCacheBufferSize]);
191 dst = newCache.get();
192 }
193
194 // when rolling the cache window, try to keep about half the old bytes
195 // in case that the client goes back.
196 off64_t newCachedOffset = offset - (off64_t)(newCacheBufferSize / 2);
197 if (newCachedOffset < mCachedOffset) {
198 newCachedOffset = mCachedOffset;
199 }
200
201 int64_t newCachedSize = (int64_t)(mCachedOffset + mCachedSize) - newCachedOffset;
202 if (newCachedSize > 0) {
203 // in this case, the new cache region partially overlop the old cache,
204 // move the portion of the cache we want to save to the beginning of
205 // the cache buffer.
206 memcpy(dst, mCache.get() + newCachedOffset - mCachedOffset, newCachedSize);
207 } else if (newCachedSize < 0){
208 // in this case, the new cache region is entirely out of the old cache,
209 // in order to guarantee sequential read, we need to skip a number of
210 // bytes before reading.
211 size_t bytesToSkip = -newCachedSize;
212 size_t bytesSkipped = mStream->read(nullptr, bytesToSkip);
213 if (bytesSkipped != bytesToSkip) {
214 // bytesSkipped is invalid, there is not enough bytes to reach
215 // the requested offset.
216 ALOGE("readAt: skip failed, EOS");
217
218 mEOS = true;
219 mCachedOffset = newCachedOffset;
220 mCachedSize = 0;
221 return ERROR_END_OF_STREAM;
222 }
223 // set cache size to 0, since we're not keeping any old cache
224 newCachedSize = 0;
225 }
226
227 if (newCache.get() != nullptr) {
228 mCache.reset(newCache.release());
229 mCacheBufferSize = newCacheBufferSize;
230 }
231 mCachedOffset = newCachedOffset;
232 mCachedSize = newCachedSize;
233
234 ALOGV("readAt: rolling cache window to (%lld, %zu), cache buffer size %zu",
235 (long long)mCachedOffset, mCachedSize, mCacheBufferSize);
236 } else {
237 // expand cache buffer, but no need to roll the window
238 size_t newCacheBufferSize = mCacheBufferSize;
239 while (offset + size > mCachedOffset + newCacheBufferSize) {
240 newCacheBufferSize *= 2;
241 }
242 CHECK(newCacheBufferSize <= kMaxCacheBufferSize);
243 if (mCacheBufferSize < newCacheBufferSize) {
244 uint8_t* newCache = new uint8_t[newCacheBufferSize];
245 memcpy(newCache, mCache.get(), mCachedSize);
246 mCache.reset(newCache);
247 mCacheBufferSize = newCacheBufferSize;
248
249 ALOGV("readAt: current cache window (%lld, %zu), new cache buffer size %zu",
250 (long long) mCachedOffset, mCachedSize, mCacheBufferSize);
251 }
252 }
253 size_t bytesToRead = offset + size - mCachedOffset - mCachedSize;
254 size_t bytesRead = mStream->read(mCache.get() + mCachedSize, bytesToRead);
255 if (bytesRead > bytesToRead || bytesRead == 0) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700256 // bytesRead is invalid
257 mEOS = true;
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700258 bytesRead = 0;
259 } else if (bytesRead < bytesToRead) {
260 // read some bytes but not all, set EOS
Chong Zhangea280cb2017-08-02 11:10:10 -0700261 mEOS = true;
262 }
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700263 mCachedSize += bytesRead;
264 ALOGV("readAt: current cache window (%lld, %zu)",
265 (long long) mCachedOffset, mCachedSize);
266
267 // here bytesAvailable could be negative if offset jumped past EOS.
268 int64_t bytesAvailable = mCachedOffset + mCachedSize - offset;
269 if (bytesAvailable <= 0) {
270 return ERROR_END_OF_STREAM;
271 }
272 if (bytesAvailable < (int64_t)size) {
273 size = bytesAvailable;
274 }
275 memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
276 return size;
Chong Zhangea280cb2017-08-02 11:10:10 -0700277}
278
279status_t HeifDataSource::getSize(off64_t* size) {
280 if (!mStream->hasLength()) {
281 *size = -1;
282 ALOGE("getSize: not supported!");
283 return ERROR_UNSUPPORTED;
284 }
285 *size = mStream->getLength();
286 ALOGV("getSize: size=%lld", (long long)*size);
287 return OK;
288}
289
290/////////////////////////////////////////////////////////////////////////
291
Chong Zhang0c1407f2018-05-02 17:09:05 -0700292struct HeifDecoderImpl::DecodeThread : public Thread {
293 explicit DecodeThread(HeifDecoderImpl *decoder) : mDecoder(decoder) {}
294
295private:
296 HeifDecoderImpl* mDecoder;
297
298 bool threadLoop();
299
300 DISALLOW_EVIL_CONSTRUCTORS(DecodeThread);
301};
302
303bool HeifDecoderImpl::DecodeThread::threadLoop() {
304 return mDecoder->decodeAsync();
305}
306
307/////////////////////////////////////////////////////////////////////////
308
Chong Zhangea280cb2017-08-02 11:10:10 -0700309HeifDecoderImpl::HeifDecoderImpl() :
310 // output color format should always be set via setOutputColor(), in case
311 // it's not, default to HAL_PIXEL_FORMAT_RGB_565.
312 mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700313 mCurScanline(0),
Chong Zhang8541d302019-07-12 11:19:47 -0700314 mTotalScanline(0),
Chong Zhangd3e0d862017-10-03 13:17:13 -0700315 mFrameDecoded(false),
316 mHasImage(false),
Chong Zhang0c1407f2018-05-02 17:09:05 -0700317 mHasVideo(false),
Chong Zhang8541d302019-07-12 11:19:47 -0700318 mSequenceLength(0),
Chong Zhang0c1407f2018-05-02 17:09:05 -0700319 mAvailableLines(0),
320 mNumSlices(1),
321 mSliceHeight(0),
322 mAsyncDecodeDone(false) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700323}
324
325HeifDecoderImpl::~HeifDecoderImpl() {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700326 if (mThread != nullptr) {
327 mThread->join();
328 }
Chong Zhangea280cb2017-08-02 11:10:10 -0700329}
330
331bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700332 mFrameDecoded = false;
Chong Zhangd3e0d862017-10-03 13:17:13 -0700333 mFrameMemory.clear();
334
Chong Zhangea280cb2017-08-02 11:10:10 -0700335 sp<HeifDataSource> dataSource = new HeifDataSource(stream);
336 if (!dataSource->init()) {
337 return false;
338 }
339 mDataSource = dataSource;
340
341 mRetriever = new MediaMetadataRetriever();
Chong Zhangd3e0d862017-10-03 13:17:13 -0700342 status_t err = mRetriever->setDataSource(mDataSource, "image/heif");
Chong Zhangea280cb2017-08-02 11:10:10 -0700343 if (err != OK) {
344 ALOGE("failed to set data source!");
345
346 mRetriever.clear();
347 mDataSource.clear();
348 return false;
349 }
350 ALOGV("successfully set data source.");
351
Chong Zhangd3e0d862017-10-03 13:17:13 -0700352 const char* hasImage = mRetriever->extractMetadata(METADATA_KEY_HAS_IMAGE);
Chong Zhangea280cb2017-08-02 11:10:10 -0700353 const char* hasVideo = mRetriever->extractMetadata(METADATA_KEY_HAS_VIDEO);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700354
355 mHasImage = hasImage && !strcasecmp(hasImage, "yes");
356 mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
Chong Zhang8541d302019-07-12 11:19:47 -0700357
358 HeifFrameInfo* defaultInfo = nullptr;
Chong Zhangd3e0d862017-10-03 13:17:13 -0700359 if (mHasImage) {
360 // image index < 0 to retrieve primary image
Chong Zhang8541d302019-07-12 11:19:47 -0700361 sp<IMemory> sharedMem = mRetriever->getImageAtIndex(
Chong Zhangd3e0d862017-10-03 13:17:13 -0700362 -1, mOutputColor, true /*metaOnly*/);
Chong Zhang8541d302019-07-12 11:19:47 -0700363
364 if (sharedMem == nullptr || sharedMem->pointer() == nullptr) {
365 ALOGE("init: videoFrame is a nullptr");
366 return false;
367 }
368
369 VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->pointer());
370
371 ALOGV("Image dimension %dx%d, display %dx%d, angle %d, iccSize %d",
372 videoFrame->mWidth,
373 videoFrame->mHeight,
374 videoFrame->mDisplayWidth,
375 videoFrame->mDisplayHeight,
376 videoFrame->mRotationAngle,
377 videoFrame->mIccSize);
378
379 initFrameInfo(&mImageInfo, videoFrame);
380
381 if (videoFrame->mTileHeight >= 512) {
382 // Try decoding in slices only if the image has tiles and is big enough.
383 mSliceHeight = videoFrame->mTileHeight;
384 ALOGV("mSliceHeight %u", mSliceHeight);
385 }
386
387 defaultInfo = &mImageInfo;
Chong Zhangea280cb2017-08-02 11:10:10 -0700388 }
389
Chong Zhang8541d302019-07-12 11:19:47 -0700390 if (mHasVideo) {
391 sp<IMemory> sharedMem = mRetriever->getFrameAtTime(0,
392 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
393 mOutputColor, true /*metaOnly*/);
394
395 if (sharedMem == nullptr || sharedMem->pointer() == nullptr) {
396 ALOGE("init: videoFrame is a nullptr");
397 return false;
398 }
399
400 VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->pointer());
401
402 ALOGV("Sequence dimension %dx%d, display %dx%d, angle %d, iccSize %d",
403 videoFrame->mWidth,
404 videoFrame->mHeight,
405 videoFrame->mDisplayWidth,
406 videoFrame->mDisplayHeight,
407 videoFrame->mRotationAngle,
408 videoFrame->mIccSize);
409
410 initFrameInfo(&mSequenceInfo, videoFrame);
411
412 mSequenceLength = atoi(mRetriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT));
413
414 if (defaultInfo == nullptr) {
415 defaultInfo = &mSequenceInfo;
416 }
417 }
418
419 if (defaultInfo == nullptr) {
420 ALOGD("No valid image or sequence available");
Chong Zhangea280cb2017-08-02 11:10:10 -0700421 return false;
422 }
423
Chong Zhangea280cb2017-08-02 11:10:10 -0700424 if (frameInfo != nullptr) {
Chong Zhang8541d302019-07-12 11:19:47 -0700425 *frameInfo = *defaultInfo;
Chong Zhangea280cb2017-08-02 11:10:10 -0700426 }
Chong Zhang8541d302019-07-12 11:19:47 -0700427
428 // default total scanline, this might change if decodeSequence() is used
429 mTotalScanline = defaultInfo->mHeight;
430
431 return true;
432}
433
434bool HeifDecoderImpl::getSequenceInfo(
435 HeifFrameInfo* frameInfo, size_t *frameCount) {
436 ALOGV("%s", __FUNCTION__);
437 if (!mHasVideo) {
438 return false;
439 }
440 if (frameInfo != nullptr) {
441 *frameInfo = mSequenceInfo;
442 }
443 if (frameCount != nullptr) {
444 *frameCount = mSequenceLength;
Chong Zhang0c1407f2018-05-02 17:09:05 -0700445 }
Chong Zhangea280cb2017-08-02 11:10:10 -0700446 return true;
447}
448
449bool HeifDecoderImpl::getEncodedColor(HeifEncodedColor* /*outColor*/) const {
450 ALOGW("getEncodedColor: not implemented!");
451 return false;
452}
453
454bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) {
455 switch(heifColor) {
456 case kHeifColorFormat_RGB565:
457 {
458 mOutputColor = HAL_PIXEL_FORMAT_RGB_565;
459 return true;
460 }
461 case kHeifColorFormat_RGBA_8888:
462 {
463 mOutputColor = HAL_PIXEL_FORMAT_RGBA_8888;
464 return true;
465 }
466 case kHeifColorFormat_BGRA_8888:
467 {
468 mOutputColor = HAL_PIXEL_FORMAT_BGRA_8888;
469 return true;
470 }
471 default:
472 break;
473 }
474 ALOGE("Unsupported output color format %d", heifColor);
475 return false;
476}
477
Chong Zhang0c1407f2018-05-02 17:09:05 -0700478bool HeifDecoderImpl::decodeAsync() {
479 for (size_t i = 1; i < mNumSlices; i++) {
480 ALOGV("decodeAsync(): decoding slice %zu", i);
481 size_t top = i * mSliceHeight;
482 size_t bottom = (i + 1) * mSliceHeight;
Chong Zhang8541d302019-07-12 11:19:47 -0700483 if (bottom > mImageInfo.mHeight) {
484 bottom = mImageInfo.mHeight;
Chong Zhang0c1407f2018-05-02 17:09:05 -0700485 }
486 sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
Chong Zhang8541d302019-07-12 11:19:47 -0700487 -1, mOutputColor, 0, top, mImageInfo.mWidth, bottom);
Chong Zhang0c1407f2018-05-02 17:09:05 -0700488 {
489 Mutex::Autolock autolock(mLock);
490
491 if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
492 mAsyncDecodeDone = true;
493 mScanlineReady.signal();
494 break;
495 }
496 mFrameMemory = frameMemory;
497 mAvailableLines = bottom;
498 ALOGV("decodeAsync(): available lines %zu", mAvailableLines);
499 mScanlineReady.signal();
500 }
501 }
502 // Aggressive clear to avoid holding on to resources
503 mRetriever.clear();
504 mDataSource.clear();
505 return false;
506}
507
Chong Zhangea280cb2017-08-02 11:10:10 -0700508bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) {
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700509 // reset scanline pointer
510 mCurScanline = 0;
511
512 if (mFrameDecoded) {
513 return true;
514 }
515
Chong Zhang0c1407f2018-05-02 17:09:05 -0700516 // See if we want to decode in slices to allow client to start
517 // scanline processing in parallel with decode. If this fails
518 // we fallback to decoding the full frame.
Chong Zhang8541d302019-07-12 11:19:47 -0700519 if (mHasImage) {
520 if (mSliceHeight >= 512 &&
521 mImageInfo.mWidth >= 3000 &&
522 mImageInfo.mHeight >= 2000 ) {
523 // Try decoding in slices only if the image has tiles and is big enough.
524 mNumSlices = (mImageInfo.mHeight + mSliceHeight - 1) / mSliceHeight;
525 ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
Chong Zhang0c1407f2018-05-02 17:09:05 -0700526 }
527
Chong Zhang8541d302019-07-12 11:19:47 -0700528 if (mNumSlices > 1) {
529 // get first slice and metadata
530 sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
531 -1, mOutputColor, 0, 0, mImageInfo.mWidth, mSliceHeight);
Chong Zhang0c1407f2018-05-02 17:09:05 -0700532
Chong Zhang8541d302019-07-12 11:19:47 -0700533 if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
534 ALOGE("decode: metadata is a nullptr");
535 return false;
536 }
537
538 VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->pointer());
539
540 if (frameInfo != nullptr) {
541 initFrameInfo(frameInfo, videoFrame);
542 }
543 mFrameMemory = frameMemory;
544 mAvailableLines = mSliceHeight;
545 mThread = new DecodeThread(this);
546 if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
547 mFrameDecoded = true;
548 return true;
549 }
550 // Fallback to decode without slicing
551 mThread.clear();
552 mNumSlices = 1;
553 mSliceHeight = 0;
554 mAvailableLines = 0;
555 mFrameMemory.clear();
Chong Zhang0c1407f2018-05-02 17:09:05 -0700556 }
Chong Zhang0c1407f2018-05-02 17:09:05 -0700557 }
558
Chong Zhangd3e0d862017-10-03 13:17:13 -0700559 if (mHasImage) {
560 // image index < 0 to retrieve primary image
561 mFrameMemory = mRetriever->getImageAtIndex(-1, mOutputColor);
562 } else if (mHasVideo) {
563 mFrameMemory = mRetriever->getFrameAtTime(0,
564 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
565 }
566
Chong Zhangea280cb2017-08-02 11:10:10 -0700567 if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700568 ALOGE("decode: videoFrame is a nullptr");
Chong Zhangea280cb2017-08-02 11:10:10 -0700569 return false;
570 }
571
572 VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700573 if (videoFrame->mSize == 0 ||
574 mFrameMemory->size() < videoFrame->getFlattenedSize()) {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700575 ALOGE("decode: videoFrame size is invalid");
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700576 return false;
577 }
578
Chong Zhangea280cb2017-08-02 11:10:10 -0700579 ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
580 videoFrame->mWidth,
581 videoFrame->mHeight,
582 videoFrame->mDisplayWidth,
583 videoFrame->mDisplayHeight,
584 videoFrame->mRotationAngle,
585 videoFrame->mRowBytes,
586 videoFrame->mSize);
587
588 if (frameInfo != nullptr) {
Chong Zhang8541d302019-07-12 11:19:47 -0700589 initFrameInfo(frameInfo, videoFrame);
590
Chong Zhangea280cb2017-08-02 11:10:10 -0700591 }
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700592 mFrameDecoded = true;
Chong Zhang4c6398b2017-09-07 17:43:19 -0700593
Chong Zhang0c1407f2018-05-02 17:09:05 -0700594 // Aggressively clear to avoid holding on to resources
Chong Zhang4c6398b2017-09-07 17:43:19 -0700595 mRetriever.clear();
596 mDataSource.clear();
Chong Zhangea280cb2017-08-02 11:10:10 -0700597 return true;
598}
599
Chong Zhang8541d302019-07-12 11:19:47 -0700600bool HeifDecoderImpl::decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) {
601 ALOGV("%s: frame index %d", __FUNCTION__, frameIndex);
602 if (!mHasVideo) {
603 return false;
604 }
605
606 if (frameIndex < 0 || frameIndex >= mSequenceLength) {
607 ALOGE("invalid frame index: %d, total frames %zu", frameIndex, mSequenceLength);
608 return false;
609 }
610
611 mCurScanline = 0;
612
613 // set total scanline to sequence height now
614 mTotalScanline = mSequenceInfo.mHeight;
615
616 mFrameMemory = mRetriever->getFrameAtIndex(frameIndex, mOutputColor);
617 if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
618 ALOGE("decode: videoFrame is a nullptr");
619 return false;
620 }
621
622 VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
623 if (videoFrame->mSize == 0 ||
624 mFrameMemory->size() < videoFrame->getFlattenedSize()) {
625 ALOGE("decode: videoFrame size is invalid");
626 return false;
627 }
628
629 ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
630 videoFrame->mWidth,
631 videoFrame->mHeight,
632 videoFrame->mDisplayWidth,
633 videoFrame->mDisplayHeight,
634 videoFrame->mRotationAngle,
635 videoFrame->mRowBytes,
636 videoFrame->mSize);
637
638 if (frameInfo != nullptr) {
639 initFrameInfo(frameInfo, videoFrame);
640 }
641 return true;
642}
643
Chong Zhang0c1407f2018-05-02 17:09:05 -0700644bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700645 if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
646 return false;
647 }
648 VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
Chong Zhangea280cb2017-08-02 11:10:10 -0700649 uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++;
Chong Zhang70b0afd2018-02-27 12:43:06 -0800650 memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth);
Chong Zhangea280cb2017-08-02 11:10:10 -0700651 return true;
652}
653
Chong Zhang0c1407f2018-05-02 17:09:05 -0700654bool HeifDecoderImpl::getScanline(uint8_t* dst) {
Chong Zhang8541d302019-07-12 11:19:47 -0700655 if (mCurScanline >= mTotalScanline) {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700656 ALOGE("no more scanline available");
657 return false;
Chong Zhangea280cb2017-08-02 11:10:10 -0700658 }
Chong Zhangea280cb2017-08-02 11:10:10 -0700659
Chong Zhang0c1407f2018-05-02 17:09:05 -0700660 if (mNumSlices > 1) {
661 Mutex::Autolock autolock(mLock);
662
663 while (!mAsyncDecodeDone && mCurScanline >= mAvailableLines) {
664 mScanlineReady.wait(mLock);
665 }
666 return (mCurScanline < mAvailableLines) ? getScanlineInner(dst) : false;
667 }
668
669 return getScanlineInner(dst);
670}
671
672size_t HeifDecoderImpl::skipScanlines(size_t count) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700673 uint32_t oldScanline = mCurScanline;
674 mCurScanline += count;
Chong Zhang8541d302019-07-12 11:19:47 -0700675 if (mCurScanline > mTotalScanline) {
676 mCurScanline = mTotalScanline;
Chong Zhangea280cb2017-08-02 11:10:10 -0700677 }
678 return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
679}
680
681} // namespace android