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 
32 namespace android {
33 
34 template<class T>
InitOMXParams(T * params)35 static 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 
SoftVideoDecoderOMXComponent(const char * name,const char * componentRole,OMX_VIDEO_CODINGTYPE codingType,const CodecProfileLevel * profileLevels,size_t numProfileLevels,int32_t width,int32_t height,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)43 SoftVideoDecoderOMXComponent::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 
initPorts(OMX_U32 numInputBuffers,OMX_U32 inputBufferSize,OMX_U32 numOutputBuffers,const char * mimeType,OMX_U32 minCompressionRatio)81 void 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 
initPorts(OMX_U32 numMinInputBuffers,OMX_U32 numInputBuffers,OMX_U32 inputBufferSize,OMX_U32 numMinOutputBuffers,OMX_U32 numOutputBuffers,const char * mimeType,OMX_U32 minCompressionRatio)91 void 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 
updatePortDefinitions(bool updateCrop,bool updateInputSize)152 void 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.nSliceHeight = outDef->format.video.nFrameHeight;
158 
159     int32_t bpp = (mOutputFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
160     outDef->format.video.nStride = outDef->format.video.nFrameWidth * bpp;
161     outDef->nBufferSize =
162             (outDef->format.video.nStride * outDef->format.video.nSliceHeight * 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 
outputBufferWidth()187 uint32_t SoftVideoDecoderOMXComponent::outputBufferWidth() {
188     return max(mIsAdaptive ? mAdaptiveMaxWidth : 0, mWidth);
189 }
190 
outputBufferHeight()191 uint32_t SoftVideoDecoderOMXComponent::outputBufferHeight() {
192     return max(mIsAdaptive ? mAdaptiveMaxHeight : 0, mHeight);
193 }
194 
handlePortSettingsChange(bool * portWillReset,uint32_t width,uint32_t height,OMX_COLOR_FORMATTYPE outputFormat,CropSettingsMode cropSettingsMode,bool fakeStride)195 void 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 
dumpColorAspects(const ColorAspects & colorAspects)262 void 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 
colorAspectsDiffer(const ColorAspects & a,const ColorAspects & b)270 bool 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 
updateFinalColorAspects(const ColorAspects & otherAspects,const ColorAspects & preferredAspects)281 void 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 
handleColorAspectsChange()301 status_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 
copyYV12FrameToOutputBuffer(uint8_t * dst,const uint8_t * srcY,const uint8_t * srcU,const uint8_t * srcV,size_t srcYStride,size_t srcUStride,size_t srcVStride)315 void 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 
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)347 OMX_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 
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)410 OMX_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->nStride < -32768
506                     || video_def->nSliceHeight > 32768) {
507                 ALOGE("b/22885421");
508                 return OMX_ErrorBadParameter;
509             }
510             if (newWidth != oldWidth || newHeight != oldHeight) {
511                 bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
512                 if (outputPort) {
513                     // only update (essentially crop) if size changes
514                     mWidth = newWidth;
515                     mHeight = newHeight;
516 
517                     updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
518                     // reset buffer size based on frame size
519                     newParams->nBufferSize = def->nBufferSize;
520                 } else {
521                     // For input port, we only set nFrameWidth and nFrameHeight. Buffer size
522                     // is updated when configuring the output port using the max-frame-size,
523                     // though client can still request a larger size.
524                     def->format.video.nFrameWidth = newWidth;
525                     def->format.video.nFrameHeight = newHeight;
526                 }
527             }
528             return SimpleSoftOMXComponent::internalSetParameter(index, params);
529         }
530 
531         default:
532             return SimpleSoftOMXComponent::internalSetParameter(index, params);
533     }
534 }
535 
getConfig(OMX_INDEXTYPE index,OMX_PTR params)536 OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getConfig(
537         OMX_INDEXTYPE index, OMX_PTR params) {
538     switch ((int)index) {
539         case OMX_IndexConfigCommonOutputCrop:
540         {
541             OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
542 
543             if (!isValidOMXParam(rectParams)) {
544                 return OMX_ErrorBadParameter;
545             }
546 
547             if (rectParams->nPortIndex != kOutputPortIndex) {
548                 return OMX_ErrorUndefined;
549             }
550 
551             rectParams->nLeft = mCropLeft;
552             rectParams->nTop = mCropTop;
553             rectParams->nWidth = mCropWidth;
554             rectParams->nHeight = mCropHeight;
555 
556             return OMX_ErrorNone;
557         }
558         case kDescribeColorAspectsIndex:
559         {
560             if (!supportsDescribeColorAspects()) {
561                 return OMX_ErrorUnsupportedIndex;
562             }
563 
564             DescribeColorAspectsParams* colorAspectsParams =
565                     (DescribeColorAspectsParams *)params;
566 
567             if (!isValidOMXParam(colorAspectsParams)) {
568                 return OMX_ErrorBadParameter;
569             }
570 
571             if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
572                 return OMX_ErrorBadParameter;
573             }
574 
575             colorAspectsParams->sAspects = mFinalColorAspects;
576             if (colorAspectsParams->bRequestingDataSpace || colorAspectsParams->bDataSpaceChanged) {
577                 return OMX_ErrorUnsupportedSetting;
578             }
579 
580             return OMX_ErrorNone;
581         }
582 
583         case kDescribeHdrStaticInfoIndex:
584         {
585             if (!supportDescribeHdrStaticInfo()) {
586                 return OMX_ErrorUnsupportedIndex;
587             }
588 
589             DescribeHDRStaticInfoParams* hdrStaticInfoParams =
590                     (DescribeHDRStaticInfoParams *)params;
591 
592             if (!isValidOMXParam(hdrStaticInfoParams)) {
593                 return OMX_ErrorBadParameter;
594             }
595 
596             if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
597                 return OMX_ErrorBadPortIndex;
598             }
599 
600             hdrStaticInfoParams->sInfo = mHdrStaticInfo;
601 
602             return OMX_ErrorNone;
603         }
604 
605         case kDescribeHdr10PlusInfoIndex:
606         {
607             if (!supportDescribeHdr10PlusInfo()) {
608                 return OMX_ErrorUnsupportedIndex;
609             }
610 
611             if (mHdr10PlusOutputs.size() > 0) {
612                 auto it = mHdr10PlusOutputs.begin();
613 
614                 auto info = (*it).get();
615 
616                 DescribeHDR10PlusInfoParams* outParams =
617                         (DescribeHDR10PlusInfoParams *)params;
618 
619                 outParams->nParamSizeUsed = info->size();
620 
621                 // If the buffer provided by the client does not have enough
622                 // storage, return the size only and do not remove the param yet.
623                 if (outParams->nParamSize >= info->size()) {
624                     memcpy(outParams->nValue, info->data(), info->size());
625                     mHdr10PlusOutputs.erase(it);
626                 }
627                 return OMX_ErrorNone;
628             }
629             return OMX_ErrorUnderflow;
630         }
631 
632         default:
633             return OMX_ErrorUnsupportedIndex;
634     }
635 }
636 
internalSetConfig(OMX_INDEXTYPE index,const OMX_PTR params,bool * frameConfig)637 OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalSetConfig(
638         OMX_INDEXTYPE index, const OMX_PTR params, bool *frameConfig){
639     switch ((int)index) {
640         case kDescribeColorAspectsIndex:
641         {
642             if (!supportsDescribeColorAspects()) {
643                 return OMX_ErrorUnsupportedIndex;
644             }
645             const DescribeColorAspectsParams* colorAspectsParams =
646                     (const DescribeColorAspectsParams *)params;
647 
648             if (!isValidOMXParam(colorAspectsParams)) {
649                 return OMX_ErrorBadParameter;
650             }
651 
652             if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
653                 return OMX_ErrorBadParameter;
654             }
655 
656             // Update color aspects if necessary.
657             if (colorAspectsDiffer(colorAspectsParams->sAspects, mDefaultColorAspects)) {
658                 mDefaultColorAspects = colorAspectsParams->sAspects;
659                 status_t err = handleColorAspectsChange();
660                 CHECK(err == OK);
661             }
662             return OMX_ErrorNone;
663         }
664 
665         case kDescribeHdrStaticInfoIndex:
666         {
667             if (!supportDescribeHdrStaticInfo()) {
668                 return OMX_ErrorUnsupportedIndex;
669             }
670 
671             const DescribeHDRStaticInfoParams* hdrStaticInfoParams =
672                     (DescribeHDRStaticInfoParams *)params;
673 
674             if (!isValidOMXParam(hdrStaticInfoParams)) {
675                 return OMX_ErrorBadParameter;
676             }
677 
678             if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
679                 return OMX_ErrorBadPortIndex;
680             }
681 
682             mHdrStaticInfo = hdrStaticInfoParams->sInfo;
683             updatePortDefinitions(false);
684 
685             return OMX_ErrorNone;
686         }
687 
688         case kDescribeHdr10PlusInfoIndex:
689         {
690             if (!supportDescribeHdr10PlusInfo()) {
691                 return OMX_ErrorUnsupportedIndex;
692             }
693 
694             const DescribeHDR10PlusInfoParams* inParams =
695                     (DescribeHDR10PlusInfoParams *)params;
696 
697             if (*frameConfig) {
698                 // This is a request to append to the current frame config set.
699                 // For now, we only support kDescribeHdr10PlusInfoIndex, which
700                 // we simply replace with the last set value.
701                 if (mHdr10PlusInputs.size() > 0) {
702                     *(--mHdr10PlusInputs.end()) = ABuffer::CreateAsCopy(
703                             inParams->nValue, inParams->nParamSizeUsed);
704                 } else {
705                     ALOGW("Ignoring kDescribeHdr10PlusInfoIndex: append to "
706                             "frame config while no frame config is present");
707                 }
708             } else {
709                 // This is a frame config, setting *frameConfig to true so that
710                 // the client marks the next queued input frame to apply it.
711                 *frameConfig = true;
712                 mHdr10PlusInputs.push_back(ABuffer::CreateAsCopy(
713                         inParams->nValue, inParams->nParamSizeUsed));
714             }
715             return OMX_ErrorNone;
716         }
717 
718         default:
719             return OMX_ErrorUnsupportedIndex;
720     }
721 }
722 
dequeueInputFrameConfig()723 sp<ABuffer> SoftVideoDecoderOMXComponent::dequeueInputFrameConfig() {
724     auto it = mHdr10PlusInputs.begin();
725     sp<ABuffer> info = *it;
726     mHdr10PlusInputs.erase(it);
727     return info;
728 }
729 
queueOutputFrameConfig(const sp<ABuffer> & info)730 void SoftVideoDecoderOMXComponent::queueOutputFrameConfig(const sp<ABuffer> &info) {
731     mHdr10PlusOutputs.push_back(info);
732     notify(OMX_EventConfigUpdate,
733            kOutputPortIndex,
734            kDescribeHdr10PlusInfoIndex,
735            NULL);
736 }
737 
getExtensionIndex(const char * name,OMX_INDEXTYPE * index)738 OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getExtensionIndex(
739         const char *name, OMX_INDEXTYPE *index) {
740     if (!strcmp(name, "OMX.google.android.index.prepareForAdaptivePlayback")) {
741         *(int32_t*)index = kPrepareForAdaptivePlaybackIndex;
742         return OMX_ErrorNone;
743     } else if (!strcmp(name, "OMX.google.android.index.describeColorAspects")
744                 && supportsDescribeColorAspects()) {
745         *(int32_t*)index = kDescribeColorAspectsIndex;
746         return OMX_ErrorNone;
747     } else if (!strcmp(name, "OMX.google.android.index.describeHDRStaticInfo")
748             && supportDescribeHdrStaticInfo()) {
749         *(int32_t*)index = kDescribeHdrStaticInfoIndex;
750         return OMX_ErrorNone;
751     } else if (!strcmp(name, "OMX.google.android.index.describeHDR10PlusInfo")
752             && supportDescribeHdr10PlusInfo()) {
753         *(int32_t*)index = kDescribeHdr10PlusInfoIndex;
754         return OMX_ErrorNone;
755     }
756 
757     return SimpleSoftOMXComponent::getExtensionIndex(name, index);
758 }
759 
supportsDescribeColorAspects()760 bool SoftVideoDecoderOMXComponent::supportsDescribeColorAspects() {
761     return getColorAspectPreference() != kNotSupported;
762 }
763 
getColorAspectPreference()764 int SoftVideoDecoderOMXComponent::getColorAspectPreference() {
765     return kNotSupported;
766 }
767 
supportDescribeHdrStaticInfo()768 bool SoftVideoDecoderOMXComponent::supportDescribeHdrStaticInfo() {
769     return false;
770 }
771 
supportDescribeHdr10PlusInfo()772 bool SoftVideoDecoderOMXComponent::supportDescribeHdr10PlusInfo() {
773     return false;
774 }
775 
onReset()776 void SoftVideoDecoderOMXComponent::onReset() {
777     mOutputPortSettingsChange = NONE;
778 }
779 
onPortEnableCompleted(OMX_U32 portIndex,bool enabled)780 void SoftVideoDecoderOMXComponent::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
781     if (portIndex != kOutputPortIndex) {
782         return;
783     }
784 
785     switch (mOutputPortSettingsChange) {
786         case NONE:
787             break;
788 
789         case AWAITING_DISABLED:
790         {
791             CHECK(!enabled);
792             mOutputPortSettingsChange = AWAITING_ENABLED;
793             break;
794         }
795 
796         default:
797         {
798             CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
799             CHECK(enabled);
800             mOutputPortSettingsChange = NONE;
801             break;
802         }
803     }
804 }
805 
806 }  // namespace android
807