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