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