SoftVideoDecoderOMXComponent.cpp revision 1aa26f787afc525e0deae31d856dce74a4b28a0f
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 = outputBufferWidth(); 137 def->format.video.nFrameHeight = outputBufferHeight(); 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 153 154uint32_t SoftVideoDecoderOMXComponent::outputBufferWidth() { 155 return mIsAdaptive ? mAdaptiveMaxWidth : mWidth; 156} 157 158uint32_t SoftVideoDecoderOMXComponent::outputBufferHeight() { 159 return mIsAdaptive ? mAdaptiveMaxHeight : mHeight; 160} 161 162void SoftVideoDecoderOMXComponent::handlePortSettingsChange( 163 bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged, bool fakeStride) { 164 *portWillReset = false; 165 bool sizeChanged = (width != mWidth || height != mHeight); 166 167 if (sizeChanged || cropChanged) { 168 mWidth = width; 169 mHeight = height; 170 171 bool updateCrop = !cropChanged; 172 if ((sizeChanged && !mIsAdaptive) 173 || width > mAdaptiveMaxWidth 174 || height > mAdaptiveMaxHeight) { 175 if (mIsAdaptive) { 176 if (width > mAdaptiveMaxWidth) { 177 mAdaptiveMaxWidth = width; 178 } 179 if (height > mAdaptiveMaxHeight) { 180 mAdaptiveMaxHeight = height; 181 } 182 } 183 updatePortDefinitions(updateCrop); 184 notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL); 185 mOutputPortSettingsChange = AWAITING_DISABLED; 186 *portWillReset = true; 187 } else { 188 updatePortDefinitions(updateCrop); 189 190 if (fakeStride) { 191 // MAJOR HACK that is not pretty, it's just to fool the renderer to read the correct 192 // data. 193 // Some software decoders (e.g. SoftMPEG4) fill decoded frame directly to output 194 // buffer without considering the output buffer stride and slice height. So this is 195 // used to signal how the buffer is arranged. The alternative is to re-arrange the 196 // output buffer in SoftMPEG4, but that results in memcopies. 197 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; 198 def->format.video.nStride = mWidth; 199 def->format.video.nSliceHeight = mHeight; 200 } 201 202 notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 203 OMX_IndexConfigCommonOutputCrop, NULL); 204 } 205 } 206} 207 208void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer( 209 uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV, 210 size_t srcYStride, size_t srcUStride, size_t srcVStride) { 211 size_t dstYStride = outputBufferWidth(); 212 size_t dstUVStride = dstYStride / 2; 213 size_t dstHeight = outputBufferHeight(); 214 uint8_t *dstStart = dst; 215 216 for (size_t i = 0; i < mHeight; ++i) { 217 memcpy(dst, srcY, mWidth); 218 srcY += srcYStride; 219 dst += dstYStride; 220 } 221 222 dst = dstStart + dstYStride * dstHeight; 223 for (size_t i = 0; i < mHeight / 2; ++i) { 224 memcpy(dst, srcU, mWidth / 2); 225 srcU += srcUStride; 226 dst += dstUVStride; 227 } 228 229 dst = dstStart + (5 * dstYStride * dstHeight) / 4; 230 for (size_t i = 0; i < mHeight / 2; ++i) { 231 memcpy(dst, srcV, mWidth / 2); 232 srcV += srcVStride; 233 dst += dstUVStride; 234 } 235} 236 237OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter( 238 OMX_INDEXTYPE index, OMX_PTR params) { 239 switch (index) { 240 case OMX_IndexParamVideoPortFormat: 241 { 242 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 243 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 244 245 if (formatParams->nPortIndex > kMaxPortIndex) { 246 return OMX_ErrorUndefined; 247 } 248 249 if (formatParams->nIndex != 0) { 250 return OMX_ErrorNoMore; 251 } 252 253 if (formatParams->nPortIndex == kInputPortIndex) { 254 formatParams->eCompressionFormat = mCodingType; 255 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 256 formatParams->xFramerate = 0; 257 } else { 258 CHECK_EQ(formatParams->nPortIndex, 1u); 259 260 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 261 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; 262 formatParams->xFramerate = 0; 263 } 264 265 return OMX_ErrorNone; 266 } 267 268 case OMX_IndexParamVideoProfileLevelQuerySupported: 269 { 270 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel = 271 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params; 272 273 if (profileLevel->nPortIndex != kInputPortIndex) { 274 ALOGE("Invalid port index: %" PRIu32, profileLevel->nPortIndex); 275 return OMX_ErrorUnsupportedIndex; 276 } 277 278 if (profileLevel->nProfileIndex >= mNumProfileLevels) { 279 return OMX_ErrorNoMore; 280 } 281 282 profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile; 283 profileLevel->eLevel = mProfileLevels[profileLevel->nProfileIndex].mLevel; 284 return OMX_ErrorNone; 285 } 286 287 default: 288 return SimpleSoftOMXComponent::internalGetParameter(index, params); 289 } 290} 291 292OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalSetParameter( 293 OMX_INDEXTYPE index, const OMX_PTR params) { 294 // Include extension index OMX_INDEXEXTTYPE. 295 const int32_t indexFull = index; 296 297 switch (indexFull) { 298 case OMX_IndexParamStandardComponentRole: 299 { 300 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 301 (const OMX_PARAM_COMPONENTROLETYPE *)params; 302 303 if (strncmp((const char *)roleParams->cRole, 304 mComponentRole, 305 OMX_MAX_STRINGNAME_SIZE - 1)) { 306 return OMX_ErrorUndefined; 307 } 308 309 return OMX_ErrorNone; 310 } 311 312 case OMX_IndexParamVideoPortFormat: 313 { 314 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 315 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 316 317 if (formatParams->nPortIndex > kMaxPortIndex) { 318 return OMX_ErrorUndefined; 319 } 320 321 if (formatParams->nIndex != 0) { 322 return OMX_ErrorNoMore; 323 } 324 325 return OMX_ErrorNone; 326 } 327 328 case kPrepareForAdaptivePlaybackIndex: 329 { 330 const PrepareForAdaptivePlaybackParams* adaptivePlaybackParams = 331 (const PrepareForAdaptivePlaybackParams *)params; 332 mIsAdaptive = adaptivePlaybackParams->bEnable; 333 if (mIsAdaptive) { 334 mAdaptiveMaxWidth = adaptivePlaybackParams->nMaxFrameWidth; 335 mAdaptiveMaxHeight = adaptivePlaybackParams->nMaxFrameHeight; 336 mWidth = mAdaptiveMaxWidth; 337 mHeight = mAdaptiveMaxHeight; 338 } else { 339 mAdaptiveMaxWidth = 0; 340 mAdaptiveMaxHeight = 0; 341 } 342 updatePortDefinitions(); 343 return OMX_ErrorNone; 344 } 345 346 default: 347 return SimpleSoftOMXComponent::internalSetParameter(index, params); 348 } 349} 350 351OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getConfig( 352 OMX_INDEXTYPE index, OMX_PTR params) { 353 switch (index) { 354 case OMX_IndexConfigCommonOutputCrop: 355 { 356 OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params; 357 358 if (rectParams->nPortIndex != kOutputPortIndex) { 359 return OMX_ErrorUndefined; 360 } 361 362 rectParams->nLeft = mCropLeft; 363 rectParams->nTop = mCropTop; 364 rectParams->nWidth = mCropWidth; 365 rectParams->nHeight = mCropHeight; 366 367 return OMX_ErrorNone; 368 } 369 370 default: 371 return OMX_ErrorUnsupportedIndex; 372 } 373} 374 375OMX_ERRORTYPE SoftVideoDecoderOMXComponent::getExtensionIndex( 376 const char *name, OMX_INDEXTYPE *index) { 377 if (!strcmp(name, "OMX.google.android.index.prepareForAdaptivePlayback")) { 378 *(int32_t*)index = kPrepareForAdaptivePlaybackIndex; 379 return OMX_ErrorNone; 380 } 381 382 return SimpleSoftOMXComponent::getExtensionIndex(name, index); 383} 384 385void SoftVideoDecoderOMXComponent::onReset() { 386 mOutputPortSettingsChange = NONE; 387} 388 389void SoftVideoDecoderOMXComponent::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { 390 if (portIndex != kOutputPortIndex) { 391 return; 392 } 393 394 switch (mOutputPortSettingsChange) { 395 case NONE: 396 break; 397 398 case AWAITING_DISABLED: 399 { 400 CHECK(!enabled); 401 mOutputPortSettingsChange = AWAITING_ENABLED; 402 break; 403 } 404 405 default: 406 { 407 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); 408 CHECK(enabled); 409 mOutputPortSettingsChange = NONE; 410 break; 411 } 412 } 413} 414 415} // namespace android 416