HeifDecoderImpl.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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. //#define LOG_NDEBUG 0
  17. #define LOG_TAG "HeifDecoderImpl"
  18. #include "HeifDecoderImpl.h"
  19. #include <stdio.h>
  20. #include <binder/IMemory.h>
  21. #include <binder/MemoryDealer.h>
  22. #include <drm/drm_framework_common.h>
  23. #include <media/IDataSource.h>
  24. #include <media/mediametadataretriever.h>
  25. #include <media/MediaSource.h>
  26. #include <media/stagefright/foundation/ADebug.h>
  27. #include <private/media/VideoFrame.h>
  28. #include <utils/Log.h>
  29. #include <utils/RefBase.h>
  30. HeifDecoder* createHeifDecoder() {
  31. return new android::HeifDecoderImpl();
  32. }
  33. namespace android {
  34. /*
  35. * HeifDataSource
  36. *
  37. * Proxies data requests over IDataSource interface from MediaMetadataRetriever
  38. * to the HeifStream interface we received from the heif decoder client.
  39. */
  40. class HeifDataSource : public BnDataSource {
  41. public:
  42. /*
  43. * Constructs HeifDataSource; will take ownership of |stream|.
  44. */
  45. HeifDataSource(HeifStream* stream)
  46. : mStream(stream), mEOS(false),
  47. mCachedOffset(0), mCachedSize(0), mCacheBufferSize(0) {}
  48. ~HeifDataSource() override {}
  49. /*
  50. * Initializes internal resources.
  51. */
  52. bool init();
  53. sp<IMemory> getIMemory() override { return mMemory; }
  54. ssize_t readAt(off64_t offset, size_t size) override;
  55. status_t getSize(off64_t* size) override ;
  56. void close() {}
  57. uint32_t getFlags() override { return 0; }
  58. String8 toString() override { return String8("HeifDataSource"); }
  59. sp<DecryptHandle> DrmInitialization(const char*) override {
  60. return nullptr;
  61. }
  62. private:
  63. enum {
  64. /*
  65. * Buffer size for passing the read data to mediaserver. Set to 64K
  66. * (which is what MediaDataSource Java API's jni implementation uses).
  67. */
  68. kBufferSize = 64 * 1024,
  69. /*
  70. * Initial and max cache buffer size.
  71. */
  72. kInitialCacheBufferSize = 4 * 1024 * 1024,
  73. kMaxCacheBufferSize = 64 * 1024 * 1024,
  74. };
  75. sp<IMemory> mMemory;
  76. std::unique_ptr<HeifStream> mStream;
  77. bool mEOS;
  78. std::unique_ptr<uint8_t[]> mCache;
  79. off64_t mCachedOffset;
  80. size_t mCachedSize;
  81. size_t mCacheBufferSize;
  82. };
  83. bool HeifDataSource::init() {
  84. sp<MemoryDealer> memoryDealer =
  85. new MemoryDealer(kBufferSize, "HeifDataSource");
  86. mMemory = memoryDealer->allocate(kBufferSize);
  87. if (mMemory == nullptr) {
  88. ALOGE("Failed to allocate shared memory!");
  89. return false;
  90. }
  91. mCache.reset(new uint8_t[kInitialCacheBufferSize]);
  92. if (mCache.get() == nullptr) {
  93. ALOGE("mFailed to allocate cache!");
  94. return false;
  95. }
  96. mCacheBufferSize = kInitialCacheBufferSize;
  97. return true;
  98. }
  99. ssize_t HeifDataSource::readAt(off64_t offset, size_t size) {
  100. ALOGV("readAt: offset=%lld, size=%zu", (long long)offset, size);
  101. if (offset < mCachedOffset) {
  102. // try seek, then rewind/skip, fail if none worked
  103. if (mStream->seek(offset)) {
  104. ALOGV("readAt: seek to offset=%lld", (long long)offset);
  105. mCachedOffset = offset;
  106. mCachedSize = 0;
  107. mEOS = false;
  108. } else if (mStream->rewind()) {
  109. ALOGV("readAt: rewind to offset=0");
  110. mCachedOffset = 0;
  111. mCachedSize = 0;
  112. mEOS = false;
  113. } else {
  114. ALOGE("readAt: couldn't seek or rewind!");
  115. mEOS = true;
  116. }
  117. }
  118. if (mEOS && (offset < mCachedOffset ||
  119. offset >= (off64_t)(mCachedOffset + mCachedSize))) {
  120. ALOGV("readAt: EOS");
  121. return ERROR_END_OF_STREAM;
  122. }
  123. // at this point, offset must be >= mCachedOffset, other cases should
  124. // have been caught above.
  125. CHECK(offset >= mCachedOffset);
  126. off64_t resultOffset;
  127. if (__builtin_add_overflow(offset, size, &resultOffset)) {
  128. return ERROR_IO;
  129. }
  130. if (size == 0) {
  131. return 0;
  132. }
  133. // Can only read max of kBufferSize
  134. if (size > kBufferSize) {
  135. size = kBufferSize;
  136. }
  137. // copy from cache if the request falls entirely in cache
  138. if (offset + size <= mCachedOffset + mCachedSize) {
  139. memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
  140. return size;
  141. }
  142. // need to fetch more, check if we need to expand the cache buffer.
  143. if ((off64_t)(offset + size) > mCachedOffset + kMaxCacheBufferSize) {
  144. // it's reaching max cache buffer size, need to roll window, and possibly
  145. // expand the cache buffer.
  146. size_t newCacheBufferSize = mCacheBufferSize;
  147. std::unique_ptr<uint8_t[]> newCache;
  148. uint8_t* dst = mCache.get();
  149. if (newCacheBufferSize < kMaxCacheBufferSize) {
  150. newCacheBufferSize = kMaxCacheBufferSize;
  151. newCache.reset(new uint8_t[newCacheBufferSize]);
  152. dst = newCache.get();
  153. }
  154. // when rolling the cache window, try to keep about half the old bytes
  155. // in case that the client goes back.
  156. off64_t newCachedOffset = offset - (off64_t)(newCacheBufferSize / 2);
  157. if (newCachedOffset < mCachedOffset) {
  158. newCachedOffset = mCachedOffset;
  159. }
  160. int64_t newCachedSize = (int64_t)(mCachedOffset + mCachedSize) - newCachedOffset;
  161. if (newCachedSize > 0) {
  162. // in this case, the new cache region partially overlop the old cache,
  163. // move the portion of the cache we want to save to the beginning of
  164. // the cache buffer.
  165. memcpy(dst, mCache.get() + newCachedOffset - mCachedOffset, newCachedSize);
  166. } else if (newCachedSize < 0){
  167. // in this case, the new cache region is entirely out of the old cache,
  168. // in order to guarantee sequential read, we need to skip a number of
  169. // bytes before reading.
  170. size_t bytesToSkip = -newCachedSize;
  171. size_t bytesSkipped = mStream->read(nullptr, bytesToSkip);
  172. if (bytesSkipped != bytesToSkip) {
  173. // bytesSkipped is invalid, there is not enough bytes to reach
  174. // the requested offset.
  175. ALOGE("readAt: skip failed, EOS");
  176. mEOS = true;
  177. mCachedOffset = newCachedOffset;
  178. mCachedSize = 0;
  179. return ERROR_END_OF_STREAM;
  180. }
  181. // set cache size to 0, since we're not keeping any old cache
  182. newCachedSize = 0;
  183. }
  184. if (newCache.get() != nullptr) {
  185. mCache.reset(newCache.release());
  186. mCacheBufferSize = newCacheBufferSize;
  187. }
  188. mCachedOffset = newCachedOffset;
  189. mCachedSize = newCachedSize;
  190. ALOGV("readAt: rolling cache window to (%lld, %zu), cache buffer size %zu",
  191. (long long)mCachedOffset, mCachedSize, mCacheBufferSize);
  192. } else {
  193. // expand cache buffer, but no need to roll the window
  194. size_t newCacheBufferSize = mCacheBufferSize;
  195. while (offset + size > mCachedOffset + newCacheBufferSize) {
  196. newCacheBufferSize *= 2;
  197. }
  198. CHECK(newCacheBufferSize <= kMaxCacheBufferSize);
  199. if (mCacheBufferSize < newCacheBufferSize) {
  200. uint8_t* newCache = new uint8_t[newCacheBufferSize];
  201. memcpy(newCache, mCache.get(), mCachedSize);
  202. mCache.reset(newCache);
  203. mCacheBufferSize = newCacheBufferSize;
  204. ALOGV("readAt: current cache window (%lld, %zu), new cache buffer size %zu",
  205. (long long) mCachedOffset, mCachedSize, mCacheBufferSize);
  206. }
  207. }
  208. size_t bytesToRead = offset + size - mCachedOffset - mCachedSize;
  209. size_t bytesRead = mStream->read(mCache.get() + mCachedSize, bytesToRead);
  210. if (bytesRead > bytesToRead || bytesRead == 0) {
  211. // bytesRead is invalid
  212. mEOS = true;
  213. bytesRead = 0;
  214. } else if (bytesRead < bytesToRead) {
  215. // read some bytes but not all, set EOS
  216. mEOS = true;
  217. }
  218. mCachedSize += bytesRead;
  219. ALOGV("readAt: current cache window (%lld, %zu)",
  220. (long long) mCachedOffset, mCachedSize);
  221. // here bytesAvailable could be negative if offset jumped past EOS.
  222. int64_t bytesAvailable = mCachedOffset + mCachedSize - offset;
  223. if (bytesAvailable <= 0) {
  224. return ERROR_END_OF_STREAM;
  225. }
  226. if (bytesAvailable < (int64_t)size) {
  227. size = bytesAvailable;
  228. }
  229. memcpy(mMemory->pointer(), mCache.get() + offset - mCachedOffset, size);
  230. return size;
  231. }
  232. status_t HeifDataSource::getSize(off64_t* size) {
  233. if (!mStream->hasLength()) {
  234. *size = -1;
  235. ALOGE("getSize: not supported!");
  236. return ERROR_UNSUPPORTED;
  237. }
  238. *size = mStream->getLength();
  239. ALOGV("getSize: size=%lld", (long long)*size);
  240. return OK;
  241. }
  242. /////////////////////////////////////////////////////////////////////////
  243. struct HeifDecoderImpl::DecodeThread : public Thread {
  244. explicit DecodeThread(HeifDecoderImpl *decoder) : mDecoder(decoder) {}
  245. private:
  246. HeifDecoderImpl* mDecoder;
  247. bool threadLoop();
  248. DISALLOW_EVIL_CONSTRUCTORS(DecodeThread);
  249. };
  250. bool HeifDecoderImpl::DecodeThread::threadLoop() {
  251. return mDecoder->decodeAsync();
  252. }
  253. /////////////////////////////////////////////////////////////////////////
  254. HeifDecoderImpl::HeifDecoderImpl() :
  255. // output color format should always be set via setOutputColor(), in case
  256. // it's not, default to HAL_PIXEL_FORMAT_RGB_565.
  257. mOutputColor(HAL_PIXEL_FORMAT_RGB_565),
  258. mCurScanline(0),
  259. mWidth(0),
  260. mHeight(0),
  261. mFrameDecoded(false),
  262. mHasImage(false),
  263. mHasVideo(false),
  264. mAvailableLines(0),
  265. mNumSlices(1),
  266. mSliceHeight(0),
  267. mAsyncDecodeDone(false) {
  268. }
  269. HeifDecoderImpl::~HeifDecoderImpl() {
  270. if (mThread != nullptr) {
  271. mThread->join();
  272. }
  273. }
  274. bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) {
  275. mFrameDecoded = false;
  276. mFrameMemory.clear();
  277. sp<HeifDataSource> dataSource = new HeifDataSource(stream);
  278. if (!dataSource->init()) {
  279. return false;
  280. }
  281. mDataSource = dataSource;
  282. mRetriever = new MediaMetadataRetriever();
  283. status_t err = mRetriever->setDataSource(mDataSource, "image/heif");
  284. if (err != OK) {
  285. ALOGE("failed to set data source!");
  286. mRetriever.clear();
  287. mDataSource.clear();
  288. return false;
  289. }
  290. ALOGV("successfully set data source.");
  291. const char* hasImage = mRetriever->extractMetadata(METADATA_KEY_HAS_IMAGE);
  292. const char* hasVideo = mRetriever->extractMetadata(METADATA_KEY_HAS_VIDEO);
  293. mHasImage = hasImage && !strcasecmp(hasImage, "yes");
  294. mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes");
  295. sp<IMemory> sharedMem;
  296. if (mHasImage) {
  297. // image index < 0 to retrieve primary image
  298. sharedMem = mRetriever->getImageAtIndex(
  299. -1, mOutputColor, true /*metaOnly*/);
  300. } else if (mHasVideo) {
  301. sharedMem = mRetriever->getFrameAtTime(0,
  302. MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC,
  303. mOutputColor, true /*metaOnly*/);
  304. }
  305. if (sharedMem == nullptr || sharedMem->pointer() == nullptr) {
  306. ALOGE("getFrameAtTime: videoFrame is a nullptr");
  307. return false;
  308. }
  309. VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->pointer());
  310. ALOGV("Meta dimension %dx%d, display %dx%d, angle %d, iccSize %d",
  311. videoFrame->mWidth,
  312. videoFrame->mHeight,
  313. videoFrame->mDisplayWidth,
  314. videoFrame->mDisplayHeight,
  315. videoFrame->mRotationAngle,
  316. videoFrame->mIccSize);
  317. if (frameInfo != nullptr) {
  318. frameInfo->set(
  319. videoFrame->mWidth,
  320. videoFrame->mHeight,
  321. videoFrame->mRotationAngle,
  322. videoFrame->mBytesPerPixel,
  323. videoFrame->mIccSize,
  324. videoFrame->getFlattenedIccData());
  325. }
  326. mWidth = videoFrame->mWidth;
  327. mHeight = videoFrame->mHeight;
  328. if (mHasImage && videoFrame->mTileHeight >= 512 && mWidth >= 3000 && mHeight >= 2000 ) {
  329. // Try decoding in slices only if the image has tiles and is big enough.
  330. mSliceHeight = videoFrame->mTileHeight;
  331. mNumSlices = (videoFrame->mHeight + mSliceHeight - 1) / mSliceHeight;
  332. ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices);
  333. }
  334. return true;
  335. }
  336. bool HeifDecoderImpl::getEncodedColor(HeifEncodedColor* /*outColor*/) const {
  337. ALOGW("getEncodedColor: not implemented!");
  338. return false;
  339. }
  340. bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) {
  341. switch(heifColor) {
  342. case kHeifColorFormat_RGB565:
  343. {
  344. mOutputColor = HAL_PIXEL_FORMAT_RGB_565;
  345. return true;
  346. }
  347. case kHeifColorFormat_RGBA_8888:
  348. {
  349. mOutputColor = HAL_PIXEL_FORMAT_RGBA_8888;
  350. return true;
  351. }
  352. case kHeifColorFormat_BGRA_8888:
  353. {
  354. mOutputColor = HAL_PIXEL_FORMAT_BGRA_8888;
  355. return true;
  356. }
  357. default:
  358. break;
  359. }
  360. ALOGE("Unsupported output color format %d", heifColor);
  361. return false;
  362. }
  363. bool HeifDecoderImpl::decodeAsync() {
  364. for (size_t i = 1; i < mNumSlices; i++) {
  365. ALOGV("decodeAsync(): decoding slice %zu", i);
  366. size_t top = i * mSliceHeight;
  367. size_t bottom = (i + 1) * mSliceHeight;
  368. if (bottom > mHeight) {
  369. bottom = mHeight;
  370. }
  371. sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
  372. -1, mOutputColor, 0, top, mWidth, bottom);
  373. {
  374. Mutex::Autolock autolock(mLock);
  375. if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
  376. mAsyncDecodeDone = true;
  377. mScanlineReady.signal();
  378. break;
  379. }
  380. mFrameMemory = frameMemory;
  381. mAvailableLines = bottom;
  382. ALOGV("decodeAsync(): available lines %zu", mAvailableLines);
  383. mScanlineReady.signal();
  384. }
  385. }
  386. // Aggressive clear to avoid holding on to resources
  387. mRetriever.clear();
  388. mDataSource.clear();
  389. return false;
  390. }
  391. bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) {
  392. // reset scanline pointer
  393. mCurScanline = 0;
  394. if (mFrameDecoded) {
  395. return true;
  396. }
  397. // See if we want to decode in slices to allow client to start
  398. // scanline processing in parallel with decode. If this fails
  399. // we fallback to decoding the full frame.
  400. if (mHasImage && mNumSlices > 1) {
  401. // get first slice and metadata
  402. sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex(
  403. -1, mOutputColor, 0, 0, mWidth, mSliceHeight);
  404. if (frameMemory == nullptr || frameMemory->pointer() == nullptr) {
  405. ALOGE("decode: metadata is a nullptr");
  406. return false;
  407. }
  408. VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->pointer());
  409. if (frameInfo != nullptr) {
  410. frameInfo->set(
  411. videoFrame->mWidth,
  412. videoFrame->mHeight,
  413. videoFrame->mRotationAngle,
  414. videoFrame->mBytesPerPixel,
  415. videoFrame->mIccSize,
  416. videoFrame->getFlattenedIccData());
  417. }
  418. mFrameMemory = frameMemory;
  419. mAvailableLines = mSliceHeight;
  420. mThread = new DecodeThread(this);
  421. if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) {
  422. mFrameDecoded = true;
  423. return true;
  424. }
  425. // Fallback to decode without slicing
  426. mThread.clear();
  427. mNumSlices = 1;
  428. mSliceHeight = 0;
  429. mAvailableLines = 0;
  430. mFrameMemory.clear();
  431. }
  432. if (mHasImage) {
  433. // image index < 0 to retrieve primary image
  434. mFrameMemory = mRetriever->getImageAtIndex(-1, mOutputColor);
  435. } else if (mHasVideo) {
  436. mFrameMemory = mRetriever->getFrameAtTime(0,
  437. MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor);
  438. }
  439. if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
  440. ALOGE("decode: videoFrame is a nullptr");
  441. return false;
  442. }
  443. VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
  444. if (videoFrame->mSize == 0 ||
  445. mFrameMemory->size() < videoFrame->getFlattenedSize()) {
  446. ALOGE("decode: videoFrame size is invalid");
  447. return false;
  448. }
  449. ALOGV("Decoded dimension %dx%d, display %dx%d, angle %d, rowbytes %d, size %d",
  450. videoFrame->mWidth,
  451. videoFrame->mHeight,
  452. videoFrame->mDisplayWidth,
  453. videoFrame->mDisplayHeight,
  454. videoFrame->mRotationAngle,
  455. videoFrame->mRowBytes,
  456. videoFrame->mSize);
  457. if (frameInfo != nullptr) {
  458. frameInfo->set(
  459. videoFrame->mWidth,
  460. videoFrame->mHeight,
  461. videoFrame->mRotationAngle,
  462. videoFrame->mBytesPerPixel,
  463. videoFrame->mIccSize,
  464. videoFrame->getFlattenedIccData());
  465. }
  466. mFrameDecoded = true;
  467. // Aggressively clear to avoid holding on to resources
  468. mRetriever.clear();
  469. mDataSource.clear();
  470. return true;
  471. }
  472. bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) {
  473. if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) {
  474. return false;
  475. }
  476. VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer());
  477. uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++;
  478. memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth);
  479. return true;
  480. }
  481. bool HeifDecoderImpl::getScanline(uint8_t* dst) {
  482. if (mCurScanline >= mHeight) {
  483. ALOGE("no more scanline available");
  484. return false;
  485. }
  486. if (mNumSlices > 1) {
  487. Mutex::Autolock autolock(mLock);
  488. while (!mAsyncDecodeDone && mCurScanline >= mAvailableLines) {
  489. mScanlineReady.wait(mLock);
  490. }
  491. return (mCurScanline < mAvailableLines) ? getScanlineInner(dst) : false;
  492. }
  493. return getScanlineInner(dst);
  494. }
  495. size_t HeifDecoderImpl::skipScanlines(size_t count) {
  496. uint32_t oldScanline = mCurScanline;
  497. mCurScanline += count;
  498. if (mCurScanline > mHeight) {
  499. mCurScanline = mHeight;
  500. }
  501. return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0;
  502. }
  503. } // namespace android