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