1 /* 2 * Copyright 2014 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 "SoftVideoEncoderOMXComponent" 21 #include <utils/Log.h> 22 #include <utils/misc.h> 23 24 #include "include/SoftVideoEncoderOMXComponent.h" 25 26 #include <hardware/gralloc.h> 27 #include <media/hardware/HardwareAPI.h> 28 #include <media/stagefright/foundation/ADebug.h> 29 #include <media/stagefright/foundation/ALooper.h> 30 #include <media/stagefright/foundation/AMessage.h> 31 #include <media/stagefright/foundation/AUtils.h> 32 #include <media/stagefright/MediaDefs.h> 33 34 #include <ui/GraphicBuffer.h> 35 #include <ui/GraphicBufferMapper.h> 36 37 #include <OMX_IndexExt.h> 38 39 namespace android { 40 41 const static OMX_COLOR_FORMATTYPE kSupportedColorFormats[] = { 42 OMX_COLOR_FormatYUV420Planar, 43 OMX_COLOR_FormatYUV420SemiPlanar, 44 OMX_COLOR_FormatAndroidOpaque 45 }; 46 47 template<class T> 48 static void InitOMXParams(T *params) { 49 params->nSize = sizeof(T); 50 params->nVersion.s.nVersionMajor = 1; 51 params->nVersion.s.nVersionMinor = 0; 52 params->nVersion.s.nRevision = 0; 53 params->nVersion.s.nStep = 0; 54 } 55 56 SoftVideoEncoderOMXComponent::SoftVideoEncoderOMXComponent( 57 const char *name, 58 const char *componentRole, 59 OMX_VIDEO_CODINGTYPE codingType, 60 const CodecProfileLevel *profileLevels, 61 size_t numProfileLevels, 62 int32_t width, 63 int32_t height, 64 const OMX_CALLBACKTYPE *callbacks, 65 OMX_PTR appData, 66 OMX_COMPONENTTYPE **component) 67 : SimpleSoftOMXComponent(name, callbacks, appData, component), 68 mInputDataIsMeta(false), 69 mWidth(width), 70 mHeight(height), 71 mBitrate(192000), 72 mFramerate(30 << 16), // Q16 format 73 mColorFormat(OMX_COLOR_FormatYUV420Planar), 74 mGrallocModule(NULL), 75 mMinOutputBufferSize(384), // arbitrary, using one uncompressed macroblock 76 mMinCompressionRatio(1), // max output size is normally the input size 77 mComponentRole(componentRole), 78 mCodingType(codingType), 79 mProfileLevels(profileLevels), 80 mNumProfileLevels(numProfileLevels) { 81 } 82 83 void SoftVideoEncoderOMXComponent::initPorts( 84 OMX_U32 numInputBuffers, OMX_U32 numOutputBuffers, OMX_U32 outputBufferSize, 85 const char *mime, OMX_U32 minCompressionRatio) { 86 OMX_PARAM_PORTDEFINITIONTYPE def; 87 88 mMinOutputBufferSize = outputBufferSize; 89 mMinCompressionRatio = minCompressionRatio; 90 91 InitOMXParams(&def); 92 93 def.nPortIndex = kInputPortIndex; 94 def.eDir = OMX_DirInput; 95 def.nBufferCountMin = numInputBuffers; 96 def.nBufferCountActual = def.nBufferCountMin; 97 def.bEnabled = OMX_TRUE; 98 def.bPopulated = OMX_FALSE; 99 def.eDomain = OMX_PortDomainVideo; 100 def.bBuffersContiguous = OMX_FALSE; 101 def.format.video.pNativeRender = NULL; 102 def.format.video.nFrameWidth = mWidth; 103 def.format.video.nFrameHeight = mHeight; 104 def.format.video.nStride = def.format.video.nFrameWidth; 105 def.format.video.nSliceHeight = def.format.video.nFrameHeight; 106 def.format.video.nBitrate = 0; 107 // frameRate is in Q16 format. 108 def.format.video.xFramerate = mFramerate; 109 def.format.video.bFlagErrorConcealment = OMX_FALSE; 110 def.nBufferAlignment = kInputBufferAlignment; 111 def.format.video.cMIMEType = const_cast<char *>("video/raw"); 112 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 113 def.format.video.eColorFormat = mColorFormat; 114 def.format.video.pNativeWindow = NULL; 115 // buffersize set in updatePortParams 116 117 addPort(def); 118 119 InitOMXParams(&def); 120 121 def.nPortIndex = kOutputPortIndex; 122 def.eDir = OMX_DirOutput; 123 def.nBufferCountMin = numOutputBuffers; 124 def.nBufferCountActual = def.nBufferCountMin; 125 def.bEnabled = OMX_TRUE; 126 def.bPopulated = OMX_FALSE; 127 def.eDomain = OMX_PortDomainVideo; 128 def.bBuffersContiguous = OMX_FALSE; 129 def.format.video.pNativeRender = NULL; 130 def.format.video.nFrameWidth = mWidth; 131 def.format.video.nFrameHeight = mHeight; 132 def.format.video.nStride = 0; 133 def.format.video.nSliceHeight = 0; 134 def.format.video.nBitrate = mBitrate; 135 def.format.video.xFramerate = 0 << 16; 136 def.format.video.bFlagErrorConcealment = OMX_FALSE; 137 def.nBufferAlignment = kOutputBufferAlignment; 138 def.format.video.cMIMEType = const_cast<char *>(mime); 139 def.format.video.eCompressionFormat = mCodingType; 140 def.format.video.eColorFormat = OMX_COLOR_FormatUnused; 141 def.format.video.pNativeWindow = NULL; 142 // buffersize set in updatePortParams 143 144 addPort(def); 145 146 updatePortParams(); 147 } 148 149 void SoftVideoEncoderOMXComponent::updatePortParams() { 150 OMX_PARAM_PORTDEFINITIONTYPE *inDef = &editPortInfo(kInputPortIndex)->mDef; 151 inDef->format.video.nFrameWidth = mWidth; 152 inDef->format.video.nFrameHeight = mHeight; 153 inDef->format.video.nStride = inDef->format.video.nFrameWidth; 154 inDef->format.video.nSliceHeight = inDef->format.video.nFrameHeight; 155 inDef->format.video.xFramerate = mFramerate; 156 inDef->format.video.eColorFormat = mColorFormat; 157 uint32_t rawBufferSize = 158 inDef->format.video.nStride * inDef->format.video.nSliceHeight * 3 / 2; 159 if (inDef->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) { 160 inDef->nBufferSize = max(sizeof(VideoNativeMetadata), sizeof(VideoGrallocMetadata)); 161 } else { 162 inDef->nBufferSize = rawBufferSize; 163 } 164 165 OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef; 166 outDef->format.video.nFrameWidth = mWidth; 167 outDef->format.video.nFrameHeight = mHeight; 168 outDef->format.video.nBitrate = mBitrate; 169 170 outDef->nBufferSize = max(mMinOutputBufferSize, rawBufferSize / mMinCompressionRatio); 171 } 172 173 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalSetPortParams( 174 const OMX_PARAM_PORTDEFINITIONTYPE *port) { 175 if (port->nPortIndex == kInputPortIndex) { 176 mWidth = port->format.video.nFrameWidth; 177 mHeight = port->format.video.nFrameHeight; 178 179 // xFramerate comes in Q16 format, in frames per second unit 180 mFramerate = port->format.video.xFramerate; 181 182 if (port->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused 183 || (port->format.video.eColorFormat != OMX_COLOR_FormatYUV420Planar 184 && port->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar 185 && port->format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque)) { 186 return OMX_ErrorUnsupportedSetting; 187 } 188 189 mColorFormat = port->format.video.eColorFormat; 190 } else if (port->nPortIndex == kOutputPortIndex) { 191 if (port->format.video.eCompressionFormat != mCodingType 192 || port->format.video.eColorFormat != OMX_COLOR_FormatUnused) { 193 return OMX_ErrorUnsupportedSetting; 194 } 195 196 mBitrate = port->format.video.nBitrate; 197 } else { 198 return OMX_ErrorBadPortIndex; 199 } 200 201 updatePortParams(); 202 return OMX_ErrorNone; 203 } 204 205 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalSetParameter( 206 OMX_INDEXTYPE index, const OMX_PTR param) { 207 // can include extension index OMX_INDEXEXTTYPE 208 const int32_t indexFull = index; 209 210 switch (indexFull) { 211 case OMX_IndexParamVideoErrorCorrection: 212 { 213 return OMX_ErrorNotImplemented; 214 } 215 216 case OMX_IndexParamStandardComponentRole: 217 { 218 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 219 (const OMX_PARAM_COMPONENTROLETYPE *)param; 220 221 if (strncmp((const char *)roleParams->cRole, 222 mComponentRole, 223 OMX_MAX_STRINGNAME_SIZE - 1)) { 224 return OMX_ErrorUnsupportedSetting; 225 } 226 227 return OMX_ErrorNone; 228 } 229 230 case OMX_IndexParamPortDefinition: 231 { 232 OMX_ERRORTYPE err = internalSetPortParams((const OMX_PARAM_PORTDEFINITIONTYPE *)param); 233 234 if (err != OMX_ErrorNone) { 235 return err; 236 } 237 238 return SimpleSoftOMXComponent::internalSetParameter(index, param); 239 } 240 241 case OMX_IndexParamVideoPortFormat: 242 { 243 const OMX_VIDEO_PARAM_PORTFORMATTYPE* format = 244 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param; 245 246 if (format->nPortIndex == kInputPortIndex) { 247 if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar || 248 format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || 249 format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) { 250 mColorFormat = format->eColorFormat; 251 252 updatePortParams(); 253 return OMX_ErrorNone; 254 } else { 255 ALOGE("Unsupported color format %i", format->eColorFormat); 256 return OMX_ErrorUnsupportedSetting; 257 } 258 } else if (format->nPortIndex == kOutputPortIndex) { 259 if (format->eCompressionFormat == mCodingType) { 260 return OMX_ErrorNone; 261 } else { 262 return OMX_ErrorUnsupportedSetting; 263 } 264 } else { 265 return OMX_ErrorBadPortIndex; 266 } 267 } 268 269 case kStoreMetaDataExtensionIndex: 270 { 271 // storeMetaDataInBuffers 272 const StoreMetaDataInBuffersParams *storeParam = 273 (const StoreMetaDataInBuffersParams *)param; 274 275 if (storeParam->nPortIndex == kOutputPortIndex) { 276 return storeParam->bStoreMetaData ? OMX_ErrorUnsupportedSetting : OMX_ErrorNone; 277 } else if (storeParam->nPortIndex != kInputPortIndex) { 278 return OMX_ErrorBadPortIndex; 279 } 280 281 mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE); 282 if (mInputDataIsMeta) { 283 mColorFormat = OMX_COLOR_FormatAndroidOpaque; 284 } else if (mColorFormat == OMX_COLOR_FormatAndroidOpaque) { 285 mColorFormat = OMX_COLOR_FormatYUV420Planar; 286 } 287 updatePortParams(); 288 return OMX_ErrorNone; 289 } 290 291 default: 292 return SimpleSoftOMXComponent::internalSetParameter(index, param); 293 } 294 } 295 296 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalGetParameter( 297 OMX_INDEXTYPE index, OMX_PTR param) { 298 switch ((int)index) { 299 case OMX_IndexParamVideoErrorCorrection: 300 { 301 return OMX_ErrorNotImplemented; 302 } 303 304 case OMX_IndexParamVideoPortFormat: 305 { 306 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 307 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param; 308 309 if (formatParams->nPortIndex == kInputPortIndex) { 310 if (formatParams->nIndex >= NELEM(kSupportedColorFormats)) { 311 return OMX_ErrorNoMore; 312 } 313 314 // Color formats, in order of preference 315 formatParams->eColorFormat = kSupportedColorFormats[formatParams->nIndex]; 316 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 317 formatParams->xFramerate = mFramerate; 318 return OMX_ErrorNone; 319 } else if (formatParams->nPortIndex == kOutputPortIndex) { 320 formatParams->eCompressionFormat = mCodingType; 321 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 322 formatParams->xFramerate = 0; 323 return OMX_ErrorNone; 324 } else { 325 return OMX_ErrorBadPortIndex; 326 } 327 } 328 329 case OMX_IndexParamVideoProfileLevelQuerySupported: 330 { 331 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel = 332 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) param; 333 334 if (profileLevel->nPortIndex != kOutputPortIndex) { 335 ALOGE("Invalid port index: %u", profileLevel->nPortIndex); 336 return OMX_ErrorUnsupportedIndex; 337 } 338 339 if (profileLevel->nProfileIndex >= mNumProfileLevels) { 340 return OMX_ErrorNoMore; 341 } 342 343 profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile; 344 profileLevel->eLevel = mProfileLevels[profileLevel->nProfileIndex].mLevel; 345 return OMX_ErrorNone; 346 } 347 348 case OMX_IndexParamConsumerUsageBits: 349 { 350 OMX_U32 *usageBits = (OMX_U32 *)param; 351 *usageBits = GRALLOC_USAGE_SW_READ_OFTEN; 352 return OMX_ErrorNone; 353 } 354 355 default: 356 return SimpleSoftOMXComponent::internalGetParameter(index, param); 357 } 358 } 359 360 // static 361 void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar( 362 uint8_t *dst, size_t dstStride, size_t dstVStride, 363 struct android_ycbcr *ycbcr, int32_t width, int32_t height) { 364 const uint8_t *src = (const uint8_t *)ycbcr->y; 365 const uint8_t *srcU = (const uint8_t *)ycbcr->cb; 366 const uint8_t *srcV = (const uint8_t *)ycbcr->cr; 367 uint8_t *dstU = dst + dstVStride * dstStride; 368 uint8_t *dstV = dstU + (dstVStride >> 1) * (dstStride >> 1); 369 370 for (size_t y = height; y > 0; --y) { 371 memcpy(dst, src, width); 372 dst += dstStride; 373 src += ycbcr->ystride; 374 } 375 if (ycbcr->cstride == ycbcr->ystride >> 1 && ycbcr->chroma_step == 1) { 376 // planar 377 for (size_t y = height >> 1; y > 0; --y) { 378 memcpy(dstU, srcU, width >> 1); 379 dstU += dstStride >> 1; 380 srcU += ycbcr->cstride; 381 memcpy(dstV, srcV, width >> 1); 382 dstV += dstStride >> 1; 383 srcV += ycbcr->cstride; 384 } 385 } else { 386 // arbitrary 387 for (size_t y = height >> 1; y > 0; --y) { 388 for (size_t x = width >> 1; x > 0; --x) { 389 *dstU++ = *srcU; 390 *dstV++ = *srcV; 391 srcU += ycbcr->chroma_step; 392 srcV += ycbcr->chroma_step; 393 } 394 dstU += (dstStride >> 1) - (width >> 1); 395 dstV += (dstStride >> 1) - (width >> 1); 396 srcU += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step; 397 srcV += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step; 398 } 399 } 400 } 401 402 // static 403 void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar( 404 const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) { 405 // TODO: add support for stride 406 int32_t outYsize = width * height; 407 uint32_t *outY = (uint32_t *) outYUV; 408 uint16_t *outCb = (uint16_t *) (outYUV + outYsize); 409 uint16_t *outCr = (uint16_t *) (outYUV + outYsize + (outYsize >> 2)); 410 411 /* Y copying */ 412 memcpy(outY, inYVU, outYsize); 413 414 /* U & V copying */ 415 // FIXME this only works if width is multiple of 4 416 uint32_t *inYVU_4 = (uint32_t *) (inYVU + outYsize); 417 for (int32_t i = height >> 1; i > 0; --i) { 418 for (int32_t j = width >> 2; j > 0; --j) { 419 uint32_t temp = *inYVU_4++; 420 uint32_t tempU = temp & 0xFF; 421 tempU = tempU | ((temp >> 8) & 0xFF00); 422 423 uint32_t tempV = (temp >> 8) & 0xFF; 424 tempV = tempV | ((temp >> 16) & 0xFF00); 425 426 *outCb++ = tempU; 427 *outCr++ = tempV; 428 } 429 } 430 } 431 432 // static 433 void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar( 434 uint8_t *dstY, size_t dstStride, size_t dstVStride, 435 const uint8_t *src, size_t width, size_t height, size_t srcStride, 436 bool bgr) { 437 CHECK((width & 1) == 0); 438 CHECK((height & 1) == 0); 439 440 uint8_t *dstU = dstY + dstStride * dstVStride; 441 uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1); 442 443 #ifdef SURFACE_IS_BGR32 444 bgr = !bgr; 445 #endif 446 447 const size_t redOffset = bgr ? 2 : 0; 448 const size_t greenOffset = 1; 449 const size_t blueOffset = bgr ? 0 : 2; 450 451 for (size_t y = 0; y < height; ++y) { 452 for (size_t x = 0; x < width; ++x) { 453 unsigned red = src[redOffset]; 454 unsigned green = src[greenOffset]; 455 unsigned blue = src[blueOffset]; 456 457 // using ITU-R BT.601 conversion matrix 458 unsigned luma = 459 ((red * 66 + green * 129 + blue * 25) >> 8) + 16; 460 461 dstY[x] = luma; 462 463 if ((x & 1) == 0 && (y & 1) == 0) { 464 unsigned U = 465 ((-red * 38 - green * 74 + blue * 112) >> 8) + 128; 466 467 unsigned V = 468 ((red * 112 - green * 94 - blue * 18) >> 8) + 128; 469 470 dstU[x >> 1] = U; 471 dstV[x >> 1] = V; 472 } 473 src += 4; 474 } 475 476 if ((y & 1) == 0) { 477 dstU += dstStride >> 1; 478 dstV += dstStride >> 1; 479 } 480 481 src += srcStride - 4 * width; 482 dstY += dstStride; 483 } 484 } 485 486 const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer( 487 uint8_t *dst, size_t dstSize, 488 const uint8_t *src, size_t srcSize, 489 size_t width, size_t height) const { 490 size_t dstStride = width; 491 size_t dstVStride = height; 492 493 MetadataBufferType bufferType = *(MetadataBufferType *)src; 494 bool usingANWBuffer = bufferType == kMetadataBufferTypeANWBuffer; 495 if (!usingANWBuffer && bufferType != kMetadataBufferTypeGrallocSource) { 496 ALOGE("Unsupported metadata type (%d)", bufferType); 497 return NULL; 498 } 499 500 if (mGrallocModule == NULL) { 501 CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule)); 502 } 503 504 const gralloc_module_t *grmodule = 505 (const gralloc_module_t *)mGrallocModule; 506 507 buffer_handle_t handle; 508 int format; 509 size_t srcStride; 510 size_t srcVStride; 511 if (usingANWBuffer) { 512 if (srcSize < sizeof(VideoNativeMetadata)) { 513 ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoNativeMetadata)); 514 return NULL; 515 } 516 517 VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)src; 518 ANativeWindowBuffer *buffer = nativeMeta.pBuffer; 519 handle = buffer->handle; 520 format = buffer->format; 521 srcStride = buffer->stride; 522 srcVStride = buffer->height; 523 // convert stride from pixels to bytes 524 if (format != HAL_PIXEL_FORMAT_YV12 && 525 format != HAL_PIXEL_FORMAT_YCbCr_420_888) { 526 // TODO do we need to support other formats? 527 srcStride *= 4; 528 } 529 530 if (nativeMeta.nFenceFd >= 0) { 531 sp<Fence> fence = new Fence(nativeMeta.nFenceFd); 532 nativeMeta.nFenceFd = -1; 533 status_t err = fence->wait(IOMX::kFenceTimeoutMs); 534 if (err != OK) { 535 ALOGE("Timed out waiting on input fence"); 536 return NULL; 537 } 538 } 539 } else { 540 // TODO: remove this part. Check if anyone uses this. 541 542 if (srcSize < sizeof(VideoGrallocMetadata)) { 543 ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoGrallocMetadata)); 544 return NULL; 545 } 546 547 VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)(src); 548 handle = grallocMeta.pHandle; 549 // assume HAL_PIXEL_FORMAT_RGBA_8888 550 // there is no way to get the src stride without the graphic buffer 551 format = HAL_PIXEL_FORMAT_RGBA_8888; 552 srcStride = width * 4; 553 srcVStride = height; 554 } 555 556 size_t neededSize = 557 dstStride * dstVStride + (width >> 1) 558 + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1); 559 if (dstSize < neededSize) { 560 ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize); 561 return NULL; 562 } 563 564 void *bits = NULL; 565 struct android_ycbcr ycbcr; 566 status_t res; 567 if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { 568 res = grmodule->lock_ycbcr( 569 grmodule, handle, 570 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, 571 0, 0, width, height, &ycbcr); 572 } else { 573 res = grmodule->lock( 574 grmodule, handle, 575 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, 576 0, 0, width, height, &bits); 577 } 578 if (res != OK) { 579 ALOGE("Unable to lock image buffer %p for access", handle); 580 return NULL; 581 } 582 583 switch (format) { 584 case HAL_PIXEL_FORMAT_YV12: // YCrCb / YVU planar 585 // convert to flex YUV 586 ycbcr.y = bits; 587 ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride; 588 ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1); 589 ycbcr.chroma_step = 1; 590 ycbcr.cstride = srcVStride >> 1; 591 ycbcr.ystride = srcVStride; 592 ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); 593 break; 594 case HAL_PIXEL_FORMAT_YCrCb_420_SP: // YCrCb / YVU semiplanar, NV21 595 // convert to flex YUV 596 ycbcr.y = bits; 597 ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride; 598 ycbcr.cb = (uint8_t *)ycbcr.cr + 1; 599 ycbcr.chroma_step = 2; 600 ycbcr.cstride = srcVStride; 601 ycbcr.ystride = srcVStride; 602 ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); 603 break; 604 case HAL_PIXEL_FORMAT_YCbCr_420_888: 605 ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); 606 break; 607 case HAL_PIXEL_FORMAT_RGBA_8888: 608 case HAL_PIXEL_FORMAT_BGRA_8888: 609 ConvertRGB32ToPlanar( 610 dst, dstStride, dstVStride, 611 (const uint8_t *)bits, width, height, srcStride, 612 format == HAL_PIXEL_FORMAT_BGRA_8888); 613 break; 614 default: 615 ALOGE("Unsupported pixel format %#x", format); 616 dst = NULL; 617 break; 618 } 619 620 if (grmodule->unlock(grmodule, handle) != OK) { 621 ALOGE("Unable to unlock image buffer %p for access", handle); 622 } 623 624 return dst; 625 } 626 627 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex( 628 const char *name, OMX_INDEXTYPE *index) { 629 if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") || 630 !strcmp(name, "OMX.google.android.index.storeANWBufferInMetadata")) { 631 *(int32_t*)index = kStoreMetaDataExtensionIndex; 632 return OMX_ErrorNone; 633 } 634 return SimpleSoftOMXComponent::getExtensionIndex(name, index); 635 } 636 637 } // namespace android 638