1/*
2 * Copyright (C) 2013 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#include <inttypes.h>
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "SoftVideoDecoderOMXComponent"
21#include <utils/Log.h>
22
23#include "include/SoftVideoDecoderOMXComponent.h"
24
25#include <media/hardware/HardwareAPI.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/ALooper.h>
28#include <media/stagefright/foundation/AMessage.h>
29#include <media/stagefright/foundation/AUtils.h>
30#include <media/stagefright/MediaDefs.h>
31
32namespace android {
33
34template<class T>
35static void InitOMXParams(T *params) {
36    params->nSize = sizeof(T);
37    params->nVersion.s.nVersionMajor = 1;
38    params->nVersion.s.nVersionMinor = 0;
39    params->nVersion.s.nRevision = 0;
40    params->nVersion.s.nStep = 0;
41}
42
43SoftVideoDecoderOMXComponent::SoftVideoDecoderOMXComponent(
44        const char *name,
45        const char *componentRole,
46        OMX_VIDEO_CODINGTYPE codingType,
47        const CodecProfileLevel *profileLevels,
48        size_t numProfileLevels,
49        int32_t width,
50        int32_t height,
51        const OMX_CALLBACKTYPE *callbacks,
52        OMX_PTR appData,
53        OMX_COMPONENTTYPE **component)
54        : SimpleSoftOMXComponent(name, callbacks, appData, component),
55        mIsAdaptive(false),
56        mAdaptiveMaxWidth(0),
57        mAdaptiveMaxHeight(0),
58        mWidth(width),
59        mHeight(height),
60        mCropLeft(0),
61        mCropTop(0),
62        mCropWidth(width),
63        mCropHeight(height),
64        mOutputPortSettingsChange(NONE),
65        mMinInputBufferSize(384), // arbitrary, using one uncompressed macroblock
66        mMinCompressionRatio(1),  // max input size is normally the output size
67        mComponentRole(componentRole),
68        mCodingType(codingType),
69        mProfileLevels(profileLevels),
70        mNumProfileLevels(numProfileLevels) {
71
72    // init all the color aspects to be Unspecified.
73    memset(&mDefaultColorAspects, 0, sizeof(ColorAspects));
74    memset(&mBitstreamColorAspects, 0, sizeof(ColorAspects));
75    memset(&mFinalColorAspects, 0, sizeof(ColorAspects));
76}
77
78void SoftVideoDecoderOMXComponent::initPorts(
79        OMX_U32 numInputBuffers,
80        OMX_U32 inputBufferSize,
81        OMX_U32 numOutputBuffers,
82        const char *mimeType,
83        OMX_U32 minCompressionRatio) {
84    initPorts(numInputBuffers, numInputBuffers, inputBufferSize,
85            numOutputBuffers, numOutputBuffers, mimeType, minCompressionRatio);
86}
87
88void SoftVideoDecoderOMXComponent::initPorts(
89        OMX_U32 numMinInputBuffers,
90        OMX_U32 numInputBuffers,
91        OMX_U32 inputBufferSize,
92        OMX_U32 numMinOutputBuffers,
93        OMX_U32 numOutputBuffers,
94        const char *mimeType,
95        OMX_U32 minCompressionRatio) {
96    mMinInputBufferSize = inputBufferSize;
97    mMinCompressionRatio = minCompressionRatio;
98
99    OMX_PARAM_PORTDEFINITIONTYPE def;
100    InitOMXParams(&def);
101
102    def.nPortIndex = kInputPortIndex;
103    def.eDir = OMX_DirInput;
104    def.nBufferCountMin = numMinInputBuffers;
105    def.nBufferCountActual = numInputBuffers;
106    def.nBufferSize = inputBufferSize;
107    def.bEnabled = OMX_TRUE;
108    def.bPopulated = OMX_FALSE;
109    def.eDomain = OMX_PortDomainVideo;
110    def.bBuffersContiguous = OMX_FALSE;
111    def.nBufferAlignment = 1;
112
113    def.format.video.cMIMEType = const_cast<char *>(mimeType);
114    def.format.video.pNativeRender = NULL;
115    /* size is initialized in updatePortDefinitions() */
116    def.format.video.nBitrate = 0;
117    def.format.video.xFramerate = 0;
118    def.format.video.bFlagErrorConcealment = OMX_FALSE;
119    def.format.video.eCompressionFormat = mCodingType;
120    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
121    def.format.video.pNativeWindow = NULL;
122
123    addPort(def);
124
125    def.nPortIndex = kOutputPortIndex;
126    def.eDir = OMX_DirOutput;
127    def.nBufferCountMin = numMinOutputBuffers;
128    def.nBufferCountActual = numOutputBuffers;
129    def.bEnabled = OMX_TRUE;
130    def.bPopulated = OMX_FALSE;
131    def.eDomain = OMX_PortDomainVideo;
132    def.bBuffersContiguous = OMX_FALSE;
133    def.nBufferAlignment = 2;
134
135    def.format.video.cMIMEType = const_cast<char *>("video/raw");
136    def.format.video.pNativeRender = NULL;
137    /* size is initialized in updatePortDefinitions() */
138    def.format.video.nBitrate = 0;
139    def.format.video.xFramerate = 0;
140    def.format.video.bFlagErrorConcealment = OMX_FALSE;
141    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
142    def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
143    def.format.video.pNativeWindow = NULL;
144
145    addPort(def);
146
147    updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
148}
149
150void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop, bool updateInputSize) {
151    OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
152    outDef->format.video.nFrameWidth = outputBufferWidth();
153    outDef->format.video.nFrameHeight = outputBufferHeight();
154    outDef->format.video.nStride = outDef->format.video.nFrameWidth;
155    outDef->format.video.nSliceHeight = outDef->format.video.nFrameHeight;
156
157    outDef->nBufferSize =
158        (outDef->format.video.nStride * outDef->format.video.nSliceHeight * 3) / 2;
159
160    OMX_PARAM_PORTDEFINITIONTYPE *inDef = &editPortInfo(kInputPortIndex)->mDef;
161    inDef->format.video.nFrameWidth = mWidth;
162    inDef->format.video.nFrameHeight = mHeight;
163    // input port is compressed, hence it has no stride
164    inDef->format.video.nStride = 0;
165    inDef->format.video.nSliceHeight = 0;
166
167    // when output format changes, input buffer size does not actually change
168    if (updateInputSize) {
169        inDef->nBufferSize = max(
170                outDef->nBufferSize / mMinCompressionRatio,
171                max(mMinInputBufferSize, inDef->nBufferSize));
172    }
173
174    if (updateCrop) {
175        mCropLeft = 0;
176        mCropTop = 0;
177        mCropWidth = mWidth;
178        mCropHeight = mHeight;
179    }
180}
181
182
183uint32_t SoftVideoDecoderOMXComponent::outputBufferWidth() {
184    return mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
185}
186
187uint32_t SoftVideoDecoderOMXComponent::outputBufferHeight() {
188    return mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
189}
190
191void SoftVideoDecoderOMXComponent::handlePortSettingsChange(
192        bool *portWillReset, uint32_t width, uint32_t height,
193        CropSettingsMode cropSettingsMode, bool fakeStride) {
194    *portWillReset = false;
195    bool sizeChanged = (width != mWidth || height != mHeight);
196    bool updateCrop = (cropSettingsMode == kCropUnSet);
197    bool cropChanged = (cropSettingsMode == kCropChanged);
198    bool strideChanged = false;
199    if (fakeStride) {
200        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
201        if (def->format.video.nStride != (OMX_S32)width
202                || def->format.video.nSliceHeight != (OMX_U32)height) {
203            strideChanged = true;
204        }
205    }
206
207    if (sizeChanged || cropChanged || strideChanged) {
208        mWidth = width;
209        mHeight = height;
210
211        if ((sizeChanged && !mIsAdaptive)
212            || width > mAdaptiveMaxWidth
213            || height > mAdaptiveMaxHeight) {
214            if (mIsAdaptive) {
215                if (width > mAdaptiveMaxWidth) {
216                    mAdaptiveMaxWidth = width;
217                }
218                if (height > mAdaptiveMaxHeight) {
219                    mAdaptiveMaxHeight = height;
220                }
221            }
222            updatePortDefinitions(updateCrop);
223            notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL);
224            mOutputPortSettingsChange = AWAITING_DISABLED;
225            *portWillReset = true;
226        } else {
227            updatePortDefinitions(updateCrop);
228
229            if (fakeStride) {
230                // MAJOR HACK that is not pretty, it's just to fool the renderer to read the correct
231                // data.
232                // Some software decoders (e.g. SoftMPEG4) fill decoded frame directly to output
233                // buffer without considering the output buffer stride and slice height. So this is
234                // used to signal how the buffer is arranged.  The alternative is to re-arrange the
235                // output buffer in SoftMPEG4, but that results in memcopies.
236                OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
237                def->format.video.nStride = mWidth;
238                def->format.video.nSliceHeight = mHeight;
239            }
240
241            notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
242                   OMX_IndexConfigCommonOutputCrop, NULL);
243        }
244    } else if (mUpdateColorAspects) {
245        notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
246                kDescribeColorAspectsIndex, NULL);
247        mUpdateColorAspects = false;
248    }
249}
250
251void SoftVideoDecoderOMXComponent::dumpColorAspects(const ColorAspects &colorAspects) {
252    ALOGD("dumpColorAspects: (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) ",
253            colorAspects.mRange, asString(colorAspects.mRange),
254            colorAspects.mPrimaries, asString(colorAspects.mPrimaries),
255            colorAspects.mMatrixCoeffs, asString(colorAspects.mMatrixCoeffs),
256            colorAspects.mTransfer, asString(colorAspects.mTransfer));
257}
258
259bool SoftVideoDecoderOMXComponent::colorAspectsDiffer(
260        const ColorAspects &a, const ColorAspects &b) {
261    if (a.mRange != b.mRange
262        || a.mPrimaries != b.mPrimaries
263        || a.mTransfer != b.mTransfer
264        || a.mMatrixCoeffs != b.mMatrixCoeffs) {
265        return true;
266    }
267    return false;
268}
269
270void SoftVideoDecoderOMXComponent::updateFinalColorAspects(
271        const ColorAspects &otherAspects, const ColorAspects &preferredAspects) {
272    Mutex::Autolock autoLock(mColorAspectsLock);
273    ColorAspects newAspects;
274    newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ?
275        preferredAspects.mRange : otherAspects.mRange;
276    newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ?
277        preferredAspects.mPrimaries : otherAspects.mPrimaries;
278    newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ?
279        preferredAspects.mTransfer : otherAspects.mTransfer;
280    newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ?
281        preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs;
282
283    // Check to see if need update mFinalColorAspects.
284    if (colorAspectsDiffer(mFinalColorAspects, newAspects)) {
285        mFinalColorAspects = newAspects;
286        mUpdateColorAspects = true;
287    }
288}
289
290status_t SoftVideoDecoderOMXComponent::handleColorAspectsChange() {
291    int perference = getColorAspectPreference();
292    ALOGD("Color Aspects preference: %d ", perference);
293
294    if (perference == kPreferBitstream) {
295        updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
296    } else if (perference == kPreferContainer) {
297        updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects);
298    } else {
299        return OMX_ErrorUnsupportedSetting;
300    }
301    return OK;
302}
303
304void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer(
305        uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
306        size_t srcYStride, size_t srcUStride, size_t srcVStride) {
307    size_t dstYStride = outputBufferWidth();
308    size_t dstUVStride = dstYStride / 2;
309    size_t dstHeight = outputBufferHeight();
310    uint8_t *dstStart = dst;
311
312    for (size_t i = 0; i < mHeight; ++i) {
313         memcpy(dst, srcY, mWidth);
314         srcY += srcYStride;
315         dst += dstYStride;
316    }
317
318    dst = dstStart + dstYStride * dstHeight;
319    for (size_t i = 0; i < mHeight / 2; ++i) {
320         memcpy(dst, srcU, mWidth / 2);
321         srcU += srcUStride;
322         dst += dstUVStride;
323    }
324
325    dst = dstStart + (5 * dstYStride * dstHeight) / 4;
326    for (size_t i = 0; i < mHeight / 2; ++i) {
327         memcpy(dst, srcV, mWidth / 2);
328         srcV += srcVStride;
329         dst += dstUVStride;
330    }
331}
332
333OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter(
334        OMX_INDEXTYPE index, OMX_PTR params) {
335    switch (index) {
336        case OMX_IndexParamVideoPortFormat:
337        {
338            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
339                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
340
341            if (!isValidOMXParam(formatParams)) {
342                return OMX_ErrorBadParameter;
343            }
344
345            if (formatParams->nPortIndex > kMaxPortIndex) {
346                return OMX_ErrorBadPortIndex;
347            }
348
349            if (formatParams->nIndex != 0) {
350                return OMX_ErrorNoMore;
351            }
352
353            if (formatParams->nPortIndex == kInputPortIndex) {
354                formatParams->eCompressionFormat = mCodingType;
355                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
356                formatParams->xFramerate = 0;
357            } else {
358                CHECK_EQ(formatParams->nPortIndex, 1u);
359
360                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
361                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
362                formatParams->xFramerate = 0;
363            }
364
365            return OMX_ErrorNone;
366        }
367
368        case OMX_IndexParamVideoProfileLevelQuerySupported:
369        {
370            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
371                  (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
372
373            if (!isValidOMXParam(profileLevel)) {
374                return OMX_ErrorBadParameter;
375            }
376
377            if (profileLevel->nPortIndex != kInputPortIndex) {
378                ALOGE("Invalid port index: %" PRIu32, profileLevel->nPortIndex);
379                return OMX_ErrorUnsupportedIndex;
380            }
381
382            if (profileLevel->nProfileIndex >= mNumProfileLevels) {
383                return OMX_ErrorNoMore;
384            }
385
386            profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile;
387            profileLevel->eLevel   = mProfileLevels[profileLevel->nProfileIndex].mLevel;
388            return OMX_ErrorNone;
389        }
390
391        default:
392            return SimpleSoftOMXComponent::internalGetParameter(index, params);
393    }
394}
395
396OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalSetParameter(
397        OMX_INDEXTYPE index, const OMX_PTR params) {
398    // Include extension index OMX_INDEXEXTTYPE.
399    const int32_t indexFull = index;
400
401    switch (indexFull) {
402        case OMX_IndexParamStandardComponentRole:
403        {
404            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
405                (const OMX_PARAM_COMPONENTROLETYPE *)params;
406
407            if (!isValidOMXParam(roleParams)) {
408                return OMX_ErrorBadParameter;
409            }
410
411            if (strncmp((const char *)roleParams->cRole,
412                        mComponentRole,
413                        OMX_MAX_STRINGNAME_SIZE - 1)) {
414                return OMX_ErrorUndefined;
415            }
416
417            return OMX_ErrorNone;
418        }
419
420        case OMX_IndexParamVideoPortFormat:
421        {
422            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
423                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
424
425            if (!isValidOMXParam(formatParams)) {
426                return OMX_ErrorBadParameter;
427            }
428
429            if (formatParams->nPortIndex > kMaxPortIndex) {
430                return OMX_ErrorBadPortIndex;
431            }
432
433            if (formatParams->nIndex != 0) {
434                return OMX_ErrorNoMore;
435            }
436
437            if (formatParams->nPortIndex == kInputPortIndex) {
438                if (formatParams->eCompressionFormat != mCodingType
439                        || formatParams->eColorFormat != OMX_COLOR_FormatUnused) {
440                    return OMX_ErrorUnsupportedSetting;
441                }
442            } else {
443                if (formatParams->eCompressionFormat != OMX_VIDEO_CodingUnused
444                        || formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) {
445                    return OMX_ErrorUnsupportedSetting;
446                }
447            }
448
449            return OMX_ErrorNone;
450        }
451
452        case kPrepareForAdaptivePlaybackIndex:
453        {
454            const PrepareForAdaptivePlaybackParams* adaptivePlaybackParams =
455                    (const PrepareForAdaptivePlaybackParams *)params;
456
457            if (!isValidOMXParam(adaptivePlaybackParams)) {
458                return OMX_ErrorBadParameter;
459            }
460
461            mIsAdaptive = adaptivePlaybackParams->bEnable;
462            if (mIsAdaptive) {
463                mAdaptiveMaxWidth = adaptivePlaybackParams->nMaxFrameWidth;
464                mAdaptiveMaxHeight = adaptivePlaybackParams->nMaxFrameHeight;
465                mWidth = mAdaptiveMaxWidth;
466                mHeight = mAdaptiveMaxHeight;
467            } else {
468                mAdaptiveMaxWidth = 0;
469                mAdaptiveMaxHeight = 0;
470            }
471            updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
472            return OMX_ErrorNone;
473        }
474
475        case OMX_IndexParamPortDefinition:
476        {
477            OMX_PARAM_PORTDEFINITIONTYPE *newParams =
478                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
479
480            if (!isValidOMXParam(newParams)) {
481                return OMX_ErrorBadParameter;
482            }
483
484            OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video;
485            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef;
486
487            uint32_t oldWidth = def->format.video.nFrameWidth;
488            uint32_t oldHeight = def->format.video.nFrameHeight;
489            uint32_t newWidth = video_def->nFrameWidth;
490            uint32_t newHeight = video_def->nFrameHeight;
491            // We need width, height, stride and slice-height to be non-zero and sensible.
492            // These values were chosen to prevent integer overflows further down the line, and do
493            // not indicate support for 32kx32k video.
494            if (newWidth > 32768 || newHeight > 32768
495                    || video_def->nStride > 32768 || video_def->nSliceHeight > 32768) {
496                ALOGE("b/22885421");
497                return OMX_ErrorBadParameter;
498            }
499            if (newWidth != oldWidth || newHeight != oldHeight) {
500                bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
501                if (outputPort) {
502                    // only update (essentially crop) if size changes
503                    mWidth = newWidth;
504                    mHeight = newHeight;
505
506                    updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
507                    // reset buffer size based on frame size
508                    newParams->nBufferSize = def->nBufferSize;
509                } else {
510                    // For input port, we only set nFrameWidth and nFrameHeight. Buffer size
511                    // is updated when configuring the output port using the max-frame-size,
512                    // though client can still request a larger size.
513                    def->format.video.nFrameWidth = newWidth;
514                    def->format.video.nFrameHeight = newHeight;
515                }
516            }
517            return SimpleSoftOMXComponent::internalSetParameter(index, params);
518        }
519
520        default:
521            return SimpleSoftOMXComponent::internalSetParameter(index, params);
522    }
523}
524
525OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getConfig(
526        OMX_INDEXTYPE index, OMX_PTR params) {
527    switch ((int)index) {
528        case OMX_IndexConfigCommonOutputCrop:
529        {
530            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
531
532            if (!isValidOMXParam(rectParams)) {
533                return OMX_ErrorBadParameter;
534            }
535
536            if (rectParams->nPortIndex != kOutputPortIndex) {
537                return OMX_ErrorUndefined;
538            }
539
540            rectParams->nLeft = mCropLeft;
541            rectParams->nTop = mCropTop;
542            rectParams->nWidth = mCropWidth;
543            rectParams->nHeight = mCropHeight;
544
545            return OMX_ErrorNone;
546        }
547        case kDescribeColorAspectsIndex:
548        {
549            if (!supportsDescribeColorAspects()) {
550                return OMX_ErrorUnsupportedIndex;
551            }
552
553            DescribeColorAspectsParams* colorAspectsParams =
554                    (DescribeColorAspectsParams *)params;
555
556            if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
557                return OMX_ErrorBadParameter;
558            }
559
560            colorAspectsParams->sAspects = mFinalColorAspects;
561            if (colorAspectsParams->bRequestingDataSpace || colorAspectsParams->bDataSpaceChanged) {
562                return OMX_ErrorUnsupportedSetting;
563            }
564
565            return OMX_ErrorNone;
566        }
567
568        default:
569            return OMX_ErrorUnsupportedIndex;
570    }
571}
572
573OMX_ERRORTYPE SoftVideoDecoderOMXComponent::setConfig(
574        OMX_INDEXTYPE index, const OMX_PTR params){
575    switch ((int)index) {
576        case kDescribeColorAspectsIndex:
577        {
578            if (!supportsDescribeColorAspects()) {
579                return OMX_ErrorUnsupportedIndex;
580            }
581            const DescribeColorAspectsParams* colorAspectsParams =
582                    (const DescribeColorAspectsParams *)params;
583
584            if (!isValidOMXParam(colorAspectsParams)) {
585                return OMX_ErrorBadParameter;
586            }
587
588            if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
589                return OMX_ErrorBadParameter;
590            }
591
592            // Update color aspects if necessary.
593            if (colorAspectsDiffer(colorAspectsParams->sAspects, mDefaultColorAspects)) {
594                mDefaultColorAspects = colorAspectsParams->sAspects;
595                status_t err = handleColorAspectsChange();
596                CHECK(err == OK);
597            }
598            return OMX_ErrorNone;
599        }
600
601        default:
602            return OMX_ErrorUnsupportedIndex;
603    }
604}
605
606
607OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getExtensionIndex(
608        const char *name, OMX_INDEXTYPE *index) {
609    if (!strcmp(name, "OMX.google.android.index.prepareForAdaptivePlayback")) {
610        *(int32_t*)index = kPrepareForAdaptivePlaybackIndex;
611        return OMX_ErrorNone;
612    } else if (!strcmp(name, "OMX.google.android.index.describeColorAspects")
613                && supportsDescribeColorAspects()) {
614        *(int32_t*)index = kDescribeColorAspectsIndex;
615        return OMX_ErrorNone;
616    }
617
618    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
619}
620
621bool SoftVideoDecoderOMXComponent::supportsDescribeColorAspects() {
622    return getColorAspectPreference() != kNotSupported;
623}
624
625int SoftVideoDecoderOMXComponent::getColorAspectPreference() {
626    return kNotSupported;
627}
628
629void SoftVideoDecoderOMXComponent::onReset() {
630    mOutputPortSettingsChange = NONE;
631}
632
633void SoftVideoDecoderOMXComponent::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
634    if (portIndex != kOutputPortIndex) {
635        return;
636    }
637
638    switch (mOutputPortSettingsChange) {
639        case NONE:
640            break;
641
642        case AWAITING_DISABLED:
643        {
644            CHECK(!enabled);
645            mOutputPortSettingsChange = AWAITING_ENABLED;
646            break;
647        }
648
649        default:
650        {
651            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
652            CHECK(enabled);
653            mOutputPortSettingsChange = NONE;
654            break;
655        }
656    }
657}
658
659}  // namespace android
660