Home | History | Annotate | Download | only in libstagefright
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "FrameDecoder"
     19 
     20 #include "include/FrameDecoder.h"
     21 #include <binder/MemoryBase.h>
     22 #include <binder/MemoryHeapBase.h>
     23 #include <gui/Surface.h>
     24 #include <inttypes.h>
     25 #include <media/ICrypto.h>
     26 #include <media/IMediaSource.h>
     27 #include <media/MediaCodecBuffer.h>
     28 #include <media/stagefright/foundation/avc_utils.h>
     29 #include <media/stagefright/foundation/ADebug.h>
     30 #include <media/stagefright/foundation/AMessage.h>
     31 #include <media/stagefright/ColorConverter.h>
     32 #include <media/stagefright/MediaBuffer.h>
     33 #include <media/stagefright/MediaCodec.h>
     34 #include <media/stagefright/MediaDefs.h>
     35 #include <media/stagefright/MediaErrors.h>
     36 #include <media/stagefright/Utils.h>
     37 #include <private/media/VideoFrame.h>
     38 #include <utils/Log.h>
     39 
     40 namespace android {
     41 
     42 static const int64_t kBufferTimeOutUs = 10000LL; // 10 msec
     43 static const size_t kRetryCount = 50; // must be >0
     44 
     45 sp<IMemory> allocVideoFrame(const sp<MetaData>& trackMeta,
     46         int32_t width, int32_t height, int32_t tileWidth, int32_t tileHeight,
     47         int32_t dstBpp, bool metaOnly = false) {
     48     int32_t rotationAngle;
     49     if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
     50         rotationAngle = 0;  // By default, no rotation
     51     }
     52     uint32_t type;
     53     const void *iccData;
     54     size_t iccSize;
     55     if (!trackMeta->findData(kKeyIccProfile, &type, &iccData, &iccSize)){
     56         iccData = NULL;
     57         iccSize = 0;
     58     }
     59 
     60     int32_t sarWidth, sarHeight;
     61     int32_t displayWidth, displayHeight;
     62     if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
     63             && trackMeta->findInt32(kKeySARHeight, &sarHeight)
     64             && sarHeight != 0) {
     65         displayWidth = (width * sarWidth) / sarHeight;
     66         displayHeight = height;
     67     } else if (trackMeta->findInt32(kKeyDisplayWidth, &displayWidth)
     68                 && trackMeta->findInt32(kKeyDisplayHeight, &displayHeight)
     69                 && displayWidth > 0 && displayHeight > 0
     70                 && width > 0 && height > 0) {
     71         ALOGV("found display size %dx%d", displayWidth, displayHeight);
     72     } else {
     73         displayWidth = width;
     74         displayHeight = height;
     75     }
     76 
     77     VideoFrame frame(width, height, displayWidth, displayHeight,
     78             tileWidth, tileHeight, rotationAngle, dstBpp, !metaOnly, iccSize);
     79 
     80     size_t size = frame.getFlattenedSize();
     81     sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
     82     if (heap == NULL) {
     83         ALOGE("failed to create MemoryDealer");
     84         return NULL;
     85     }
     86     sp<IMemory> frameMem = new MemoryBase(heap, 0, size);
     87     if (frameMem == NULL) {
     88         ALOGE("not enough memory for VideoFrame size=%zu", size);
     89         return NULL;
     90     }
     91     VideoFrame* frameCopy = static_cast<VideoFrame*>(frameMem->pointer());
     92     frameCopy->init(frame, iccData, iccSize);
     93 
     94     return frameMem;
     95 }
     96 
     97 bool findThumbnailInfo(
     98         const sp<MetaData> &trackMeta, int32_t *width, int32_t *height,
     99         uint32_t *type = NULL, const void **data = NULL, size_t *size = NULL) {
    100     uint32_t dummyType;
    101     const void *dummyData;
    102     size_t dummySize;
    103     return trackMeta->findInt32(kKeyThumbnailWidth, width)
    104         && trackMeta->findInt32(kKeyThumbnailHeight, height)
    105         && trackMeta->findData(kKeyThumbnailHVCC,
    106                 type ?: &dummyType, data ?: &dummyData, size ?: &dummySize);
    107 }
    108 
    109 bool findGridInfo(const sp<MetaData> &trackMeta,
    110         int32_t *tileWidth, int32_t *tileHeight, int32_t *gridRows, int32_t *gridCols) {
    111     return trackMeta->findInt32(kKeyTileWidth, tileWidth) && (*tileWidth > 0)
    112         && trackMeta->findInt32(kKeyTileHeight, tileHeight) && (*tileHeight > 0)
    113         && trackMeta->findInt32(kKeyGridRows, gridRows) && (*gridRows > 0)
    114         && trackMeta->findInt32(kKeyGridCols, gridCols) && (*gridCols > 0);
    115 }
    116 
    117 bool getDstColorFormat(
    118         android_pixel_format_t colorFormat,
    119         OMX_COLOR_FORMATTYPE *dstFormat,
    120         int32_t *dstBpp) {
    121     switch (colorFormat) {
    122         case HAL_PIXEL_FORMAT_RGB_565:
    123         {
    124             *dstFormat = OMX_COLOR_Format16bitRGB565;
    125             *dstBpp = 2;
    126             return true;
    127         }
    128         case HAL_PIXEL_FORMAT_RGBA_8888:
    129         {
    130             *dstFormat = OMX_COLOR_Format32BitRGBA8888;
    131             *dstBpp = 4;
    132             return true;
    133         }
    134         case HAL_PIXEL_FORMAT_BGRA_8888:
    135         {
    136             *dstFormat = OMX_COLOR_Format32bitBGRA8888;
    137             *dstBpp = 4;
    138             return true;
    139         }
    140         default:
    141         {
    142             ALOGE("Unsupported color format: %d", colorFormat);
    143             break;
    144         }
    145     }
    146     return false;
    147 }
    148 
    149 //static
    150 sp<IMemory> FrameDecoder::getMetadataOnly(
    151         const sp<MetaData> &trackMeta, int colorFormat, bool thumbnail) {
    152     OMX_COLOR_FORMATTYPE dstFormat;
    153     int32_t dstBpp;
    154     if (!getDstColorFormat(
    155             (android_pixel_format_t)colorFormat, &dstFormat, &dstBpp)) {
    156         return NULL;
    157     }
    158 
    159     int32_t width, height, tileWidth = 0, tileHeight = 0;
    160     if (thumbnail) {
    161         if (!findThumbnailInfo(trackMeta, &width, &height)) {
    162             return NULL;
    163         }
    164     } else {
    165         CHECK(trackMeta->findInt32(kKeyWidth, &width));
    166         CHECK(trackMeta->findInt32(kKeyHeight, &height));
    167 
    168         int32_t gridRows, gridCols;
    169         if (!findGridInfo(trackMeta, &tileWidth, &tileHeight, &gridRows, &gridCols)) {
    170             tileWidth = tileHeight = 0;
    171         }
    172     }
    173     return allocVideoFrame(trackMeta,
    174             width, height, tileWidth, tileHeight, dstBpp, true /*metaOnly*/);
    175 }
    176 
    177 FrameDecoder::FrameDecoder(
    178         const AString &componentName,
    179         const sp<MetaData> &trackMeta,
    180         const sp<IMediaSource> &source)
    181     : mComponentName(componentName),
    182       mTrackMeta(trackMeta),
    183       mSource(source),
    184       mDstFormat(OMX_COLOR_Format16bitRGB565),
    185       mDstBpp(2),
    186       mHaveMoreInputs(true),
    187       mFirstSample(true) {
    188 }
    189 
    190 FrameDecoder::~FrameDecoder() {
    191     if (mDecoder != NULL) {
    192         mDecoder->release();
    193         mSource->stop();
    194     }
    195 }
    196 
    197 status_t FrameDecoder::init(
    198         int64_t frameTimeUs, size_t numFrames, int option, int colorFormat) {
    199     if (!getDstColorFormat(
    200             (android_pixel_format_t)colorFormat, &mDstFormat, &mDstBpp)) {
    201         return ERROR_UNSUPPORTED;
    202     }
    203 
    204     sp<AMessage> videoFormat = onGetFormatAndSeekOptions(
    205             frameTimeUs, numFrames, option, &mReadOptions);
    206     if (videoFormat == NULL) {
    207         ALOGE("video format or seek mode not supported");
    208         return ERROR_UNSUPPORTED;
    209     }
    210 
    211     status_t err;
    212     sp<ALooper> looper = new ALooper;
    213     looper->start();
    214     sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
    215             looper, mComponentName, &err);
    216     if (decoder.get() == NULL || err != OK) {
    217         ALOGW("Failed to instantiate decoder [%s]", mComponentName.c_str());
    218         return (decoder.get() == NULL) ? NO_MEMORY : err;
    219     }
    220 
    221     err = decoder->configure(
    222             videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
    223     if (err != OK) {
    224         ALOGW("configure returned error %d (%s)", err, asString(err));
    225         decoder->release();
    226         return err;
    227     }
    228 
    229     err = decoder->start();
    230     if (err != OK) {
    231         ALOGW("start returned error %d (%s)", err, asString(err));
    232         decoder->release();
    233         return err;
    234     }
    235 
    236     err = mSource->start();
    237     if (err != OK) {
    238         ALOGW("source failed to start: %d (%s)", err, asString(err));
    239         decoder->release();
    240         return err;
    241     }
    242     mDecoder = decoder;
    243 
    244     return OK;
    245 }
    246 
    247 sp<IMemory> FrameDecoder::extractFrame(FrameRect *rect) {
    248     status_t err = onExtractRect(rect);
    249     if (err == OK) {
    250         err = extractInternal();
    251     }
    252     if (err != OK) {
    253         return NULL;
    254     }
    255 
    256     return mFrames.size() > 0 ? mFrames[0] : NULL;
    257 }
    258 
    259 status_t FrameDecoder::extractFrames(std::vector<sp<IMemory> >* frames) {
    260     status_t err = extractInternal();
    261     if (err != OK) {
    262         return err;
    263     }
    264 
    265     for (size_t i = 0; i < mFrames.size(); i++) {
    266         frames->push_back(mFrames[i]);
    267     }
    268     return OK;
    269 }
    270 
    271 status_t FrameDecoder::extractInternal() {
    272     status_t err = OK;
    273     bool done = false;
    274     size_t retriesLeft = kRetryCount;
    275     do {
    276         size_t index;
    277         int64_t ptsUs = 0LL;
    278         uint32_t flags = 0;
    279 
    280         // Queue as many inputs as we possibly can, then block on dequeuing
    281         // outputs. After getting each output, come back and queue the inputs
    282         // again to keep the decoder busy.
    283         while (mHaveMoreInputs) {
    284             err = mDecoder->dequeueInputBuffer(&index, 0);
    285             if (err != OK) {
    286                 ALOGV("Timed out waiting for input");
    287                 if (retriesLeft) {
    288                     err = OK;
    289                 }
    290                 break;
    291             }
    292             sp<MediaCodecBuffer> codecBuffer;
    293             err = mDecoder->getInputBuffer(index, &codecBuffer);
    294             if (err != OK) {
    295                 ALOGE("failed to get input buffer %zu", index);
    296                 break;
    297             }
    298 
    299             MediaBufferBase *mediaBuffer = NULL;
    300 
    301             err = mSource->read(&mediaBuffer, &mReadOptions);
    302             mReadOptions.clearSeekTo();
    303             if (err != OK) {
    304                 mHaveMoreInputs = false;
    305                 if (!mFirstSample && err == ERROR_END_OF_STREAM) {
    306                     (void)mDecoder->queueInputBuffer(
    307                             index, 0, 0, 0, MediaCodec::BUFFER_FLAG_EOS);
    308                     err = OK;
    309                 } else {
    310                     ALOGW("Input Error: err=%d", err);
    311                 }
    312                 break;
    313             }
    314 
    315             if (mediaBuffer->range_length() > codecBuffer->capacity()) {
    316                 ALOGE("buffer size (%zu) too large for codec input size (%zu)",
    317                         mediaBuffer->range_length(), codecBuffer->capacity());
    318                 mHaveMoreInputs = false;
    319                 err = BAD_VALUE;
    320             } else {
    321                 codecBuffer->setRange(0, mediaBuffer->range_length());
    322 
    323                 CHECK(mediaBuffer->meta_data().findInt64(kKeyTime, &ptsUs));
    324                 memcpy(codecBuffer->data(),
    325                         (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
    326                         mediaBuffer->range_length());
    327 
    328                 onInputReceived(codecBuffer, mediaBuffer->meta_data(), mFirstSample, &flags);
    329                 mFirstSample = false;
    330             }
    331 
    332             mediaBuffer->release();
    333 
    334             if (mHaveMoreInputs) {
    335                 ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
    336                         codecBuffer->size(), ptsUs, flags);
    337 
    338                 err = mDecoder->queueInputBuffer(
    339                         index,
    340                         codecBuffer->offset(),
    341                         codecBuffer->size(),
    342                         ptsUs,
    343                         flags);
    344 
    345                 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
    346                     mHaveMoreInputs = false;
    347                 }
    348             }
    349         }
    350 
    351         while (err == OK) {
    352             size_t offset, size;
    353             // wait for a decoded buffer
    354             err = mDecoder->dequeueOutputBuffer(
    355                     &index,
    356                     &offset,
    357                     &size,
    358                     &ptsUs,
    359                     &flags,
    360                     kBufferTimeOutUs);
    361 
    362             if (err == INFO_FORMAT_CHANGED) {
    363                 ALOGV("Received format change");
    364                 err = mDecoder->getOutputFormat(&mOutputFormat);
    365             } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
    366                 ALOGV("Output buffers changed");
    367                 err = OK;
    368             } else {
    369                 if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
    370                     ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
    371                     err = OK;
    372                 } else if (err == OK) {
    373                     // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
    374                     // from the extractor, decode to the specified frame. Otherwise we're done.
    375                     ALOGV("Received an output buffer, timeUs=%lld", (long long)ptsUs);
    376                     sp<MediaCodecBuffer> videoFrameBuffer;
    377                     err = mDecoder->getOutputBuffer(index, &videoFrameBuffer);
    378                     if (err != OK) {
    379                         ALOGE("failed to get output buffer %zu", index);
    380                         break;
    381                     }
    382                     err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
    383                     mDecoder->releaseOutputBuffer(index);
    384                 } else {
    385                     ALOGW("Received error %d (%s) instead of output", err, asString(err));
    386                     done = true;
    387                 }
    388                 break;
    389             }
    390         }
    391     } while (err == OK && !done);
    392 
    393     if (err != OK) {
    394         ALOGE("failed to get video frame (err %d)", err);
    395     }
    396 
    397     return err;
    398 }
    399 
    400 //////////////////////////////////////////////////////////////////////
    401 
    402 VideoFrameDecoder::VideoFrameDecoder(
    403         const AString &componentName,
    404         const sp<MetaData> &trackMeta,
    405         const sp<IMediaSource> &source)
    406     : FrameDecoder(componentName, trackMeta, source),
    407       mIsAvcOrHevc(false),
    408       mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
    409       mTargetTimeUs(-1LL),
    410       mNumFrames(0),
    411       mNumFramesDecoded(0) {
    412 }
    413 
    414 sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
    415         int64_t frameTimeUs, size_t numFrames, int seekMode, MediaSource::ReadOptions *options) {
    416     mSeekMode = static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
    417     if (mSeekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
    418             mSeekMode > MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
    419         ALOGE("Unknown seek mode: %d", mSeekMode);
    420         return NULL;
    421     }
    422     mNumFrames = numFrames;
    423 
    424     const char *mime;
    425     if (!trackMeta()->findCString(kKeyMIMEType, &mime)) {
    426         ALOGE("Could not find mime type");
    427         return NULL;
    428     }
    429 
    430     mIsAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
    431             || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
    432 
    433     if (frameTimeUs < 0) {
    434         int64_t thumbNailTime = -1ll;
    435         if (!trackMeta()->findInt64(kKeyThumbnailTime, &thumbNailTime)
    436                 || thumbNailTime < 0) {
    437             thumbNailTime = 0;
    438         }
    439         options->setSeekTo(thumbNailTime, mSeekMode);
    440     } else {
    441         options->setSeekTo(frameTimeUs, mSeekMode);
    442     }
    443 
    444     sp<AMessage> videoFormat;
    445     if (convertMetaDataToMessage(trackMeta(), &videoFormat) != OK) {
    446         ALOGE("b/23680780");
    447         ALOGW("Failed to convert meta data to message");
    448         return NULL;
    449     }
    450 
    451     // TODO: Use Flexible color instead
    452     videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
    453 
    454     // For the thumbnail extraction case, try to allocate single buffer in both
    455     // input and output ports, if seeking to a sync frame. NOTE: This request may
    456     // fail if component requires more than that for decoding.
    457     bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
    458             || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
    459     if (!isSeekingClosest) {
    460         videoFormat->setInt32("android._num-input-buffers", 1);
    461         videoFormat->setInt32("android._num-output-buffers", 1);
    462     }
    463     return videoFormat;
    464 }
    465 
    466 status_t VideoFrameDecoder::onInputReceived(
    467         const sp<MediaCodecBuffer> &codecBuffer,
    468         MetaDataBase &sampleMeta, bool firstSample, uint32_t *flags) {
    469     bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
    470             || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
    471 
    472     if (firstSample && isSeekingClosest) {
    473         sampleMeta.findInt64(kKeyTargetTime, &mTargetTimeUs);
    474         ALOGV("Seeking closest: targetTimeUs=%lld", (long long)mTargetTimeUs);
    475     }
    476 
    477     if (mIsAvcOrHevc && !isSeekingClosest
    478             && IsIDR(codecBuffer->data(), codecBuffer->size())) {
    479         // Only need to decode one IDR frame, unless we're seeking with CLOSEST
    480         // option, in which case we need to actually decode to targetTimeUs.
    481         *flags |= MediaCodec::BUFFER_FLAG_EOS;
    482     }
    483     return OK;
    484 }
    485 
    486 status_t VideoFrameDecoder::onOutputReceived(
    487         const sp<MediaCodecBuffer> &videoFrameBuffer,
    488         const sp<AMessage> &outputFormat,
    489         int64_t timeUs, bool *done) {
    490     bool shouldOutput = (mTargetTimeUs < 0LL) || (timeUs >= mTargetTimeUs);
    491 
    492     // If this is not the target frame, skip color convert.
    493     if (!shouldOutput) {
    494         *done = false;
    495         return OK;
    496     }
    497 
    498     *done = (++mNumFramesDecoded >= mNumFrames);
    499 
    500     if (outputFormat == NULL) {
    501         return ERROR_MALFORMED;
    502     }
    503 
    504     int32_t width, height, stride, srcFormat;
    505     if (!outputFormat->findInt32("width", &width) ||
    506             !outputFormat->findInt32("height", &height) ||
    507             !outputFormat->findInt32("stride", &stride) ||
    508             !outputFormat->findInt32("color-format", &srcFormat)) {
    509         ALOGE("format missing dimension or color: %s",
    510                 outputFormat->debugString().c_str());
    511         return ERROR_MALFORMED;
    512     }
    513 
    514     int32_t crop_left, crop_top, crop_right, crop_bottom;
    515     if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
    516         crop_left = crop_top = 0;
    517         crop_right = width - 1;
    518         crop_bottom = height - 1;
    519     }
    520 
    521     sp<IMemory> frameMem = allocVideoFrame(
    522             trackMeta(),
    523             (crop_right - crop_left + 1),
    524             (crop_bottom - crop_top + 1),
    525             0,
    526             0,
    527             dstBpp());
    528     addFrame(frameMem);
    529     VideoFrame* frame = static_cast<VideoFrame*>(frameMem->pointer());
    530 
    531     ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
    532 
    533     uint32_t standard, range, transfer;
    534     if (!outputFormat->findInt32("color-standard", (int32_t*)&standard)) {
    535         standard = 0;
    536     }
    537     if (!outputFormat->findInt32("color-range", (int32_t*)&range)) {
    538         range = 0;
    539     }
    540     if (!outputFormat->findInt32("color-transfer", (int32_t*)&transfer)) {
    541         transfer = 0;
    542     }
    543     converter.setSrcColorSpace(standard, range, transfer);
    544 
    545     if (converter.isValid()) {
    546         converter.convert(
    547                 (const uint8_t *)videoFrameBuffer->data(),
    548                 width, height, stride,
    549                 crop_left, crop_top, crop_right, crop_bottom,
    550                 frame->getFlattenedData(),
    551                 frame->mWidth, frame->mHeight, frame->mRowBytes,
    552                 crop_left, crop_top, crop_right, crop_bottom);
    553         return OK;
    554     }
    555 
    556     ALOGE("Unable to convert from format 0x%08x to 0x%08x",
    557                 srcFormat, dstFormat());
    558     return ERROR_UNSUPPORTED;
    559 }
    560 
    561 ////////////////////////////////////////////////////////////////////////
    562 
    563 ImageDecoder::ImageDecoder(
    564         const AString &componentName,
    565         const sp<MetaData> &trackMeta,
    566         const sp<IMediaSource> &source)
    567     : FrameDecoder(componentName, trackMeta, source),
    568       mFrame(NULL),
    569       mWidth(0),
    570       mHeight(0),
    571       mGridRows(1),
    572       mGridCols(1),
    573       mTileWidth(0),
    574       mTileHeight(0),
    575       mTilesDecoded(0),
    576       mTargetTiles(0) {
    577 }
    578 
    579 sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
    580         int64_t frameTimeUs, size_t /*numFrames*/,
    581         int /*seekMode*/, MediaSource::ReadOptions *options) {
    582     sp<MetaData> overrideMeta;
    583     if (frameTimeUs < 0) {
    584         uint32_t type;
    585         const void *data;
    586         size_t size;
    587 
    588         // if we have a stand-alone thumbnail, set up the override meta,
    589         // and set seekTo time to -1.
    590         if (!findThumbnailInfo(trackMeta(), &mWidth, &mHeight, &type, &data, &size)) {
    591             ALOGE("Thumbnail not available");
    592             return NULL;
    593         }
    594         overrideMeta = new MetaData(*(trackMeta()));
    595         overrideMeta->remove(kKeyDisplayWidth);
    596         overrideMeta->remove(kKeyDisplayHeight);
    597         overrideMeta->setInt32(kKeyWidth, mWidth);
    598         overrideMeta->setInt32(kKeyHeight, mHeight);
    599         overrideMeta->setData(kKeyHVCC, type, data, size);
    600         options->setSeekTo(-1);
    601     } else {
    602         CHECK(trackMeta()->findInt32(kKeyWidth, &mWidth));
    603         CHECK(trackMeta()->findInt32(kKeyHeight, &mHeight));
    604 
    605         options->setSeekTo(frameTimeUs);
    606     }
    607 
    608     mGridRows = mGridCols = 1;
    609     if (overrideMeta == NULL) {
    610         // check if we're dealing with a tiled heif
    611         int32_t tileWidth, tileHeight, gridRows, gridCols;
    612         if (findGridInfo(trackMeta(), &tileWidth, &tileHeight, &gridRows, &gridCols)) {
    613             if (mWidth <= tileWidth * gridCols && mHeight <= tileHeight * gridRows) {
    614                 ALOGV("grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
    615                         gridCols, gridRows, tileWidth, tileHeight, mWidth, mHeight);
    616 
    617                 overrideMeta = new MetaData(*(trackMeta()));
    618                 overrideMeta->setInt32(kKeyWidth, tileWidth);
    619                 overrideMeta->setInt32(kKeyHeight, tileHeight);
    620                 mTileWidth = tileWidth;
    621                 mTileHeight = tileHeight;
    622                 mGridCols = gridCols;
    623                 mGridRows = gridRows;
    624             } else {
    625                 ALOGW("ignore bad grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
    626                         gridCols, gridRows, tileWidth, tileHeight, mWidth, mHeight);
    627             }
    628         }
    629         if (overrideMeta == NULL) {
    630             overrideMeta = trackMeta();
    631         }
    632     }
    633     mTargetTiles = mGridCols * mGridRows;
    634 
    635     sp<AMessage> videoFormat;
    636     if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
    637         ALOGE("b/23680780");
    638         ALOGW("Failed to convert meta data to message");
    639         return NULL;
    640     }
    641 
    642     // TODO: Use Flexible color instead
    643     videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
    644 
    645     if ((mGridRows == 1) && (mGridCols == 1)) {
    646         videoFormat->setInt32("android._num-input-buffers", 1);
    647         videoFormat->setInt32("android._num-output-buffers", 1);
    648     }
    649     return videoFormat;
    650 }
    651 
    652 status_t ImageDecoder::onExtractRect(FrameRect *rect) {
    653     // TODO:
    654     // This callback is for verifying whether we can decode the rect,
    655     // and if so, set up the internal variables for decoding.
    656     // Currently, rect decoding is restricted to sequentially decoding one
    657     // row of tiles at a time. We can't decode arbitrary rects, as the image
    658     // track doesn't yet support seeking by tiles. So all we do here is to
    659     // verify the rect against what we expect.
    660     // When seeking by tile is supported, this code should be updated to
    661     // set the seek parameters.
    662     if (rect == NULL) {
    663         if (mTilesDecoded > 0) {
    664             return ERROR_UNSUPPORTED;
    665         }
    666         mTargetTiles = mGridRows * mGridCols;
    667         return OK;
    668     }
    669 
    670     if (mTileWidth <= 0 || mTileHeight <=0) {
    671         return ERROR_UNSUPPORTED;
    672     }
    673 
    674     int32_t row = mTilesDecoded / mGridCols;
    675     int32_t expectedTop = row * mTileHeight;
    676     int32_t expectedBot = (row + 1) * mTileHeight;
    677     if (expectedBot > mHeight) {
    678         expectedBot = mHeight;
    679     }
    680     if (rect->left != 0 || rect->top != expectedTop
    681             || rect->right != mWidth || rect->bottom != expectedBot) {
    682         ALOGE("currently only support sequential decoding of slices");
    683         return ERROR_UNSUPPORTED;
    684     }
    685 
    686     // advance one row
    687     mTargetTiles = mTilesDecoded + mGridCols;
    688     return OK;
    689 }
    690 
    691 status_t ImageDecoder::onOutputReceived(
    692         const sp<MediaCodecBuffer> &videoFrameBuffer,
    693         const sp<AMessage> &outputFormat, int64_t /*timeUs*/, bool *done) {
    694     if (outputFormat == NULL) {
    695         return ERROR_MALFORMED;
    696     }
    697 
    698     int32_t width, height, stride;
    699     CHECK(outputFormat->findInt32("width", &width));
    700     CHECK(outputFormat->findInt32("height", &height));
    701     CHECK(outputFormat->findInt32("stride", &stride));
    702 
    703     if (mFrame == NULL) {
    704         sp<IMemory> frameMem = allocVideoFrame(
    705                 trackMeta(), mWidth, mHeight, mTileWidth, mTileHeight, dstBpp());
    706         mFrame = static_cast<VideoFrame*>(frameMem->pointer());
    707 
    708         addFrame(frameMem);
    709     }
    710 
    711     int32_t srcFormat;
    712     CHECK(outputFormat->findInt32("color-format", &srcFormat));
    713 
    714     ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
    715 
    716     uint32_t standard, range, transfer;
    717     if (!outputFormat->findInt32("color-standard", (int32_t*)&standard)) {
    718         standard = 0;
    719     }
    720     if (!outputFormat->findInt32("color-range", (int32_t*)&range)) {
    721         range = 0;
    722     }
    723     if (!outputFormat->findInt32("color-transfer", (int32_t*)&transfer)) {
    724         transfer = 0;
    725     }
    726     converter.setSrcColorSpace(standard, range, transfer);
    727 
    728     int32_t dstLeft, dstTop, dstRight, dstBottom;
    729     dstLeft = mTilesDecoded % mGridCols * width;
    730     dstTop = mTilesDecoded / mGridCols * height;
    731     dstRight = dstLeft + width - 1;
    732     dstBottom = dstTop + height - 1;
    733 
    734     int32_t crop_left, crop_top, crop_right, crop_bottom;
    735     if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
    736         crop_left = crop_top = 0;
    737         crop_right = width - 1;
    738         crop_bottom = height - 1;
    739     }
    740 
    741     // apply crop on bottom-right
    742     // TODO: need to move this into the color converter itself.
    743     if (dstRight >= mWidth) {
    744         crop_right = mWidth - dstLeft - 1;
    745         dstRight = dstLeft + crop_right;
    746     }
    747     if (dstBottom >= mHeight) {
    748         crop_bottom = mHeight - dstTop - 1;
    749         dstBottom = dstTop + crop_bottom;
    750     }
    751 
    752     *done = (++mTilesDecoded >= mTargetTiles);
    753 
    754     if (converter.isValid()) {
    755         converter.convert(
    756                 (const uint8_t *)videoFrameBuffer->data(),
    757                 width, height, stride,
    758                 crop_left, crop_top, crop_right, crop_bottom,
    759                 mFrame->getFlattenedData(),
    760                 mFrame->mWidth, mFrame->mHeight, mFrame->mRowBytes,
    761                 dstLeft, dstTop, dstRight, dstBottom);
    762         return OK;
    763     }
    764 
    765     ALOGE("Unable to convert from format 0x%08x to 0x%08x",
    766                 srcFormat, dstFormat());
    767     return ERROR_UNSUPPORTED;
    768 }
    769 
    770 }  // namespace android
    771