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