SoftVideoDecoderOMXComponent.cpp revision 58c4cf4540e3f23847196bd4b45d82613e238821
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/MediaDefs.h> 30 31namespace android { 32 33template<class T> 34static void InitOMXParams(T *params) { 35 params->nSize = sizeof(T); 36 params->nVersion.s.nVersionMajor = 1; 37 params->nVersion.s.nVersionMinor = 0; 38 params->nVersion.s.nRevision = 0; 39 params->nVersion.s.nStep = 0; 40} 41 42SoftVideoDecoderOMXComponent::SoftVideoDecoderOMXComponent( 43 const char *name, 44 const char *componentRole, 45 OMX_VIDEO_CODINGTYPE codingType, 46 const CodecProfileLevel *profileLevels, 47 size_t numProfileLevels, 48 int32_t width, 49 int32_t height, 50 const OMX_CALLBACKTYPE *callbacks, 51 OMX_PTR appData, 52 OMX_COMPONENTTYPE **component) 53 : SimpleSoftOMXComponent(name, callbacks, appData, component), 54 mIsAdaptive(false), 55 mAdaptiveMaxWidth(0), 56 mAdaptiveMaxHeight(0), 57 mWidth(width), 58 mHeight(height), 59 mCropLeft(0), 60 mCropTop(0), 61 mCropWidth(width), 62 mCropHeight(height), 63 mOutputPortSettingsChange(NONE), 64 mComponentRole(componentRole), 65 mCodingType(codingType), 66 mProfileLevels(profileLevels), 67 mNumProfileLevels(numProfileLevels) { 68} 69 70void SoftVideoDecoderOMXComponent::initPorts( 71 OMX_U32 numInputBuffers, 72 OMX_U32 inputBufferSize, 73 OMX_U32 numOutputBuffers, 74 const char *mimeType) { 75 OMX_PARAM_PORTDEFINITIONTYPE def; 76 InitOMXParams(&def); 77 78 def.nPortIndex = kInputPortIndex; 79 def.eDir = OMX_DirInput; 80 def.nBufferCountMin = numInputBuffers; 81 def.nBufferCountActual = def.nBufferCountMin; 82 def.nBufferSize = inputBufferSize; 83 def.bEnabled = OMX_TRUE; 84 def.bPopulated = OMX_FALSE; 85 def.eDomain = OMX_PortDomainVideo; 86 def.bBuffersContiguous = OMX_FALSE; 87 def.nBufferAlignment = 1; 88 89 def.format.video.cMIMEType = const_cast<char *>(mimeType); 90 def.format.video.pNativeRender = NULL; 91 /* size is initialized in updatePortDefinitions() */ 92 def.format.video.nBitrate = 0; 93 def.format.video.xFramerate = 0; 94 def.format.video.bFlagErrorConcealment = OMX_FALSE; 95 def.format.video.eCompressionFormat = mCodingType; 96 def.format.video.eColorFormat = OMX_COLOR_FormatUnused; 97 def.format.video.pNativeWindow = NULL; 98 99 addPort(def); 100 101 def.nPortIndex = kOutputPortIndex; 102 def.eDir = OMX_DirOutput; 103 def.nBufferCountMin = numOutputBuffers; 104 def.nBufferCountActual = def.nBufferCountMin; 105 def.bEnabled = OMX_TRUE; 106 def.bPopulated = OMX_FALSE; 107 def.eDomain = OMX_PortDomainVideo; 108 def.bBuffersContiguous = OMX_FALSE; 109 def.nBufferAlignment = 2; 110 111 def.format.video.cMIMEType = const_cast<char *>("video/raw"); 112 def.format.video.pNativeRender = NULL; 113 /* size is initialized in updatePortDefinitions() */ 114 def.format.video.nBitrate = 0; 115 def.format.video.xFramerate = 0; 116 def.format.video.bFlagErrorConcealment = OMX_FALSE; 117 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 118 def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; 119 def.format.video.pNativeWindow = NULL; 120 121 addPort(def); 122 123 updatePortDefinitions(); 124} 125 126void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) { 127 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; 128 def->format.video.nFrameWidth = mWidth; 129 def->format.video.nFrameHeight = mHeight; 130 def->format.video.nStride = def->format.video.nFrameWidth; 131 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 132 133 def->nBufferSize = def->format.video.nFrameWidth * def->format.video.nFrameHeight * 3 / 2; 134 135 def = &editPortInfo(kOutputPortIndex)->mDef; 136 def->format.video.nFrameWidth = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; 137 def->format.video.nFrameHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; 138 def->format.video.nStride = def->format.video.nFrameWidth; 139 def->format.video.nSliceHeight = def->format.video.nFrameHeight; 140 141 def->nBufferSize = 142 (def->format.video.nFrameWidth * 143 def->format.video.nFrameHeight * 3) / 2; 144 145 if (updateCrop) { 146 mCropLeft = 0; 147 mCropTop = 0; 148 mCropWidth = mWidth; 149 mCropHeight = mHeight; 150 } 151} 152 153void SoftVideoDecoderOMXComponent::handlePortSettingsChange( 154 bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged) { 155 *portWillReset = false; 156 bool sizeChanged = (width != mWidth || height != mHeight); 157 158 if (sizeChanged || cropChanged) { 159 mWidth = width; 160 mHeight = height; 161 162 bool updateCrop = !cropChanged; 163 if ((sizeChanged && !mIsAdaptive) 164 || width > mAdaptiveMaxWidth 165 || height > mAdaptiveMaxHeight) { 166 if (mIsAdaptive) { 167 if (width > mAdaptiveMaxWidth) { 168 mAdaptiveMaxWidth = width; 169 } 170 if (height > mAdaptiveMaxHeight) { 171 mAdaptiveMaxHeight = height; 172 } 173 } 174 updatePortDefinitions(updateCrop); 175 notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL); 176 mOutputPortSettingsChange = AWAITING_DISABLED; 177 *portWillReset = true; 178 } else { 179 updatePortDefinitions(updateCrop); 180 notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 181 OMX_IndexConfigCommonOutputCrop, NULL); 182 } 183 } 184} 185 186void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer( 187 uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, 188 size_t srcYStride, size_t srcUStride, size_t srcVStride) { 189 size_t dstYStride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth; 190 size_t dstUVStride = dstYStride / 2; 191 size_t dstHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight; 192 uint8_t *dstStart = dst; 193 194 for (size_t i = 0; i < mHeight; ++i) { 195 memcpy(dst, srcY, mWidth); 196 srcY += srcYStride; 197 dst += dstYStride; 198 } 199 200 dst = dstStart + dstYStride * dstHeight; 201 for (size_t i = 0; i < mHeight / 2; ++i) { 202 memcpy(dst, srcU, mWidth / 2); 203 srcU += srcUStride; 204 dst += dstUVStride; 205 } 206 207 dst = dstStart + (5 * dstYStride * dstHeight) / 4; 208 for (size_t i = 0; i < mHeight / 2; ++i) { 209 memcpy(dst, srcV, mWidth / 2); 210 srcV += srcVStride; 211 dst += dstUVStride; 212 } 213} 214 215OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter( 216 OMX_INDEXTYPE index, OMX_PTR params) { 217 switch (index) { 218 case OMX_IndexParamVideoPortFormat: 219 { 220 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 221 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 222 223 if (formatParams->nPortIndex > kMaxPortIndex) { 224 return OMX_ErrorUndefined; 225 } 226 227 if (formatParams->nIndex != 0) { 228 return OMX_ErrorNoMore; 229 } 230 231 if (formatParams->nPortIndex == kInputPortIndex) { 232 formatParams->eCompressionFormat = mCodingType; 233 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 234 formatParams->xFramerate = 0; 235 } else { 236 CHECK_EQ(formatParams->nPortIndex, 1u); 237 238 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 239 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; 240 formatParams->xFramerate = 0; 241 } 242 243 return OMX_ErrorNone; 244 } 245 246 case OMX_IndexParamVideoProfileLevelQuerySupported: 247 { 248 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel = 249 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params; 250 251 if (profileLevel->nPortIndex != kInputPortIndex) { 252 ALOGE("Invalid port index: %" PRIu32, profileLevel->nPortIndex); 253 return OMX_ErrorUnsupportedIndex; 254 } 255 256 if (profileLevel->nProfileIndex >= mNumProfileLevels) { 257 return OMX_ErrorNoMore; 258 } 259 260 profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile; 261 profileLevel->eLevel = mProfileLevels[profileLevel->nProfileIndex].mLevel; 262 return OMX_ErrorNone; 263 } 264 265 default: 266 return SimpleSoftOMXComponent::internalGetParameter(index, params); 267 } 268} 269 270OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalSetParameter( 271 OMX_INDEXTYPE index, const OMX_PTR params) { 272 // Include extension index OMX_INDEXEXTTYPE. 273 const int32_t indexFull = index; 274 275 switch (indexFull) { 276 case OMX_IndexParamStandardComponentRole: 277 { 278 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 279 (const OMX_PARAM_COMPONENTROLETYPE *)params; 280 281 if (strncmp((const char *)roleParams->cRole, 282 mComponentRole, 283 OMX_MAX_STRINGNAME_SIZE - 1)) { 284 return OMX_ErrorUndefined; 285 } 286 287 return OMX_ErrorNone; 288 } 289 290 case OMX_IndexParamVideoPortFormat: 291 { 292 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 293 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 294 295 if (formatParams->nPortIndex > kMaxPortIndex) { 296 return OMX_ErrorUndefined; 297 } 298 299 if (formatParams->nIndex != 0) { 300 return OMX_ErrorNoMore; 301 } 302 303 return OMX_ErrorNone; 304 } 305 306 case kPrepareForAdaptivePlaybackIndex: 307 { 308 const PrepareForAdaptivePlaybackParams* adaptivePlaybackParams = 309 (const PrepareForAdaptivePlaybackParams *)params; 310 mIsAdaptive = adaptivePlaybackParams->bEnable; 311 if (mIsAdaptive) { 312 mAdaptiveMaxWidth = adaptivePlaybackParams->nMaxFrameWidth; 313 mAdaptiveMaxHeight = adaptivePlaybackParams->nMaxFrameHeight; 314 mWidth = mAdaptiveMaxWidth; 315 mHeight = mAdaptiveMaxHeight; 316 } else { 317 mAdaptiveMaxWidth = 0; 318 mAdaptiveMaxHeight = 0; 319 } 320 updatePortDefinitions(); 321 return OMX_ErrorNone; 322 } 323 324 default: 325 return SimpleSoftOMXComponent::internalSetParameter(index, params); 326 } 327} 328 329OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getConfig( 330 OMX_INDEXTYPE index, OMX_PTR params) { 331 switch (index) { 332 case OMX_IndexConfigCommonOutputCrop: 333 { 334 OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params; 335 336 if (rectParams->nPortIndex != kOutputPortIndex) { 337 return OMX_ErrorUndefined; 338 } 339 340 rectParams->nLeft = mCropLeft; 341 rectParams->nTop = mCropTop; 342 rectParams->nWidth = mCropWidth; 343 rectParams->nHeight = mCropHeight; 344 345 return OMX_ErrorNone; 346 } 347 348 default: 349 return OMX_ErrorUnsupportedIndex; 350 } 351} 352 353OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getExtensionIndex( 354 const char *name, OMX_INDEXTYPE *index) { 355 if (!strcmp(name, "OMX.google.android.index.prepareForAdaptivePlayback")) { 356 *(int32_t*)index = kPrepareForAdaptivePlaybackIndex; 357 return OMX_ErrorNone; 358 } 359 360 return SimpleSoftOMXComponent::getExtensionIndex(name, index); 361} 362 363void SoftVideoDecoderOMXComponent::onReset() { 364 mOutputPortSettingsChange = NONE; 365} 366 367void SoftVideoDecoderOMXComponent::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 368 if (portIndex != kOutputPortIndex) { 369 return; 370 } 371 372 switch (mOutputPortSettingsChange) { 373 case NONE: 374 break; 375 376 case AWAITING_DISABLED: 377 { 378 CHECK(!enabled); 379 mOutputPortSettingsChange = AWAITING_ENABLED; 380 break; 381 } 382 383 default: 384 { 385 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 386 CHECK(enabled); 387 mOutputPortSettingsChange = NONE; 388 break; 389 } 390 } 391} 392 393} // namespace android 394