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
40namespace android {
41
42static const int64_t kBufferTimeOutUs = 10000ll; // 10 msec
43static const size_t kRetryCount = 50; // must be >0
44
45sp<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
97bool 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
109bool 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
117bool 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
150sp<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
177FrameDecoder::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
190FrameDecoder::~FrameDecoder() {
191    if (mDecoder != NULL) {
192        mDecoder->release();
193        mSource->stop();
194    }
195}
196
197status_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
247sp<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
259status_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
271status_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                ALOGW("Input Error or EOS");
305                mHaveMoreInputs = false;
306                if (!mFirstSample && err == ERROR_END_OF_STREAM) {
307                    err = OK;
308                }
309                break;
310            }
311
312            if (mediaBuffer->range_length() > codecBuffer->capacity()) {
313                ALOGE("buffer size (%zu) too large for codec input size (%zu)",
314                        mediaBuffer->range_length(), codecBuffer->capacity());
315                mHaveMoreInputs = false;
316                err = BAD_VALUE;
317            } else {
318                codecBuffer->setRange(0, mediaBuffer->range_length());
319
320                CHECK(mediaBuffer->meta_data().findInt64(kKeyTime, &ptsUs));
321                memcpy(codecBuffer->data(),
322                        (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
323                        mediaBuffer->range_length());
324
325                onInputReceived(codecBuffer, mediaBuffer->meta_data(), mFirstSample, &flags);
326                mFirstSample = false;
327            }
328
329            mediaBuffer->release();
330
331            if (mHaveMoreInputs) {
332                ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
333                        codecBuffer->size(), ptsUs, flags);
334
335                err = mDecoder->queueInputBuffer(
336                        index,
337                        codecBuffer->offset(),
338                        codecBuffer->size(),
339                        ptsUs,
340                        flags);
341
342                if (flags & MediaCodec::BUFFER_FLAG_EOS) {
343                    mHaveMoreInputs = false;
344                }
345            }
346        }
347
348        while (err == OK) {
349            size_t offset, size;
350            // wait for a decoded buffer
351            err = mDecoder->dequeueOutputBuffer(
352                    &index,
353                    &offset,
354                    &size,
355                    &ptsUs,
356                    &flags,
357                    kBufferTimeOutUs);
358
359            if (err == INFO_FORMAT_CHANGED) {
360                ALOGV("Received format change");
361                err = mDecoder->getOutputFormat(&mOutputFormat);
362            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
363                ALOGV("Output buffers changed");
364                err = OK;
365            } else {
366                if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
367                    ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
368                    err = OK;
369                } else if (err == OK) {
370                    // If we're seeking with CLOSEST option and obtained a valid targetTimeUs
371                    // from the extractor, decode to the specified frame. Otherwise we're done.
372                    ALOGV("Received an output buffer, timeUs=%lld", (long long)ptsUs);
373                    sp<MediaCodecBuffer> videoFrameBuffer;
374                    err = mDecoder->getOutputBuffer(index, &videoFrameBuffer);
375                    if (err != OK) {
376                        ALOGE("failed to get output buffer %zu", index);
377                        break;
378                    }
379                    err = onOutputReceived(videoFrameBuffer, mOutputFormat, ptsUs, &done);
380                    mDecoder->releaseOutputBuffer(index);
381                } else {
382                    ALOGW("Received error %d (%s) instead of output", err, asString(err));
383                    done = true;
384                }
385                break;
386            }
387        }
388    } while (err == OK && !done);
389
390    if (err != OK) {
391        ALOGE("failed to get video frame (err %d)", err);
392    }
393
394    return err;
395}
396
397//////////////////////////////////////////////////////////////////////
398
399VideoFrameDecoder::VideoFrameDecoder(
400        const AString &componentName,
401        const sp<MetaData> &trackMeta,
402        const sp<IMediaSource> &source)
403    : FrameDecoder(componentName, trackMeta, source),
404      mIsAvcOrHevc(false),
405      mSeekMode(MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC),
406      mTargetTimeUs(-1ll),
407      mNumFrames(0),
408      mNumFramesDecoded(0) {
409}
410
411sp<AMessage> VideoFrameDecoder::onGetFormatAndSeekOptions(
412        int64_t frameTimeUs, size_t numFrames, int seekMode, MediaSource::ReadOptions *options) {
413    mSeekMode = static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
414    if (mSeekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
415            mSeekMode > MediaSource::ReadOptions::SEEK_FRAME_INDEX) {
416        ALOGE("Unknown seek mode: %d", mSeekMode);
417        return NULL;
418    }
419    mNumFrames = numFrames;
420
421    const char *mime;
422    if (!trackMeta()->findCString(kKeyMIMEType, &mime)) {
423        ALOGE("Could not find mime type");
424        return NULL;
425    }
426
427    mIsAvcOrHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)
428            || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
429
430    if (frameTimeUs < 0) {
431        int64_t thumbNailTime;
432        if (!trackMeta()->findInt64(kKeyThumbnailTime, &thumbNailTime)
433                || thumbNailTime < 0) {
434            thumbNailTime = 0;
435        }
436        options->setSeekTo(thumbNailTime, mSeekMode);
437    } else {
438        options->setSeekTo(frameTimeUs, mSeekMode);
439    }
440
441    sp<AMessage> videoFormat;
442    if (convertMetaDataToMessage(trackMeta(), &videoFormat) != OK) {
443        ALOGE("b/23680780");
444        ALOGW("Failed to convert meta data to message");
445        return NULL;
446    }
447
448    // TODO: Use Flexible color instead
449    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
450
451    // For the thumbnail extraction case, try to allocate single buffer in both
452    // input and output ports, if seeking to a sync frame. NOTE: This request may
453    // fail if component requires more than that for decoding.
454    bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
455            || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
456    if (!isSeekingClosest) {
457        videoFormat->setInt32("android._num-input-buffers", 1);
458        videoFormat->setInt32("android._num-output-buffers", 1);
459    }
460    return videoFormat;
461}
462
463status_t VideoFrameDecoder::onInputReceived(
464        const sp<MediaCodecBuffer> &codecBuffer,
465        MetaDataBase &sampleMeta, bool firstSample, uint32_t *flags) {
466    bool isSeekingClosest = (mSeekMode == MediaSource::ReadOptions::SEEK_CLOSEST)
467            || (mSeekMode == MediaSource::ReadOptions::SEEK_FRAME_INDEX);
468
469    if (firstSample && isSeekingClosest) {
470        sampleMeta.findInt64(kKeyTargetTime, &mTargetTimeUs);
471        ALOGV("Seeking closest: targetTimeUs=%lld", (long long)mTargetTimeUs);
472    }
473
474    if (mIsAvcOrHevc && !isSeekingClosest
475            && IsIDR(codecBuffer->data(), codecBuffer->size())) {
476        // Only need to decode one IDR frame, unless we're seeking with CLOSEST
477        // option, in which case we need to actually decode to targetTimeUs.
478        *flags |= MediaCodec::BUFFER_FLAG_EOS;
479    }
480    return OK;
481}
482
483status_t VideoFrameDecoder::onOutputReceived(
484        const sp<MediaCodecBuffer> &videoFrameBuffer,
485        const sp<AMessage> &outputFormat,
486        int64_t timeUs, bool *done) {
487    bool shouldOutput = (mTargetTimeUs < 0ll) || (timeUs >= mTargetTimeUs);
488
489    // If this is not the target frame, skip color convert.
490    if (!shouldOutput) {
491        *done = false;
492        return OK;
493    }
494
495    *done = (++mNumFramesDecoded >= mNumFrames);
496
497    if (outputFormat == NULL) {
498        return ERROR_MALFORMED;
499    }
500
501    int32_t width, height;
502    CHECK(outputFormat->findInt32("width", &width));
503    CHECK(outputFormat->findInt32("height", &height));
504
505    int32_t crop_left, crop_top, crop_right, crop_bottom;
506    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
507        crop_left = crop_top = 0;
508        crop_right = width - 1;
509        crop_bottom = height - 1;
510    }
511
512    sp<IMemory> frameMem = allocVideoFrame(
513            trackMeta(),
514            (crop_right - crop_left + 1),
515            (crop_bottom - crop_top + 1),
516            0,
517            0,
518            dstBpp());
519    addFrame(frameMem);
520    VideoFrame* frame = static_cast<VideoFrame*>(frameMem->pointer());
521
522    int32_t srcFormat;
523    CHECK(outputFormat->findInt32("color-format", &srcFormat));
524
525    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
526
527    if (converter.isValid()) {
528        converter.convert(
529                (const uint8_t *)videoFrameBuffer->data(),
530                width, height,
531                crop_left, crop_top, crop_right, crop_bottom,
532                frame->getFlattenedData(),
533                frame->mWidth,
534                frame->mHeight,
535                crop_left, crop_top, crop_right, crop_bottom);
536        return OK;
537    }
538
539    ALOGE("Unable to convert from format 0x%08x to 0x%08x",
540                srcFormat, dstFormat());
541    return ERROR_UNSUPPORTED;
542}
543
544////////////////////////////////////////////////////////////////////////
545
546ImageDecoder::ImageDecoder(
547        const AString &componentName,
548        const sp<MetaData> &trackMeta,
549        const sp<IMediaSource> &source)
550    : FrameDecoder(componentName, trackMeta, source),
551      mFrame(NULL),
552      mWidth(0),
553      mHeight(0),
554      mGridRows(1),
555      mGridCols(1),
556      mTileWidth(0),
557      mTileHeight(0),
558      mTilesDecoded(0),
559      mTargetTiles(0) {
560}
561
562sp<AMessage> ImageDecoder::onGetFormatAndSeekOptions(
563        int64_t frameTimeUs, size_t /*numFrames*/,
564        int /*seekMode*/, MediaSource::ReadOptions *options) {
565    sp<MetaData> overrideMeta;
566    if (frameTimeUs < 0) {
567        uint32_t type;
568        const void *data;
569        size_t size;
570
571        // if we have a stand-alone thumbnail, set up the override meta,
572        // and set seekTo time to -1.
573        if (!findThumbnailInfo(trackMeta(), &mWidth, &mHeight, &type, &data, &size)) {
574            ALOGE("Thumbnail not available");
575            return NULL;
576        }
577        overrideMeta = new MetaData(*(trackMeta()));
578        overrideMeta->remove(kKeyDisplayWidth);
579        overrideMeta->remove(kKeyDisplayHeight);
580        overrideMeta->setInt32(kKeyWidth, mWidth);
581        overrideMeta->setInt32(kKeyHeight, mHeight);
582        overrideMeta->setData(kKeyHVCC, type, data, size);
583        options->setSeekTo(-1);
584    } else {
585        CHECK(trackMeta()->findInt32(kKeyWidth, &mWidth));
586        CHECK(trackMeta()->findInt32(kKeyHeight, &mHeight));
587
588        options->setSeekTo(frameTimeUs);
589    }
590
591    mGridRows = mGridCols = 1;
592    if (overrideMeta == NULL) {
593        // check if we're dealing with a tiled heif
594        int32_t tileWidth, tileHeight, gridRows, gridCols;
595        if (findGridInfo(trackMeta(), &tileWidth, &tileHeight, &gridRows, &gridCols)) {
596            if (mWidth <= tileWidth * gridCols && mHeight <= tileHeight * gridRows) {
597                ALOGV("grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
598                        gridCols, gridRows, tileWidth, tileHeight, mWidth, mHeight);
599
600                overrideMeta = new MetaData(*(trackMeta()));
601                overrideMeta->setInt32(kKeyWidth, tileWidth);
602                overrideMeta->setInt32(kKeyHeight, tileHeight);
603                mTileWidth = tileWidth;
604                mTileHeight = tileHeight;
605                mGridCols = gridCols;
606                mGridRows = gridRows;
607            } else {
608                ALOGW("ignore bad grid: %dx%d, tile size: %dx%d, picture size: %dx%d",
609                        gridCols, gridRows, tileWidth, tileHeight, mWidth, mHeight);
610            }
611        }
612        if (overrideMeta == NULL) {
613            overrideMeta = trackMeta();
614        }
615    }
616    mTargetTiles = mGridCols * mGridRows;
617
618    sp<AMessage> videoFormat;
619    if (convertMetaDataToMessage(overrideMeta, &videoFormat) != OK) {
620        ALOGE("b/23680780");
621        ALOGW("Failed to convert meta data to message");
622        return NULL;
623    }
624
625    // TODO: Use Flexible color instead
626    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
627
628    if ((mGridRows == 1) && (mGridCols == 1)) {
629        videoFormat->setInt32("android._num-input-buffers", 1);
630        videoFormat->setInt32("android._num-output-buffers", 1);
631    }
632    return videoFormat;
633}
634
635status_t ImageDecoder::onExtractRect(FrameRect *rect) {
636    // TODO:
637    // This callback is for verifying whether we can decode the rect,
638    // and if so, set up the internal variables for decoding.
639    // Currently, rect decoding is restricted to sequentially decoding one
640    // row of tiles at a time. We can't decode arbitrary rects, as the image
641    // track doesn't yet support seeking by tiles. So all we do here is to
642    // verify the rect against what we expect.
643    // When seeking by tile is supported, this code should be updated to
644    // set the seek parameters.
645    if (rect == NULL) {
646        if (mTilesDecoded > 0) {
647            return ERROR_UNSUPPORTED;
648        }
649        mTargetTiles = mGridRows * mGridCols;
650        return OK;
651    }
652
653    if (mTileWidth <= 0 || mTileHeight <=0) {
654        return ERROR_UNSUPPORTED;
655    }
656
657    int32_t row = mTilesDecoded / mGridCols;
658    int32_t expectedTop = row * mTileHeight;
659    int32_t expectedBot = (row + 1) * mTileHeight;
660    if (expectedBot > mHeight) {
661        expectedBot = mHeight;
662    }
663    if (rect->left != 0 || rect->top != expectedTop
664            || rect->right != mWidth || rect->bottom != expectedBot) {
665        ALOGE("currently only support sequential decoding of slices");
666        return ERROR_UNSUPPORTED;
667    }
668
669    // advance one row
670    mTargetTiles = mTilesDecoded + mGridCols;
671    return OK;
672}
673
674status_t ImageDecoder::onOutputReceived(
675        const sp<MediaCodecBuffer> &videoFrameBuffer,
676        const sp<AMessage> &outputFormat, int64_t /*timeUs*/, bool *done) {
677    if (outputFormat == NULL) {
678        return ERROR_MALFORMED;
679    }
680
681    int32_t width, height;
682    CHECK(outputFormat->findInt32("width", &width));
683    CHECK(outputFormat->findInt32("height", &height));
684
685    if (mFrame == NULL) {
686        sp<IMemory> frameMem = allocVideoFrame(
687                trackMeta(), mWidth, mHeight, mTileWidth, mTileHeight, dstBpp());
688        mFrame = static_cast<VideoFrame*>(frameMem->pointer());
689
690        addFrame(frameMem);
691    }
692
693    int32_t srcFormat;
694    CHECK(outputFormat->findInt32("color-format", &srcFormat));
695
696    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
697
698    int32_t dstLeft, dstTop, dstRight, dstBottom;
699    dstLeft = mTilesDecoded % mGridCols * width;
700    dstTop = mTilesDecoded / mGridCols * height;
701    dstRight = dstLeft + width - 1;
702    dstBottom = dstTop + height - 1;
703
704    int32_t crop_left, crop_top, crop_right, crop_bottom;
705    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
706        crop_left = crop_top = 0;
707        crop_right = width - 1;
708        crop_bottom = height - 1;
709    }
710
711    // apply crop on bottom-right
712    // TODO: need to move this into the color converter itself.
713    if (dstRight >= mWidth) {
714        crop_right = mWidth - dstLeft - 1;
715        dstRight = dstLeft + crop_right;
716    }
717    if (dstBottom >= mHeight) {
718        crop_bottom = mHeight - dstTop - 1;
719        dstBottom = dstTop + crop_bottom;
720    }
721
722    *done = (++mTilesDecoded >= mTargetTiles);
723
724    if (converter.isValid()) {
725        converter.convert(
726                (const uint8_t *)videoFrameBuffer->data(),
727                width, height,
728                crop_left, crop_top, crop_right, crop_bottom,
729                mFrame->getFlattenedData(),
730                mFrame->mWidth,
731                mFrame->mHeight,
732                dstLeft, dstTop, dstRight, dstBottom);
733        return OK;
734    }
735
736    ALOGE("Unable to convert from format 0x%08x to 0x%08x",
737                srcFormat, dstFormat());
738    return ERROR_UNSUPPORTED;
739}
740
741}  // namespace android
742