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