blob: 7c7890001dd5a3db36a9b2150b3c406d807f4f94 [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
Liz Kammer3ec5a0b2021-07-21 09:30:07 -040018#include "include/HeifDecoderAPI.h"
Chong Zhangea280cb2017-08-02 11:10:10 -070019#define LOG_TAG "HeifDecoderImpl"
20
21#include "HeifDecoderImpl.h"
22
23#include <stdio.h>
24
Marco Nelissendab79b32019-11-18 08:25:47 -080025#include <android/IDataSource.h>
Chong Zhangea280cb2017-08-02 11:10:10 -070026#include <binder/IMemory.h>
Dongwon Kang49ce6712018-01-24 10:16:25 -080027#include <binder/MemoryDealer.h>
Chong Zhangea280cb2017-08-02 11:10:10 -070028#include <drm/drm_framework_common.h>
Ray Essicke89e6322022-02-02 13:33:50 -080029#include <log/log.h>
Chong Zhangea280cb2017-08-02 11:10:10 -070030#include <media/mediametadataretriever.h>
Marco Nelissen7291da62019-12-17 13:01:55 -080031#include <media/stagefright/MediaSource.h>
Chong Zhangd3e0d862017-10-03 13:17:13 -070032#include <media/stagefright/foundation/ADebug.h>
Chong Zhangea280cb2017-08-02 11:10:10 -070033#include <private/media/VideoFrame.h>
34#include <utils/Log.h>
35#include <utils/RefBase.h>
Chong Zhang8541d302019-07-12 11:19:47 -070036#include <vector>
Chong Zhangea280cb2017-08-02 11:10:10 -070037
38HeifDecoder* createHeifDecoder() {
39 return new android::HeifDecoderImpl();
40}
41
42namespace android {
43
Chong Zhang8541d302019-07-12 11:19:47 -070044void initFrameInfo(HeifFrameInfo *info, const VideoFrame *videoFrame) {
45 info->mWidth = videoFrame->mWidth;
46 info->mHeight = videoFrame->mHeight;
47 info->mRotationAngle = videoFrame->mRotationAngle;
48 info->mBytesPerPixel = videoFrame->mBytesPerPixel;
Chong Zhang0af4db62019-08-23 15:34:58 -070049 info->mDurationUs = videoFrame->mDurationUs;
Dichen Zhangf4066492022-02-17 17:32:53 -080050 info->mBitDepth = videoFrame->mBitDepth;
Chong Zhang8541d302019-07-12 11:19:47 -070051 if (videoFrame->mIccSize > 0) {
52 info->mIccData.assign(
53 videoFrame->getFlattenedIccData(),
54 videoFrame->getFlattenedIccData() + videoFrame->mIccSize);
55 } else {
56 // clear old Icc data if there is no Icc data.
57 info->mIccData.clear();
58 }
59}
60
Chong Zhangea280cb2017-08-02 11:10:10 -070061/*
62 * HeifDataSource
63 *
64 * Proxies data requests over IDataSource interface from MediaMetadataRetriever
65 * to the HeifStream interface we received from the heif decoder client.
66 */
67class HeifDataSource : public BnDataSource {
68public:
69 /*
70 * Constructs HeifDataSource; will take ownership of |stream|.
71 */
72 HeifDataSource(HeifStream* stream)
Chong Zhang3f3ffab2017-08-23 13:51:59 -070073 : mStream(stream), mEOS(false),
74 mCachedOffset(0), mCachedSize(0), mCacheBufferSize(0) {}
Chong Zhangea280cb2017-08-02 11:10:10 -070075
76 ~HeifDataSource() override {}
77
78 /*
79 * Initializes internal resources.
80 */
81 bool init();
82
83 sp<IMemory> getIMemory() override { return mMemory; }
84 ssize_t readAt(off64_t offset, size_t size) override;
85 status_t getSize(off64_t* size) override ;
86 void close() {}
87 uint32_t getFlags() override { return 0; }
88 String8 toString() override { return String8("HeifDataSource"); }
Chong Zhangea280cb2017-08-02 11:10:10 -070089
90private:
Chong Zhangea280cb2017-08-02 11:10:10 -070091 enum {
Chong Zhang3f3ffab2017-08-23 13:51:59 -070092 /*
93 * Buffer size for passing the read data to mediaserver. Set to 64K
94 * (which is what MediaDataSource Java API's jni implementation uses).
95 */
Chong Zhangea280cb2017-08-02 11:10:10 -070096 kBufferSize = 64 * 1024,
Chong Zhang3f3ffab2017-08-23 13:51:59 -070097 /*
98 * Initial and max cache buffer size.
99 */
100 kInitialCacheBufferSize = 4 * 1024 * 1024,
101 kMaxCacheBufferSize = 64 * 1024 * 1024,
Chong Zhangea280cb2017-08-02 11:10:10 -0700102 };
103 sp<IMemory> mMemory;
104 std::unique_ptr<HeifStream> mStream;
Chong Zhangea280cb2017-08-02 11:10:10 -0700105 bool mEOS;
Chong Zhangcd031922018-08-24 13:03:19 -0700106 std::unique_ptr<uint8_t[]> mCache;
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700107 off64_t mCachedOffset;
108 size_t mCachedSize;
109 size_t mCacheBufferSize;
Chong Zhangea280cb2017-08-02 11:10:10 -0700110};
111
112bool HeifDataSource::init() {
113 sp<MemoryDealer> memoryDealer =
114 new MemoryDealer(kBufferSize, "HeifDataSource");
115 mMemory = memoryDealer->allocate(kBufferSize);
116 if (mMemory == nullptr) {
117 ALOGE("Failed to allocate shared memory!");
118 return false;
119 }
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700120 mCache.reset(new uint8_t[kInitialCacheBufferSize]);
121 if (mCache.get() == nullptr) {
122 ALOGE("mFailed to allocate cache!");
123 return false;
124 }
125 mCacheBufferSize = kInitialCacheBufferSize;
Chong Zhangea280cb2017-08-02 11:10:10 -0700126 return true;
127}
128
129ssize_t HeifDataSource::readAt(off64_t offset, size_t size) {
130 ALOGV("readAt: offset=%lld, size=%zu", (long long)offset, size);
131
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700132 if (offset < mCachedOffset) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700133 // try seek, then rewind/skip, fail if none worked
134 if (mStream->seek(offset)) {
135 ALOGV("readAt: seek to offset=%lld", (long long)offset);
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700136 mCachedOffset = offset;
137 mCachedSize = 0;
Chong Zhangea280cb2017-08-02 11:10:10 -0700138 mEOS = false;
139 } else if (mStream->rewind()) {
140 ALOGV("readAt: rewind to offset=0");
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700141 mCachedOffset = 0;
142 mCachedSize = 0;
Chong Zhangea280cb2017-08-02 11:10:10 -0700143 mEOS = false;
144 } else {
145 ALOGE("readAt: couldn't seek or rewind!");
146 mEOS = true;
147 }
148 }
149
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700150 if (mEOS && (offset < mCachedOffset ||
151 offset >= (off64_t)(mCachedOffset + mCachedSize))) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700152 ALOGV("readAt: EOS");
153 return ERROR_END_OF_STREAM;
154 }
155
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700156 // at this point, offset must be >= mCachedOffset, other cases should
157 // have been caught above.
158 CHECK(offset >= mCachedOffset);
159
Sungtak Lee237f9032018-03-05 15:21:33 -0800160 off64_t resultOffset;
161 if (__builtin_add_overflow(offset, size, &resultOffset)) {
162 return ERROR_IO;
163 }
164
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700165 if (size == 0) {
166 return 0;
Chong Zhangea280cb2017-08-02 11:10:10 -0700167 }
168
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700169 // Can only read max of kBufferSize
Chong Zhangea280cb2017-08-02 11:10:10 -0700170 if (size > kBufferSize) {
171 size = kBufferSize;
172 }
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700173
174 // copy from cache if the request falls entirely in cache
175 if (offset + size <= mCachedOffset + mCachedSize) {
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700176 memcpy(mMemory->unsecurePointer(), mCache.get() + offset - mCachedOffset, size);
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700177 return size;
178 }
179
180 // need to fetch more, check if we need to expand the cache buffer.
181 if ((off64_t)(offset + size) > mCachedOffset + kMaxCacheBufferSize) {
182 // it's reaching max cache buffer size, need to roll window, and possibly
183 // expand the cache buffer.
184 size_t newCacheBufferSize = mCacheBufferSize;
Chong Zhangcd031922018-08-24 13:03:19 -0700185 std::unique_ptr<uint8_t[]> newCache;
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700186 uint8_t* dst = mCache.get();
187 if (newCacheBufferSize < kMaxCacheBufferSize) {
188 newCacheBufferSize = kMaxCacheBufferSize;
189 newCache.reset(new uint8_t[newCacheBufferSize]);
190 dst = newCache.get();
191 }
192
193 // when rolling the cache window, try to keep about half the old bytes
194 // in case that the client goes back.
195 off64_t newCachedOffset = offset - (off64_t)(newCacheBufferSize / 2);
196 if (newCachedOffset < mCachedOffset) {
197 newCachedOffset = mCachedOffset;
198 }
199
200 int64_t newCachedSize = (int64_t)(mCachedOffset + mCachedSize) - newCachedOffset;
201 if (newCachedSize > 0) {
202 // in this case, the new cache region partially overlop the old cache,
203 // move the portion of the cache we want to save to the beginning of
204 // the cache buffer.
205 memcpy(dst, mCache.get() + newCachedOffset - mCachedOffset, newCachedSize);
206 } else if (newCachedSize < 0){
207 // in this case, the new cache region is entirely out of the old cache,
208 // in order to guarantee sequential read, we need to skip a number of
209 // bytes before reading.
210 size_t bytesToSkip = -newCachedSize;
211 size_t bytesSkipped = mStream->read(nullptr, bytesToSkip);
212 if (bytesSkipped != bytesToSkip) {
213 // bytesSkipped is invalid, there is not enough bytes to reach
214 // the requested offset.
215 ALOGE("readAt: skip failed, EOS");
216
217 mEOS = true;
218 mCachedOffset = newCachedOffset;
219 mCachedSize = 0;
220 return ERROR_END_OF_STREAM;
221 }
222 // set cache size to 0, since we're not keeping any old cache
223 newCachedSize = 0;
224 }
225
226 if (newCache.get() != nullptr) {
227 mCache.reset(newCache.release());
228 mCacheBufferSize = newCacheBufferSize;
229 }
230 mCachedOffset = newCachedOffset;
231 mCachedSize = newCachedSize;
232
233 ALOGV("readAt: rolling cache window to (%lld, %zu), cache buffer size %zu",
234 (long long)mCachedOffset, mCachedSize, mCacheBufferSize);
235 } else {
236 // expand cache buffer, but no need to roll the window
237 size_t newCacheBufferSize = mCacheBufferSize;
238 while (offset + size > mCachedOffset + newCacheBufferSize) {
239 newCacheBufferSize *= 2;
240 }
241 CHECK(newCacheBufferSize <= kMaxCacheBufferSize);
242 if (mCacheBufferSize < newCacheBufferSize) {
243 uint8_t* newCache = new uint8_t[newCacheBufferSize];
244 memcpy(newCache, mCache.get(), mCachedSize);
245 mCache.reset(newCache);
246 mCacheBufferSize = newCacheBufferSize;
247
248 ALOGV("readAt: current cache window (%lld, %zu), new cache buffer size %zu",
249 (long long) mCachedOffset, mCachedSize, mCacheBufferSize);
250 }
251 }
252 size_t bytesToRead = offset + size - mCachedOffset - mCachedSize;
253 size_t bytesRead = mStream->read(mCache.get() + mCachedSize, bytesToRead);
254 if (bytesRead > bytesToRead || bytesRead == 0) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700255 // bytesRead is invalid
256 mEOS = true;
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700257 bytesRead = 0;
258 } else if (bytesRead < bytesToRead) {
259 // read some bytes but not all, set EOS
Chong Zhangea280cb2017-08-02 11:10:10 -0700260 mEOS = true;
261 }
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700262 mCachedSize += bytesRead;
263 ALOGV("readAt: current cache window (%lld, %zu)",
264 (long long) mCachedOffset, mCachedSize);
265
266 // here bytesAvailable could be negative if offset jumped past EOS.
267 int64_t bytesAvailable = mCachedOffset + mCachedSize - offset;
268 if (bytesAvailable <= 0) {
269 return ERROR_END_OF_STREAM;
270 }
271 if (bytesAvailable < (int64_t)size) {
272 size = bytesAvailable;
273 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700274 memcpy(mMemory->unsecurePointer(), mCache.get() + offset - mCachedOffset, size);
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700275 return size;
Chong Zhangea280cb2017-08-02 11:10:10 -0700276}
277
278status_t HeifDataSource::getSize(off64_t* size) {
279 if (!mStream->hasLength()) {
280 *size = -1;
281 ALOGE("getSize: not supported!");
282 return ERROR_UNSUPPORTED;
283 }
284 *size = mStream->getLength();
285 ALOGV("getSize: size=%lld", (long long)*size);
286 return OK;
287}
288
289/////////////////////////////////////////////////////////////////////////
290
Chong Zhang0c1407f2018-05-02 17:09:05 -0700291struct HeifDecoderImpl::DecodeThread : public Thread {
292 explicit DecodeThread(HeifDecoderImpl *decoder) : mDecoder(decoder) {}
293
294private:
295 HeifDecoderImpl* mDecoder;
296
297 bool threadLoop();
298
299 DISALLOW_EVIL_CONSTRUCTORS(DecodeThread);
300};
301
302bool HeifDecoderImpl::DecodeThread::threadLoop() {
303 return mDecoder->decodeAsync();
304}
305
306/////////////////////////////////////////////////////////////////////////
307
Chong Zhangea280cb2017-08-02 11:10:10 -0700308HeifDecoderImpl::HeifDecoderImpl() :
309 // output color format should always be set via setOutputColor(), in case
310 // it's not, default to HAL_PIXEL_FORMAT_RGB_565.
311 mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700312 mCurScanline(0),
Chong Zhang8541d302019-07-12 11:19:47 -0700313 mTotalScanline(0),
Chong Zhangd3e0d862017-10-03 13:17:13 -0700314 mFrameDecoded(false),
315 mHasImage(false),
Chong Zhang0c1407f2018-05-02 17:09:05 -0700316 mHasVideo(false),
Chong Zhang8541d302019-07-12 11:19:47 -0700317 mSequenceLength(0),
Chong Zhang0c1407f2018-05-02 17:09:05 -0700318 mAvailableLines(0),
319 mNumSlices(1),
320 mSliceHeight(0),
321 mAsyncDecodeDone(false) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700322}
323
324HeifDecoderImpl::~HeifDecoderImpl() {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700325 if (mThread != nullptr) {
326 mThread->join();
327 }
Chong Zhangea280cb2017-08-02 11:10:10 -0700328}
329
330bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700331 mFrameDecoded = false;
Chong Zhangd3e0d862017-10-03 13:17:13 -0700332 mFrameMemory.clear();
333
Chong Zhangea280cb2017-08-02 11:10:10 -0700334 sp<HeifDataSource> dataSource = new HeifDataSource(stream);
335 if (!dataSource->init()) {
336 return false;
337 }
338 mDataSource = dataSource;
339
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500340 return reinit(frameInfo);
341}
342
343bool HeifDecoderImpl::reinit(HeifFrameInfo* frameInfo) {
344 mFrameDecoded = false;
345 mFrameMemory.clear();
346
Dichen Zhang92e51072022-06-08 18:26:37 -0700347 sp<MediaMetadataRetriever> retriever = new MediaMetadataRetriever();
348 status_t err = retriever->setDataSource(mDataSource, "image/heif");
Chong Zhangea280cb2017-08-02 11:10:10 -0700349 if (err != OK) {
350 ALOGE("failed to set data source!");
Chong Zhangea280cb2017-08-02 11:10:10 -0700351 mRetriever.clear();
352 mDataSource.clear();
353 return false;
354 }
Dichen Zhang92e51072022-06-08 18:26:37 -0700355 {
356 Mutex::Autolock _l(mRetrieverLock);
357 mRetriever = retriever;
358 }
Chong Zhangea280cb2017-08-02 11:10:10 -0700359 ALOGV("successfully set data source.");
360
Dichen Zhang92e51072022-06-08 18:26:37 -0700361 const char* hasImage = retriever->extractMetadata(METADATA_KEY_HAS_IMAGE);
362 const char* hasVideo = retriever->extractMetadata(METADATA_KEY_HAS_VIDEO);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700363
364 mHasImage = hasImage && !strcasecmp(hasImage, "yes");
365 mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
Chong Zhang8541d302019-07-12 11:19:47 -0700366
367 HeifFrameInfo* defaultInfo = nullptr;
Chong Zhangd3e0d862017-10-03 13:17:13 -0700368 if (mHasImage) {
369 // image index < 0 to retrieve primary image
Dichen Zhang92e51072022-06-08 18:26:37 -0700370 sp<IMemory> sharedMem = retriever->getImageAtIndex(
Chong Zhangd3e0d862017-10-03 13:17:13 -0700371 -1, mOutputColor, true /*metaOnly*/);
Chong Zhang8541d302019-07-12 11:19:47 -0700372
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700373 if (sharedMem == nullptr || sharedMem->unsecurePointer() == nullptr) {
Chong Zhang8541d302019-07-12 11:19:47 -0700374 ALOGE("init: videoFrame is a nullptr");
375 return false;
376 }
377
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700378 // TODO: Using unsecurePointer() has some associated security pitfalls
379 // (see declaration for details).
380 // Either document why it is safe in this case or address the
381 // issue (e.g. by copying).
382 VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->unsecurePointer());
Chong Zhang8541d302019-07-12 11:19:47 -0700383
Dichen Zhangf4066492022-02-17 17:32:53 -0800384 ALOGV("Image dimension %dx%d, display %dx%d, angle %d, iccSize %d, bitDepth %d",
Chong Zhang8541d302019-07-12 11:19:47 -0700385 videoFrame->mWidth,
386 videoFrame->mHeight,
387 videoFrame->mDisplayWidth,
388 videoFrame->mDisplayHeight,
389 videoFrame->mRotationAngle,
Dichen Zhangf4066492022-02-17 17:32:53 -0800390 videoFrame->mIccSize,
391 videoFrame->mBitDepth);
Chong Zhang8541d302019-07-12 11:19:47 -0700392
393 initFrameInfo(&mImageInfo, videoFrame);
394
395 if (videoFrame->mTileHeight >= 512) {
396 // Try decoding in slices only if the image has tiles and is big enough.
397 mSliceHeight = videoFrame->mTileHeight;
398 ALOGV("mSliceHeight %u", mSliceHeight);
399 }
400
401 defaultInfo = &mImageInfo;
Chong Zhangea280cb2017-08-02 11:10:10 -0700402 }
403
Chong Zhang8541d302019-07-12 11:19:47 -0700404 if (mHasVideo) {
Dichen Zhang92e51072022-06-08 18:26:37 -0700405 sp<IMemory> sharedMem = retriever->getFrameAtTime(0,
Chong Zhang8541d302019-07-12 11:19:47 -0700406 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
407 mOutputColor, true /*metaOnly*/);
408
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700409 if (sharedMem == nullptr || sharedMem->unsecurePointer() == nullptr) {
Chong Zhang8541d302019-07-12 11:19:47 -0700410 ALOGE("init: videoFrame is a nullptr");
411 return false;
412 }
413
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700414 // TODO: Using unsecurePointer() has some associated security pitfalls
415 // (see declaration for details).
416 // Either document why it is safe in this case or address the
417 // issue (e.g. by copying).
418 VideoFrame* videoFrame = static_cast<VideoFrame*>(
419 sharedMem->unsecurePointer());
Chong Zhang8541d302019-07-12 11:19:47 -0700420
421 ALOGV("Sequence dimension %dx%d, display %dx%d, angle %d, iccSize %d",
422 videoFrame->mWidth,
423 videoFrame->mHeight,
424 videoFrame->mDisplayWidth,
425 videoFrame->mDisplayHeight,
426 videoFrame->mRotationAngle,
427 videoFrame->mIccSize);
428
429 initFrameInfo(&mSequenceInfo, videoFrame);
430
Dichen Zhang92e51072022-06-08 18:26:37 -0700431 const char* frameCount = retriever->extractMetadata(METADATA_KEY_VIDEO_FRAME_COUNT);
Ray Essicke89e6322022-02-02 13:33:50 -0800432 if (frameCount == nullptr) {
433 android_errorWriteWithInfoLog(0x534e4554, "215002587", -1, NULL, 0);
434 ALOGD("No valid sequence information in metadata");
435 return false;
436 }
437 mSequenceLength = atoi(frameCount);
Chong Zhang8541d302019-07-12 11:19:47 -0700438
439 if (defaultInfo == nullptr) {
440 defaultInfo = &mSequenceInfo;
441 }
442 }
443
444 if (defaultInfo == nullptr) {
445 ALOGD("No valid image or sequence available");
Chong Zhangea280cb2017-08-02 11:10:10 -0700446 return false;
447 }
448
Chong Zhangea280cb2017-08-02 11:10:10 -0700449 if (frameInfo != nullptr) {
Chong Zhang8541d302019-07-12 11:19:47 -0700450 *frameInfo = *defaultInfo;
Chong Zhangea280cb2017-08-02 11:10:10 -0700451 }
Chong Zhang8541d302019-07-12 11:19:47 -0700452
453 // default total scanline, this might change if decodeSequence() is used
454 mTotalScanline = defaultInfo->mHeight;
455
456 return true;
457}
458
459bool HeifDecoderImpl::getSequenceInfo(
460 HeifFrameInfo* frameInfo, size_t *frameCount) {
461 ALOGV("%s", __FUNCTION__);
462 if (!mHasVideo) {
463 return false;
464 }
465 if (frameInfo != nullptr) {
466 *frameInfo = mSequenceInfo;
467 }
468 if (frameCount != nullptr) {
469 *frameCount = mSequenceLength;
Chong Zhang0c1407f2018-05-02 17:09:05 -0700470 }
Chong Zhangea280cb2017-08-02 11:10:10 -0700471 return true;
472}
473
474bool HeifDecoderImpl::getEncodedColor(HeifEncodedColor* /*outColor*/) const {
475 ALOGW("getEncodedColor: not implemented!");
476 return false;
477}
478
479bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) {
Liz Kammer3ec5a0b2021-07-21 09:30:07 -0400480 if (heifColor == (HeifColorFormat)mOutputColor) {
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500481 return true;
482 }
483
Chong Zhangea280cb2017-08-02 11:10:10 -0700484 switch(heifColor) {
485 case kHeifColorFormat_RGB565:
486 {
487 mOutputColor = HAL_PIXEL_FORMAT_RGB_565;
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500488 break;
Chong Zhangea280cb2017-08-02 11:10:10 -0700489 }
490 case kHeifColorFormat_RGBA_8888:
491 {
492 mOutputColor = HAL_PIXEL_FORMAT_RGBA_8888;
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500493 break;
Chong Zhangea280cb2017-08-02 11:10:10 -0700494 }
495 case kHeifColorFormat_BGRA_8888:
496 {
497 mOutputColor = HAL_PIXEL_FORMAT_BGRA_8888;
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500498 break;
Chong Zhangea280cb2017-08-02 11:10:10 -0700499 }
Dichen Zhang1b3441a2021-11-17 11:54:43 -0800500 case kHeifColorFormat_RGBA_1010102:
501 {
502 mOutputColor = HAL_PIXEL_FORMAT_RGBA_1010102;
503 break;
504 }
Chong Zhangea280cb2017-08-02 11:10:10 -0700505 default:
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500506 ALOGE("Unsupported output color format %d", heifColor);
507 return false;
Chong Zhangea280cb2017-08-02 11:10:10 -0700508 }
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500509
510 if (mFrameDecoded) {
511 return reinit(nullptr);
512 }
513 return true;
Chong Zhangea280cb2017-08-02 11:10:10 -0700514}
515
Chong Zhang0c1407f2018-05-02 17:09:05 -0700516bool HeifDecoderImpl::decodeAsync() {
Dichen Zhang92e51072022-06-08 18:26:37 -0700517 wp<MediaMetadataRetriever> weakRetriever;
518 {
519 Mutex::Autolock _l(mRetrieverLock);
520 weakRetriever = mRetriever;
Dichen Zhang92e51072022-06-08 18:26:37 -0700521 }
522
Chong Zhang0c1407f2018-05-02 17:09:05 -0700523 for (size_t i = 1; i < mNumSlices; i++) {
Dichen Zhang92e51072022-06-08 18:26:37 -0700524 sp<MediaMetadataRetriever> retriever = weakRetriever.promote();
525 if (retriever == nullptr) {
526 return false;
527 }
528
Chong Zhang0c1407f2018-05-02 17:09:05 -0700529 ALOGV("decodeAsync(): decoding slice %zu", i);
530 size_t top = i * mSliceHeight;
531 size_t bottom = (i + 1) * mSliceHeight;
Chong Zhang8541d302019-07-12 11:19:47 -0700532 if (bottom > mImageInfo.mHeight) {
533 bottom = mImageInfo.mHeight;
Chong Zhang0c1407f2018-05-02 17:09:05 -0700534 }
Dichen Zhang92e51072022-06-08 18:26:37 -0700535
536 sp<IMemory> frameMemory = retriever->getImageRectAtIndex(
Chong Zhang8541d302019-07-12 11:19:47 -0700537 -1, mOutputColor, 0, top, mImageInfo.mWidth, bottom);
Chong Zhang0c1407f2018-05-02 17:09:05 -0700538 {
539 Mutex::Autolock autolock(mLock);
540
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700541 if (frameMemory == nullptr || frameMemory->unsecurePointer() == nullptr) {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700542 mAsyncDecodeDone = true;
543 mScanlineReady.signal();
544 break;
545 }
546 mFrameMemory = frameMemory;
547 mAvailableLines = bottom;
548 ALOGV("decodeAsync(): available lines %zu", mAvailableLines);
549 mScanlineReady.signal();
550 }
551 }
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500552 // Hold on to mDataSource in case the client wants to redecode.
Dichen Zhangf8230032022-12-01 18:39:23 -0800553
554 {
555 Mutex::Autolock _l(mRetrieverLock);
556 mRetriever.clear();
557 }
558
Chong Zhang0c1407f2018-05-02 17:09:05 -0700559 return false;
560}
561
Chong Zhangea280cb2017-08-02 11:10:10 -0700562bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) {
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700563 // reset scanline pointer
564 mCurScanline = 0;
565
566 if (mFrameDecoded) {
567 return true;
568 }
569
Dichen Zhang92e51072022-06-08 18:26:37 -0700570 sp<MediaMetadataRetriever> retriever;
571 {
572 Mutex::Autolock _l(mRetrieverLock);
573 if (mRetriever == nullptr) {
574 ALOGE("Failed to get MediaMetadataRetriever!");
575 return false;
576 }
577
578 retriever = mRetriever;
579 }
580
Chong Zhang0c1407f2018-05-02 17:09:05 -0700581 // See if we want to decode in slices to allow client to start
582 // scanline processing in parallel with decode. If this fails
583 // we fallback to decoding the full frame.
Chong Zhang8541d302019-07-12 11:19:47 -0700584 if (mHasImage) {
585 if (mSliceHeight >= 512 &&
586 mImageInfo.mWidth >= 3000 &&
587 mImageInfo.mHeight >= 2000 ) {
588 // Try decoding in slices only if the image has tiles and is big enough.
589 mNumSlices = (mImageInfo.mHeight + mSliceHeight - 1) / mSliceHeight;
590 ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
Chong Zhang0c1407f2018-05-02 17:09:05 -0700591 }
592
Chong Zhang8541d302019-07-12 11:19:47 -0700593 if (mNumSlices > 1) {
594 // get first slice and metadata
Dichen Zhang92e51072022-06-08 18:26:37 -0700595 sp<IMemory> frameMemory = retriever->getImageRectAtIndex(
Chong Zhang8541d302019-07-12 11:19:47 -0700596 -1, mOutputColor, 0, 0, mImageInfo.mWidth, mSliceHeight);
Chong Zhang0c1407f2018-05-02 17:09:05 -0700597
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700598 if (frameMemory == nullptr || frameMemory->unsecurePointer() == nullptr) {
Chong Zhang8541d302019-07-12 11:19:47 -0700599 ALOGE("decode: metadata is a nullptr");
600 return false;
601 }
602
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700603 // TODO: Using unsecurePointer() has some associated security pitfalls
604 // (see declaration for details).
605 // Either document why it is safe in this case or address the
606 // issue (e.g. by copying).
607 VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->unsecurePointer());
Chong Zhang8541d302019-07-12 11:19:47 -0700608
609 if (frameInfo != nullptr) {
610 initFrameInfo(frameInfo, videoFrame);
611 }
612 mFrameMemory = frameMemory;
613 mAvailableLines = mSliceHeight;
614 mThread = new DecodeThread(this);
615 if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
616 mFrameDecoded = true;
617 return true;
618 }
619 // Fallback to decode without slicing
620 mThread.clear();
621 mNumSlices = 1;
622 mSliceHeight = 0;
623 mAvailableLines = 0;
624 mFrameMemory.clear();
Chong Zhang0c1407f2018-05-02 17:09:05 -0700625 }
Chong Zhang0c1407f2018-05-02 17:09:05 -0700626 }
627
Chong Zhangd3e0d862017-10-03 13:17:13 -0700628 if (mHasImage) {
629 // image index < 0 to retrieve primary image
Dichen Zhang92e51072022-06-08 18:26:37 -0700630 mFrameMemory = retriever->getImageAtIndex(-1, mOutputColor);
Chong Zhangd3e0d862017-10-03 13:17:13 -0700631 } else if (mHasVideo) {
Dichen Zhang92e51072022-06-08 18:26:37 -0700632 mFrameMemory = retriever->getFrameAtTime(0,
Chong Zhangd3e0d862017-10-03 13:17:13 -0700633 MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
634 }
635
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700636 if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700637 ALOGE("decode: videoFrame is a nullptr");
Chong Zhangea280cb2017-08-02 11:10:10 -0700638 return false;
639 }
640
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700641 // TODO: Using unsecurePointer() has some associated security pitfalls
642 // (see declaration for details).
643 // Either document why it is safe in this case or address the
644 // issue (e.g. by copying).
645 VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700646 if (videoFrame->mSize == 0 ||
647 mFrameMemory->size() < videoFrame->getFlattenedSize()) {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700648 ALOGE("decode: videoFrame size is invalid");
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700649 return false;
650 }
651
Chong Zhangea280cb2017-08-02 11:10:10 -0700652 ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
653 videoFrame->mWidth,
654 videoFrame->mHeight,
655 videoFrame->mDisplayWidth,
656 videoFrame->mDisplayHeight,
657 videoFrame->mRotationAngle,
658 videoFrame->mRowBytes,
659 videoFrame->mSize);
660
661 if (frameInfo != nullptr) {
Chong Zhang8541d302019-07-12 11:19:47 -0700662 initFrameInfo(frameInfo, videoFrame);
663
Chong Zhangea280cb2017-08-02 11:10:10 -0700664 }
Chong Zhang3f3ffab2017-08-23 13:51:59 -0700665 mFrameDecoded = true;
Chong Zhang4c6398b2017-09-07 17:43:19 -0700666
Chong Zhang0c1407f2018-05-02 17:09:05 -0700667 // Aggressively clear to avoid holding on to resources
Dichen Zhangf8230032022-12-01 18:39:23 -0800668 {
669 Mutex::Autolock _l(mRetrieverLock);
670 mRetriever.clear();
671 }
Leon Scroggins III7ca678b2020-01-22 14:09:55 -0500672
673 // Hold on to mDataSource in case the client wants to redecode.
Chong Zhangea280cb2017-08-02 11:10:10 -0700674 return true;
675}
676
Chong Zhang8541d302019-07-12 11:19:47 -0700677bool HeifDecoderImpl::decodeSequence(int frameIndex, HeifFrameInfo* frameInfo) {
678 ALOGV("%s: frame index %d", __FUNCTION__, frameIndex);
679 if (!mHasVideo) {
680 return false;
681 }
682
683 if (frameIndex < 0 || frameIndex >= mSequenceLength) {
684 ALOGE("invalid frame index: %d, total frames %zu", frameIndex, mSequenceLength);
685 return false;
686 }
687
688 mCurScanline = 0;
689
690 // set total scanline to sequence height now
691 mTotalScanline = mSequenceInfo.mHeight;
692
Dichen Zhang92e51072022-06-08 18:26:37 -0700693 sp<MediaMetadataRetriever> retriever;
694 {
695 Mutex::Autolock _l(mRetrieverLock);
696 retriever = mRetriever;
697 if (retriever == nullptr) {
698 ALOGE("failed to get MediaMetadataRetriever!");
699 return false;
700 }
701 }
702
703 mFrameMemory = retriever->getFrameAtIndex(frameIndex, mOutputColor);
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700704 if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
Chong Zhang8541d302019-07-12 11:19:47 -0700705 ALOGE("decode: videoFrame is a nullptr");
706 return false;
707 }
708
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700709 // TODO: Using unsecurePointer() has some associated security pitfalls
710 // (see declaration for details).
711 // Either document why it is safe in this case or address the
712 // issue (e.g. by copying).
713 VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
Chong Zhang8541d302019-07-12 11:19:47 -0700714 if (videoFrame->mSize == 0 ||
715 mFrameMemory->size() < videoFrame->getFlattenedSize()) {
716 ALOGE("decode: videoFrame size is invalid");
717 return false;
718 }
719
720 ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
721 videoFrame->mWidth,
722 videoFrame->mHeight,
723 videoFrame->mDisplayWidth,
724 videoFrame->mDisplayHeight,
725 videoFrame->mRotationAngle,
726 videoFrame->mRowBytes,
727 videoFrame->mSize);
728
729 if (frameInfo != nullptr) {
730 initFrameInfo(frameInfo, videoFrame);
731 }
732 return true;
733}
734
Chong Zhang0c1407f2018-05-02 17:09:05 -0700735bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) {
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700736 if (mFrameMemory == nullptr || mFrameMemory->unsecurePointer() == nullptr) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700737 return false;
738 }
Ytai Ben-Tsvi7dd39722019-09-05 15:14:30 -0700739 // TODO: Using unsecurePointer() has some associated security pitfalls
740 // (see declaration for details).
741 // Either document why it is safe in this case or address the
742 // issue (e.g. by copying).
743 VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->unsecurePointer());
Chong Zhangea280cb2017-08-02 11:10:10 -0700744 uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++;
Chong Zhang70b0afd2018-02-27 12:43:06 -0800745 memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth);
Chong Zhangea280cb2017-08-02 11:10:10 -0700746 return true;
747}
748
Chong Zhang0c1407f2018-05-02 17:09:05 -0700749bool HeifDecoderImpl::getScanline(uint8_t* dst) {
Chong Zhang8541d302019-07-12 11:19:47 -0700750 if (mCurScanline >= mTotalScanline) {
Chong Zhang0c1407f2018-05-02 17:09:05 -0700751 ALOGE("no more scanline available");
752 return false;
Chong Zhangea280cb2017-08-02 11:10:10 -0700753 }
Chong Zhangea280cb2017-08-02 11:10:10 -0700754
Chong Zhang0c1407f2018-05-02 17:09:05 -0700755 if (mNumSlices > 1) {
756 Mutex::Autolock autolock(mLock);
757
758 while (!mAsyncDecodeDone && mCurScanline >= mAvailableLines) {
759 mScanlineReady.wait(mLock);
760 }
761 return (mCurScanline < mAvailableLines) ? getScanlineInner(dst) : false;
762 }
763
764 return getScanlineInner(dst);
765}
766
767size_t HeifDecoderImpl::skipScanlines(size_t count) {
Chong Zhangea280cb2017-08-02 11:10:10 -0700768 uint32_t oldScanline = mCurScanline;
769 mCurScanline += count;
Chong Zhang8541d302019-07-12 11:19:47 -0700770 if (mCurScanline > mTotalScanline) {
771 mCurScanline = mTotalScanline;
Chong Zhangea280cb2017-08-02 11:10:10 -0700772 }
773 return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
774}
775
Dichen Zhangf4066492022-02-17 17:32:53 -0800776uint32_t HeifDecoderImpl::getColorDepth() {
777 HeifFrameInfo* info = &mImageInfo;
778 if (info != nullptr) {
779 return mImageInfo.mBitDepth;
780 } else {
781 return 0;
782 }
783}
784
Chong Zhangea280cb2017-08-02 11:10:10 -0700785} // namespace android