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