1 /* 2 * Copyright (C) 2012 Intel Corporation. All rights reserved. 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 <cutils/properties.h> 18 #include <system/graphics.h> 19 #include "isv_worker.h" 20 #ifndef TARGET_VPP_USE_GEN 21 #include <hal_public.h> 22 #else 23 #include <ufo/graphics.h> 24 #endif 25 26 //#define LOG_NDEBUG 0 27 #undef LOG_TAG 28 #define LOG_TAG "isv-omxil" 29 30 #define CHECK_VASTATUS(str) \ 31 do { \ 32 if (vaStatus != VA_STATUS_SUCCESS) { \ 33 ALOGE("%s failed\n", str); \ 34 return STATUS_ERROR;} \ 35 }while(0); 36 37 enum STRENGTH { 38 STRENGTH_LOW = 0, 39 STRENGTH_MEDIUM, 40 STRENGTH_HIGH 41 }; 42 43 #define DENOISE_DEBLOCK_STRENGTH STRENGTH_MEDIUM 44 #define COLOR_STRENGTH STRENGTH_MEDIUM 45 #ifdef TARGET_VPP_USE_GEN 46 #define COLOR_NUM 4 47 #else 48 #define COLOR_NUM 2 49 #endif 50 51 #define MAX_FRC_OUTPUT 4 /*for frcx4*/ 52 53 using namespace android; 54 55 ISVWorker::ISVWorker() 56 :mNumForwardReferences(0), 57 mVAContext(VA_INVALID_ID), 58 mWidth(0), mHeight(0), 59 mDisplay(NULL), mVADisplay(NULL), 60 mVAConfig(VA_INVALID_ID), 61 mForwardReferences(NULL), 62 mPrevInput(0), mPrevOutput(0), 63 mNumFilterBuffers(0), 64 mFilterFrc(VA_INVALID_ID), mFilters(0), 65 mInputIndex(0), mOutputIndex(0), 66 mOutputCount(0) { 67 memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID)); 68 memset(&mFilterParam, 0, sizeof(mFilterParam)); 69 } 70 71 bool ISVWorker::isSupport() const { 72 bool support = false; 73 74 int num_entrypoints = vaMaxNumEntrypoints(mVADisplay); 75 VAEntrypoint * entrypoints = (VAEntrypoint *)malloc(num_entrypoints * sizeof(VAEntrypoint)); 76 if (entrypoints == NULL) { 77 ALOGE("failed to malloc entrypoints array\n"); 78 return false; 79 } 80 81 // check if it contains VPP entry point VAEntrypointVideoProc 82 VAStatus vaStatus = vaQueryConfigEntrypoints(mVADisplay, VAProfileNone, entrypoints, &num_entrypoints); 83 if (vaStatus != VA_STATUS_SUCCESS) { 84 ALOGE("vaQueryConfigEntrypoints failed"); 85 return false; 86 } 87 for (int i = 0; !support && i < num_entrypoints; i++) { 88 support = entrypoints[i] == VAEntrypointVideoProc; 89 } 90 free(entrypoints); 91 entrypoints = NULL; 92 93 return support; 94 } 95 96 uint32_t ISVWorker::getProcBufCount() { 97 return getOutputBufCount(mInputIndex); 98 } 99 100 uint32_t ISVWorker::getFillBufCount() { 101 return getOutputBufCount(mOutputIndex); 102 } 103 104 uint32_t ISVWorker::getOutputBufCount(uint32_t index) { 105 uint32_t bufCount = 1; 106 if (((mFilters & FilterFrameRateConversion) != 0) 107 && index > 0) 108 bufCount = mFilterParam.frcRate - (((mFilterParam.frcRate == FRC_RATE_2_5X) ? (index & 1): 0)); 109 return bufCount; 110 } 111 112 113 status_t ISVWorker::init(uint32_t width, uint32_t height) { 114 ALOGV("init"); 115 116 if (mDisplay != NULL) { 117 ALOGE("VA is particially started"); 118 return STATUS_ERROR; 119 } 120 mDisplay = new Display; 121 *mDisplay = ANDROID_DISPLAY_HANDLE; 122 123 mVADisplay = vaGetDisplay(mDisplay); 124 if (mVADisplay == NULL) { 125 ALOGE("vaGetDisplay failed"); 126 return STATUS_ERROR; 127 } 128 129 int majorVersion, minorVersion; 130 VAStatus vaStatus = vaInitialize(mVADisplay, &majorVersion, &minorVersion); 131 CHECK_VASTATUS("vaInitialize"); 132 133 // Check if VPP entry point is supported 134 if (!isSupport()) { 135 ALOGE("VPP is not supported on current platform"); 136 return STATUS_NOT_SUPPORT; 137 } 138 139 // Find out the format for the target 140 VAConfigAttrib attrib; 141 attrib.type = VAConfigAttribRTFormat; 142 vaStatus = vaGetConfigAttributes(mVADisplay, VAProfileNone, VAEntrypointVideoProc, &attrib, 1); 143 CHECK_VASTATUS("vaGetConfigAttributes"); 144 145 if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) { 146 ALOGE("attribute is %x vs wanted %x", attrib.value, VA_RT_FORMAT_YUV420); 147 return STATUS_NOT_SUPPORT; 148 } 149 150 ALOGV("ready to create config"); 151 // Create the configuration 152 vaStatus = vaCreateConfig(mVADisplay, VAProfileNone, VAEntrypointVideoProc, &attrib, 1, &mVAConfig); 153 CHECK_VASTATUS("vaCreateConfig"); 154 155 156 // Create Context 157 ALOGV("ready to create context"); 158 mWidth = width; 159 mHeight = height; 160 vaStatus = vaCreateContext(mVADisplay, mVAConfig, mWidth, mHeight, 0, NULL, 0, &mVAContext); 161 CHECK_VASTATUS("vaCreateContext"); 162 163 ALOGV("VA has been successfully started"); 164 return STATUS_OK; 165 } 166 167 status_t ISVWorker::deinit() { 168 { 169 Mutex::Autolock autoLock(mPipelineBufferLock); 170 while (!mPipelineBuffers.isEmpty()) { 171 VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0); 172 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) 173 ALOGW("%s: failed to destroy va buffer id %d", __func__, pipelineBuffer); 174 mPipelineBuffers.removeAt(0); 175 } 176 } 177 178 if (mNumFilterBuffers != 0) { 179 for (uint32_t i = 0; i < mNumFilterBuffers; i++) { 180 if(VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i])) 181 ALOGW("%s: failed to destroy va buffer id %d", __func__, mFilterBuffers[i]); 182 } 183 mNumFilterBuffers = 0; 184 memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID)); 185 mFilterFrc = VA_INVALID_ID; 186 } 187 188 if (mForwardReferences != NULL) { 189 free(mForwardReferences); 190 mForwardReferences = NULL; 191 mNumForwardReferences = 0; 192 } 193 194 if (mVAContext != VA_INVALID_ID) { 195 vaDestroyContext(mVADisplay, mVAContext); 196 mVAContext = VA_INVALID_ID; 197 } 198 199 if (mVAConfig != VA_INVALID_ID) { 200 vaDestroyConfig(mVADisplay, mVAConfig); 201 mVAConfig = VA_INVALID_ID; 202 } 203 204 if (mVADisplay) { 205 vaTerminate(mVADisplay); 206 mVADisplay = NULL; 207 } 208 209 if (mDisplay) { 210 delete mDisplay; 211 mDisplay = NULL; 212 } 213 214 return STATUS_OK; 215 } 216 217 status_t ISVWorker::allocSurface(uint32_t* width, uint32_t* height, 218 uint32_t stride, uint32_t format, unsigned long handle, int32_t* surfaceId) 219 { 220 if (mWidth == 0 || mHeight == 0) { 221 ALOGE("%s: isv worker has not been initialized.", __func__); 222 return STATUS_ERROR; 223 } 224 225 #ifndef TARGET_VPP_USE_GEN 226 *width = mWidth; 227 *height = mHeight; 228 #endif 229 // Create VASurfaces 230 VASurfaceAttrib attribs[3]; 231 VASurfaceAttribExternalBuffers vaExtBuf; 232 233 memset(&vaExtBuf, 0, sizeof(VASurfaceAttribExternalBuffers)); 234 switch(format) { 235 case HAL_PIXEL_FORMAT_YV12: 236 vaExtBuf.pixel_format = VA_FOURCC_YV12; 237 vaExtBuf.num_planes = 3; 238 vaExtBuf.pitches[0] = stride; 239 vaExtBuf.pitches[1] = stride / 2; 240 vaExtBuf.pitches[2] = stride / 2; 241 vaExtBuf.pitches[3] = 0; 242 vaExtBuf.offsets[0] = 0; 243 vaExtBuf.offsets[1] = stride * *height; 244 vaExtBuf.offsets[2] = vaExtBuf.offsets[1] + (stride / 2) * (*height / 2); 245 vaExtBuf.offsets[3] = 0; 246 break; 247 case HAL_PIXEL_FORMAT_INTEL_YV12: 248 vaExtBuf.pixel_format = VA_FOURCC_YV12; 249 vaExtBuf.num_planes = 3; 250 vaExtBuf.pitches[0] = stride; 251 vaExtBuf.pitches[1] = stride / 2; 252 vaExtBuf.pitches[2] = stride / 2; 253 vaExtBuf.pitches[3] = 0; 254 vaExtBuf.offsets[0] = 0; 255 // The height of HAL_PIXEL_FORMAT_INTEL_YV12 gralloc buffer has been aligned with 32 pixels. 256 vaExtBuf.offsets[1] = stride * ((*height + 31) & ~31); 257 vaExtBuf.offsets[2] = vaExtBuf.offsets[1] + (stride / 2) * (((*height + 31) & ~31) / 2); 258 vaExtBuf.offsets[3] = 0; 259 break; 260 #ifdef TARGET_VPP_USE_GEN 261 case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL: 262 case HAL_PIXEL_FORMAT_NV12_X_TILED_INTEL: 263 //it will be removed in future, it indicate the same format with HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL 264 case HAL_PIXEL_FORMAT_YUV420PackedSemiPlanar_Tiled_INTEL: 265 #else 266 case HAL_PIXEL_FORMAT_NV12_VED: 267 case HAL_PIXEL_FORMAT_NV12_VEDT: 268 #endif 269 vaExtBuf.pixel_format = VA_FOURCC_NV12; 270 vaExtBuf.num_planes = 2; 271 vaExtBuf.pitches[0] = stride; 272 vaExtBuf.pitches[1] = stride; 273 vaExtBuf.pitches[2] = 0; 274 vaExtBuf.pitches[3] = 0; 275 vaExtBuf.offsets[0] = 0; 276 vaExtBuf.offsets[1] = stride * *height; 277 vaExtBuf.offsets[2] = 0; 278 vaExtBuf.offsets[3] = 0; 279 break; 280 default: 281 ALOGE("%s: can't support this format 0x%08x", __func__, format); 282 return STATUS_ERROR; 283 } 284 vaExtBuf.width = *width; 285 vaExtBuf.height = *height; 286 vaExtBuf.data_size = stride * *height * 1.5; 287 vaExtBuf.num_buffers = 1; 288 #ifndef TARGET_VPP_USE_GEN 289 if (format == HAL_PIXEL_FORMAT_NV12_VEDT) { 290 ALOGV("set TILING flag"); 291 vaExtBuf.flags |= VA_SURFACE_EXTBUF_DESC_ENABLE_TILING; 292 } 293 #endif 294 vaExtBuf.flags |= VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC; 295 vaExtBuf.buffers = (long unsigned int*)&handle; 296 297 attribs[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType; 298 attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE; 299 attribs[0].value.type = VAGenericValueTypeInteger; 300 attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC; 301 302 attribs[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor; 303 attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE; 304 attribs[1].value.type = VAGenericValueTypePointer; 305 attribs[1].value.value.p = &vaExtBuf; 306 307 attribs[2].type = (VASurfaceAttribType)VASurfaceAttribUsageHint; 308 attribs[2].flags = VA_SURFACE_ATTRIB_SETTABLE; 309 attribs[2].value.type = VAGenericValueTypeInteger; 310 attribs[2].value.value.i = VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ; 311 312 ALOGV("%s: Ext buffer: width %d, height %d, data_size %d, pitch %d", __func__, 313 vaExtBuf.width, vaExtBuf.height, vaExtBuf.data_size, vaExtBuf.pitches[0]); 314 VAStatus vaStatus = vaCreateSurfaces(mVADisplay, VA_RT_FORMAT_YUV420, vaExtBuf.width, 315 vaExtBuf.height, (VASurfaceID*)surfaceId, 1, attribs, 3); 316 CHECK_VASTATUS("vaCreateSurfaces"); 317 318 return (vaStatus == VA_STATUS_SUCCESS) ? STATUS_OK : STATUS_ERROR; 319 } 320 321 status_t ISVWorker::freeSurface(int32_t* surfaceId) 322 { 323 VAStatus vaStatus = VA_STATUS_SUCCESS; 324 vaDestroySurfaces(mVADisplay, (VASurfaceID*)surfaceId, 1); 325 CHECK_VASTATUS("vaDestroySurfaces"); 326 327 return (vaStatus == VA_STATUS_SUCCESS) ? STATUS_OK : STATUS_ERROR; 328 } 329 330 status_t ISVWorker::configFilters(uint32_t filters, 331 const FilterParam* filterParam) 332 { 333 status_t ret = STATUS_OK; 334 335 if (!filterParam) { 336 ALOGE("%s: invalid filterParam", __func__); 337 return STATUS_ERROR; 338 } 339 340 if (filters != 0) { 341 mFilterParam.srcWidth = filterParam->srcWidth; 342 mFilterParam.srcHeight = filterParam->srcHeight; 343 mFilterParam.dstWidth = filterParam->dstWidth; 344 mFilterParam.dstHeight = filterParam->dstHeight; 345 mFilterParam.frameRate = filterParam->frameRate; 346 mFilterParam.frcRate = filterParam->frcRate; 347 } 348 349 if (mFilters != filters) { 350 mFilters = filters; 351 ALOGI("%s: mFilters 0x%x, fps %d, frc rate %d", __func__, mFilters, mFilterParam.frameRate, mFilterParam.frcRate); 352 ret = setupFilters(); 353 } 354 355 return ret; 356 } 357 358 bool ISVWorker::isFpsSupport(int32_t fps, int32_t *fpsSet, int32_t fpsSetCnt) { 359 bool ret = false; 360 for (int32_t i = 0; i < fpsSetCnt; i++) { 361 if (fps == fpsSet[i]) { 362 ret = true; 363 break; 364 } 365 } 366 367 return ret; 368 } 369 370 status_t ISVWorker::setupFilters() { 371 ALOGV("setupFilters"); 372 VAProcFilterParameterBuffer deblock, denoise, sharpen, stde; 373 VAProcFilterParameterBufferDeinterlacing deint; 374 VAProcFilterParameterBufferColorBalance color[COLOR_NUM]; 375 VAProcFilterParameterBufferFrameRateConversion frc; 376 VABufferID deblockId, denoiseId, deintId, sharpenId, colorId, frcId, stdeId; 377 uint32_t numCaps; 378 VAProcFilterCap deblockCaps, denoiseCaps, sharpenCaps, frcCaps, stdeCaps; 379 VAProcFilterCapDeinterlacing deinterlacingCaps[VAProcDeinterlacingCount]; 380 VAProcFilterCapColorBalance colorCaps[COLOR_NUM]; 381 VAStatus vaStatus; 382 uint32_t numSupportedFilters = VAProcFilterCount; 383 VAProcFilterType supportedFilters[VAProcFilterCount]; 384 385 if (mNumFilterBuffers != 0) { 386 for (uint32_t i = 0; i < mNumFilterBuffers; i++) { 387 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i])) 388 ALOGW("%s: failed to destroy va buffer %d", __func__, mFilterBuffers[i]); 389 //return STATUS_ERROR; 390 } 391 memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID)); 392 mFilterFrc = VA_INVALID_ID; 393 mNumFilterBuffers = 0; 394 } 395 396 // query supported filters 397 vaStatus = vaQueryVideoProcFilters(mVADisplay, mVAContext, supportedFilters, &numSupportedFilters); 398 CHECK_VASTATUS("vaQueryVideoProcFilters"); 399 400 // create filter buffer for each filter 401 for (uint32_t i = 0; i < numSupportedFilters; i++) { 402 switch (supportedFilters[i]) { 403 case VAProcFilterDeblocking: 404 if ((mFilters & FilterDeblocking) != 0) { 405 // check filter caps 406 numCaps = 1; 407 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 408 VAProcFilterDeblocking, 409 &deblockCaps, 410 &numCaps); 411 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for deblocking"); 412 // create parameter buffer 413 deblock.type = VAProcFilterDeblocking; 414 deblock.value = deblockCaps.range.min_value + DENOISE_DEBLOCK_STRENGTH * deblockCaps.range.step; 415 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 416 VAProcFilterParameterBufferType, sizeof(deblock), 1, 417 &deblock, &deblockId); 418 CHECK_VASTATUS("vaCreateBuffer for deblocking"); 419 mFilterBuffers[mNumFilterBuffers] = deblockId; 420 mNumFilterBuffers++; 421 } 422 break; 423 case VAProcFilterNoiseReduction: 424 if((mFilters & FilterNoiseReduction) != 0) { 425 // check filter caps 426 numCaps = 1; 427 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 428 VAProcFilterNoiseReduction, 429 &denoiseCaps, 430 &numCaps); 431 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for denoising"); 432 // create parameter buffer 433 denoise.type = VAProcFilterNoiseReduction; 434 #ifdef TARGET_VPP_USE_GEN 435 char propValueString[PROPERTY_VALUE_MAX]; 436 437 // placeholder for vpg driver: can't support denoise factor auto adjust, so leave config to user. 438 property_get("vpp.filter.denoise.factor", propValueString, "64.0"); 439 denoise.value = atof(propValueString); 440 denoise.value = (denoise.value < 0.0f) ? 0.0f : denoise.value; 441 denoise.value = (denoise.value > 64.0f) ? 64.0f : denoise.value; 442 #else 443 denoise.value = denoiseCaps.range.min_value + DENOISE_DEBLOCK_STRENGTH * denoiseCaps.range.step; 444 #endif 445 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 446 VAProcFilterParameterBufferType, sizeof(denoise), 1, 447 &denoise, &denoiseId); 448 CHECK_VASTATUS("vaCreateBuffer for denoising"); 449 mFilterBuffers[mNumFilterBuffers] = denoiseId; 450 mNumFilterBuffers++; 451 } 452 break; 453 case VAProcFilterDeinterlacing: 454 if ((mFilters & FilterDeinterlacing) != 0) { 455 numCaps = VAProcDeinterlacingCount; 456 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 457 VAProcFilterDeinterlacing, 458 &deinterlacingCaps[0], 459 &numCaps); 460 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for deinterlacing"); 461 for (uint32_t i = 0; i < numCaps; i++) 462 { 463 VAProcFilterCapDeinterlacing * const cap = &deinterlacingCaps[i]; 464 if (cap->type != VAProcDeinterlacingBob) // desired Deinterlacing Type 465 continue; 466 467 deint.type = VAProcFilterDeinterlacing; 468 deint.algorithm = VAProcDeinterlacingBob; 469 vaStatus = vaCreateBuffer(mVADisplay, 470 mVAContext, 471 VAProcFilterParameterBufferType, 472 sizeof(deint), 1, 473 &deint, &deintId); 474 CHECK_VASTATUS("vaCreateBuffer for deinterlacing"); 475 mFilterBuffers[mNumFilterBuffers] = deintId; 476 mNumFilterBuffers++; 477 } 478 } 479 break; 480 case VAProcFilterSharpening: 481 if((mFilters & FilterSharpening) != 0) { 482 // check filter caps 483 numCaps = 1; 484 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 485 VAProcFilterSharpening, 486 &sharpenCaps, 487 &numCaps); 488 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for sharpening"); 489 // create parameter buffer 490 sharpen.type = VAProcFilterSharpening; 491 #ifdef TARGET_VPP_USE_GEN 492 char propValueString[PROPERTY_VALUE_MAX]; 493 494 // placeholder for vpg driver: can't support sharpness factor auto adjust, so leave config to user. 495 property_get("vpp.filter.sharpen.factor", propValueString, "8.0"); 496 sharpen.value = atof(propValueString); 497 sharpen.value = (sharpen.value < 0.0f) ? 0.0f : sharpen.value; 498 sharpen.value = (sharpen.value > 64.0f) ? 64.0f : sharpen.value; 499 #else 500 sharpen.value = sharpenCaps.range.default_value; 501 #endif 502 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 503 VAProcFilterParameterBufferType, sizeof(sharpen), 1, 504 &sharpen, &sharpenId); 505 CHECK_VASTATUS("vaCreateBuffer for sharpening"); 506 mFilterBuffers[mNumFilterBuffers] = sharpenId; 507 mNumFilterBuffers++; 508 } 509 break; 510 case VAProcFilterColorBalance: 511 if((mFilters & FilterColorBalance) != 0) { 512 uint32_t featureCount = 0; 513 // check filter caps 514 // FIXME: it's not used at all! 515 numCaps = COLOR_NUM; 516 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 517 VAProcFilterColorBalance, 518 colorCaps, 519 &numCaps); 520 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for color balance"); 521 // create parameter buffer 522 for (uint32_t i = 0; i < numCaps; i++) { 523 if (colorCaps[i].type == VAProcColorBalanceAutoSaturation) { 524 color[i].type = VAProcFilterColorBalance; 525 color[i].attrib = VAProcColorBalanceAutoSaturation; 526 color[i].value = colorCaps[i].range.min_value + COLOR_STRENGTH * colorCaps[i].range.step; 527 featureCount++; 528 } 529 else if (colorCaps[i].type == VAProcColorBalanceAutoBrightness) { 530 color[i].type = VAProcFilterColorBalance; 531 color[i].attrib = VAProcColorBalanceAutoBrightness; 532 color[i].value = colorCaps[i].range.min_value + COLOR_STRENGTH * colorCaps[i].range.step; 533 featureCount++; 534 } 535 } 536 #ifdef TARGET_VPP_USE_GEN 537 //TODO: VPG need to support check input value by colorCaps. 538 enum {kHue = 0, kSaturation, kBrightness, kContrast}; 539 char propValueString[PROPERTY_VALUE_MAX]; 540 color[kHue].type = VAProcFilterColorBalance; 541 color[kHue].attrib = VAProcColorBalanceHue; 542 543 // placeholder for vpg driver: can't support auto color balance, so leave config to user. 544 property_get("vpp.filter.procamp.hue", propValueString, "179.0"); 545 color[kHue].value = atof(propValueString); 546 color[kHue].value = (color[kHue].value < -180.0f) ? -180.0f : color[kHue].value; 547 color[kHue].value = (color[kHue].value > 180.0f) ? 180.0f : color[kHue].value; 548 featureCount++; 549 550 color[kSaturation].type = VAProcFilterColorBalance; 551 color[kSaturation].attrib = VAProcColorBalanceSaturation; 552 property_get("vpp.filter.procamp.saturation", propValueString, "1.0"); 553 color[kSaturation].value = atof(propValueString); 554 color[kSaturation].value = (color[kSaturation].value < 0.0f) ? 0.0f : color[kSaturation].value; 555 color[kSaturation].value = (color[kSaturation].value > 10.0f) ? 10.0f : color[kSaturation].value; 556 featureCount++; 557 558 color[kBrightness].type = VAProcFilterColorBalance; 559 color[kBrightness].attrib = VAProcColorBalanceBrightness; 560 property_get("vpp.filter.procamp.brightness", propValueString, "0.0"); 561 color[kBrightness].value = atof(propValueString); 562 color[kBrightness].value = (color[kBrightness].value < -100.0f) ? -100.0f : color[kBrightness].value; 563 color[kBrightness].value = (color[kBrightness].value > 100.0f) ? 100.0f : color[kBrightness].value; 564 featureCount++; 565 566 color[kContrast].type = VAProcFilterColorBalance; 567 color[kContrast].attrib = VAProcColorBalanceContrast; 568 property_get("vpp.filter.procamp.contrast", propValueString, "1.0"); 569 color[kContrast].value = atof(propValueString); 570 color[kContrast].value = (color[kContrast].value < 0.0f) ? 0.0f : color[kContrast].value; 571 color[kContrast].value = (color[kContrast].value > 10.0f) ? 10.0f : color[kContrast].value; 572 featureCount++; 573 #endif 574 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 575 VAProcFilterParameterBufferType, sizeof(*color), featureCount, 576 color, &colorId); 577 CHECK_VASTATUS("vaCreateBuffer for color balance"); 578 mFilterBuffers[mNumFilterBuffers] = colorId; 579 mNumFilterBuffers++; 580 } 581 break; 582 case VAProcFilterFrameRateConversion: 583 if((mFilters & FilterFrameRateConversion) != 0) { 584 frc.type = VAProcFilterFrameRateConversion; 585 frc.input_fps = mFilterParam.frameRate; 586 switch (mFilterParam.frcRate){ 587 case FRC_RATE_1X: 588 frc.output_fps = frc.input_fps; 589 break; 590 case FRC_RATE_2X: 591 frc.output_fps = frc.input_fps * 2; 592 break; 593 case FRC_RATE_2_5X: 594 frc.output_fps = frc.input_fps * 5/2; 595 break; 596 case FRC_RATE_4X: 597 frc.output_fps = frc.input_fps * 4; 598 break; 599 } 600 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 601 VAProcFilterParameterBufferType, sizeof(frc), 1, 602 &frc, &frcId); 603 CHECK_VASTATUS("vaCreateBuffer for frc"); 604 mFilterBuffers[mNumFilterBuffers] = frcId; 605 mNumFilterBuffers++; 606 mFilterFrc = frcId; 607 } 608 break; 609 case VAProcFilterSkinToneEnhancement: 610 if((mFilters & FilterSkinToneEnhancement) != 0) { 611 // check filter caps 612 numCaps = 1; 613 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 614 VAProcFilterSkinToneEnhancement, 615 &stdeCaps, 616 &numCaps); 617 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for skintone"); 618 // create parameter buffer 619 stde.type = VAProcFilterSkinToneEnhancement; 620 #ifdef TARGET_VPP_USE_GEN 621 char propValueString[PROPERTY_VALUE_MAX]; 622 623 // placeholder for vpg driver: can't support skintone factor auto adjust, so leave config to user. 624 property_get("vpp.filter.skintone.factor", propValueString, "8.0"); 625 stde.value = atof(propValueString); 626 stde.value = (stde.value < 0.0f) ? 0.0f : stde.value; 627 stde.value = (stde.value > 8.0f) ? 8.0f : stde.value; 628 #else 629 stde.value = stdeCaps.range.default_value; 630 #endif 631 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 632 VAProcFilterParameterBufferType, sizeof(stde), 1, 633 &stde, &stdeId); 634 CHECK_VASTATUS("vaCreateBuffer for skintone"); 635 mFilterBuffers[mNumFilterBuffers] = stdeId; 636 mNumFilterBuffers++; 637 } 638 break; 639 default: 640 ALOGW("%s: Not supported filter 0x%08x", __func__, supportedFilters[i]); 641 break; 642 } 643 } 644 645 return setupPipelineCaps(); 646 } 647 648 status_t ISVWorker::setupPipelineCaps() { 649 ALOGV("setupPipelineCaps"); 650 //TODO color standards 651 VAProcPipelineCaps pipelineCaps; 652 VAStatus vaStatus; 653 pipelineCaps.input_color_standards = in_color_standards; 654 pipelineCaps.num_input_color_standards = VAProcColorStandardCount; 655 pipelineCaps.output_color_standards = out_color_standards; 656 pipelineCaps.num_output_color_standards = VAProcColorStandardCount; 657 658 vaStatus = vaQueryVideoProcPipelineCaps(mVADisplay, mVAContext, 659 mFilterBuffers, mNumFilterBuffers, 660 &pipelineCaps); 661 CHECK_VASTATUS("vaQueryVideoProcPipelineCaps"); 662 663 if (mForwardReferences != NULL) { 664 free(mForwardReferences); 665 mForwardReferences = NULL; 666 mNumForwardReferences = 0; 667 } 668 669 mNumForwardReferences = pipelineCaps.num_forward_references; 670 if (mNumForwardReferences > 0) { 671 mForwardReferences = (VASurfaceID*)malloc(mNumForwardReferences * sizeof(VASurfaceID)); 672 if (mForwardReferences == NULL) 673 return STATUS_ALLOCATION_ERROR; 674 memset(mForwardReferences, 0, mNumForwardReferences * sizeof(VASurfaceID)); 675 } 676 return STATUS_OK; 677 } 678 679 status_t ISVWorker::process(ISVBuffer* inputBuffer, Vector<ISVBuffer*> outputBuffer, 680 uint32_t outputCount, bool isEOS, uint32_t flags) { 681 ALOGV("process: outputCount=%d, mInputIndex=%d", outputCount, mInputIndex); 682 VASurfaceID input; 683 VASurfaceID output[MAX_FRC_OUTPUT]; 684 VABufferID pipelineId; 685 VAProcPipelineParameterBuffer *pipeline; 686 VAProcFilterParameterBufferFrameRateConversion *frc; 687 VAStatus vaStatus = STATUS_OK; 688 uint32_t i = 0; 689 690 if (isEOS) { 691 if (mInputIndex == 0) { 692 ALOGV("%s: don't need to flush VSP", __func__); 693 return STATUS_OK; 694 } 695 input = VA_INVALID_SURFACE; 696 outputCount = 1; 697 output[0] = mPrevOutput; 698 } else { 699 if (!inputBuffer || outputBuffer.size() != outputCount) { 700 ALOGE("%s: invalid input/output buffer", __func__); 701 return STATUS_ERROR; 702 } 703 704 if (outputCount < 1 || outputCount > 4) { 705 ALOGE("%s: invalid outputCount", __func__); 706 return STATUS_ERROR; 707 } 708 709 input = inputBuffer->getSurface(); 710 for (i = 0; i < outputCount; i++) { 711 output[i] = outputBuffer[i]->getSurface(); 712 if (output[i] == VA_INVALID_SURFACE) { 713 ALOGE("invalid output buffer"); 714 return STATUS_ERROR; 715 } 716 } 717 } 718 719 // reference frames setting 720 if (mNumForwardReferences > 0) { 721 /* add previous frame into reference array*/ 722 for (i = 1; i < mNumForwardReferences; i++) { 723 mForwardReferences[i - 1] = mForwardReferences[i]; 724 } 725 726 //make last reference to input 727 mForwardReferences[mNumForwardReferences - 1] = mPrevInput; 728 } 729 730 mPrevInput = input; 731 732 // create pipeline parameter buffer 733 vaStatus = vaCreateBuffer(mVADisplay, 734 mVAContext, 735 VAProcPipelineParameterBufferType, 736 sizeof(VAProcPipelineParameterBuffer), 737 1, 738 NULL, 739 &pipelineId); 740 CHECK_VASTATUS("vaCreateBuffer for VAProcPipelineParameterBufferType"); 741 742 ALOGV("before vaBeginPicture"); 743 vaStatus = vaBeginPicture(mVADisplay, mVAContext, output[0]); 744 CHECK_VASTATUS("vaBeginPicture"); 745 746 // map pipeline paramter buffer 747 vaStatus = vaMapBuffer(mVADisplay, pipelineId, (void**)&pipeline); 748 CHECK_VASTATUS("vaMapBuffer for pipeline parameter buffer"); 749 750 // frc pamameter setting 751 if ((mFilters & FilterFrameRateConversion) != 0) { 752 vaStatus = vaMapBuffer(mVADisplay, mFilterFrc, (void **)&frc); 753 CHECK_VASTATUS("vaMapBuffer for frc parameter buffer"); 754 if (isEOS) 755 frc->num_output_frames = 0; 756 else 757 frc->num_output_frames = outputCount - 1; 758 frc->output_frames = output + 1; 759 } 760 761 // pipeline parameter setting 762 VARectangle dst_region; 763 dst_region.x = 0; 764 dst_region.y = 0; 765 dst_region.width = mFilterParam.dstWidth; 766 dst_region.height = mFilterParam.dstHeight; 767 768 VARectangle src_region; 769 src_region.x = 0; 770 src_region.y = 0; 771 src_region.width = mFilterParam.srcWidth; 772 src_region.height = mFilterParam.srcHeight; 773 774 if (isEOS) { 775 pipeline->surface = 0; 776 pipeline->pipeline_flags = VA_PIPELINE_FLAG_END; 777 } 778 else { 779 pipeline->surface = input; 780 pipeline->pipeline_flags = 0; 781 } 782 #ifdef TARGET_VPP_USE_GEN 783 pipeline->surface_region = &src_region; 784 pipeline->output_region = &dst_region; 785 pipeline->surface_color_standard = VAProcColorStandardBT601; 786 pipeline->output_color_standard = VAProcColorStandardBT601; 787 #else 788 pipeline->surface_region = NULL; 789 pipeline->output_region = NULL;//&output_region; 790 pipeline->surface_color_standard = VAProcColorStandardNone; 791 pipeline->output_color_standard = VAProcColorStandardNone; 792 /* real rotate state will be decided in psb video */ 793 pipeline->rotation_state = 0; 794 #endif 795 /* FIXME: set more meaningful background color */ 796 pipeline->output_background_color = 0; 797 pipeline->filters = mFilterBuffers; 798 pipeline->num_filters = mNumFilterBuffers; 799 pipeline->forward_references = mForwardReferences; 800 pipeline->num_forward_references = mNumForwardReferences; 801 pipeline->backward_references = NULL; 802 pipeline->num_backward_references = 0; 803 804 //currently, we only transfer TOP field to frame, no frame rate change. 805 if (flags & (OMX_BUFFERFLAG_TFF | OMX_BUFFERFLAG_BFF)) { 806 pipeline->filter_flags = VA_TOP_FIELD; 807 } else { 808 pipeline->filter_flags = VA_FRAME_PICTURE; 809 } 810 811 if ((mFilters & FilterFrameRateConversion) != 0) { 812 vaStatus = vaUnmapBuffer(mVADisplay, mFilterFrc); 813 CHECK_VASTATUS("vaUnmapBuffer for frc parameter buffer"); 814 } 815 816 vaStatus = vaUnmapBuffer(mVADisplay, pipelineId); 817 CHECK_VASTATUS("vaUnmapBuffer for pipeline parameter buffer"); 818 819 ALOGV("before vaRenderPicture"); 820 // Send parameter to driver 821 vaStatus = vaRenderPicture(mVADisplay, mVAContext, &pipelineId, 1); 822 CHECK_VASTATUS("vaRenderPicture"); 823 824 ALOGV("before vaEndPicture"); 825 vaStatus = vaEndPicture(mVADisplay, mVAContext); 826 CHECK_VASTATUS("vaEndPicture"); 827 828 if (isEOS) { 829 vaStatus = vaSyncSurface(mVADisplay, mPrevOutput); 830 CHECK_VASTATUS("vaSyncSurface"); 831 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineId)) { 832 ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineId); 833 return STATUS_ERROR; 834 } 835 return STATUS_OK; 836 } 837 838 mPrevOutput = output[0]; 839 mInputIndex++; 840 841 Mutex::Autolock autoLock(mPipelineBufferLock); 842 mPipelineBuffers.push_back(pipelineId); 843 844 ALOGV("process, exit"); 845 return STATUS_OK; 846 } 847 848 status_t ISVWorker::fill(Vector<ISVBuffer*> outputBuffer, uint32_t outputCount) { 849 ALOGV("fill, outputCount=%d, mOutputIndex=%d",outputCount, mOutputIndex); 850 // get output surface 851 VASurfaceID output[MAX_FRC_OUTPUT]; 852 VAStatus vaStatus; 853 VASurfaceStatus surStatus; 854 855 if (outputCount < 1) 856 return STATUS_ERROR; 857 // map GraphicBuffer to VASurface 858 for (uint32_t i = 0; i < outputCount; i++) { 859 860 output[i] = outputBuffer[i]->getSurface(); 861 if (output[i] == VA_INVALID_SURFACE) { 862 ALOGE("invalid output buffer"); 863 return STATUS_ERROR; 864 } 865 //FIXME: only enable sync mode 866 #if 0 867 vaStatus = vaQuerySurfaceStatus(mVADisplay, output[i],&surStatus); 868 CHECK_VASTATUS("vaQuerySurfaceStatus"); 869 if (surStatus == VASurfaceRendering) { 870 ALOGV("Rendering %d", i); 871 /* The behavior of driver is: all output of one process task are return in one interruption. 872 The whole outputs of one FRC task are all ready or none of them is ready. 873 If the behavior changed, it hurts the performance. 874 */ 875 if (0 != i) { 876 ALOGW("*****Driver behavior changed. The performance is hurt."); 877 ALOGW("Please check driver behavior: all output of one task return in one interruption."); 878 } 879 vaStatus = STATUS_DATA_RENDERING; 880 break; 881 } 882 883 if ((surStatus != VASurfaceRendering) && (surStatus != VASurfaceReady)) { 884 ALOGE("surface statu Error %d", surStatus); 885 vaStatus = STATUS_ERROR; 886 } 887 #endif 888 vaStatus = vaSyncSurface(mVADisplay, output[i]); 889 CHECK_VASTATUS("vaSyncSurface"); 890 vaStatus = STATUS_OK; 891 mOutputCount++; 892 //dumpYUVFrameData(output[i]); 893 } 894 895 { 896 Mutex::Autolock autoLock(mPipelineBufferLock); 897 if (vaStatus == STATUS_OK) { 898 VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0); 899 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) { 900 ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineBuffer); 901 return STATUS_ERROR; 902 } 903 mPipelineBuffers.removeAt(0); 904 mOutputIndex++; 905 } 906 } 907 908 ALOGV("fill, exit"); 909 return vaStatus; 910 } 911 912 // Debug only 913 #define FRAME_OUTPUT_FILE_NV12 "/storage/sdcard0/vpp_output.nv12" 914 status_t ISVWorker::dumpYUVFrameData(VASurfaceID surfaceID) { 915 status_t ret; 916 if (surfaceID == VA_INVALID_SURFACE) 917 return STATUS_ERROR; 918 919 VAStatus vaStatus; 920 VAImage image; 921 unsigned char *data_ptr; 922 923 vaStatus = vaDeriveImage(mVADisplay, 924 surfaceID, 925 &image); 926 CHECK_VASTATUS("vaDeriveImage"); 927 928 vaStatus = vaMapBuffer(mVADisplay, image.buf, (void **)&data_ptr); 929 CHECK_VASTATUS("vaMapBuffer"); 930 931 ret = writeNV12(mFilterParam.srcWidth, mFilterParam.srcHeight, data_ptr, image.pitches[0], image.pitches[1]); 932 if (ret != STATUS_OK) { 933 ALOGV("writeNV12 error"); 934 return STATUS_ERROR; 935 } 936 937 vaStatus = vaUnmapBuffer(mVADisplay, image.buf); 938 CHECK_VASTATUS("vaUnMapBuffer"); 939 940 vaStatus = vaDestroyImage(mVADisplay,image.image_id); 941 CHECK_VASTATUS("vaDestroyImage"); 942 943 return STATUS_OK; 944 } 945 946 status_t ISVWorker::reset() { 947 status_t ret; 948 ALOGV("reset"); 949 if (mOutputCount > 0) { 950 ALOGI("======mVPPInputCount=%d, mVPPRenderCount=%d======", 951 mInputIndex, mOutputCount); 952 } 953 mInputIndex = 0; 954 mOutputIndex = 0; 955 mOutputCount = 0; 956 957 { 958 Mutex::Autolock autoLock(mPipelineBufferLock); 959 while (!mPipelineBuffers.isEmpty()) { 960 VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0); 961 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) { 962 ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineBuffer); 963 return STATUS_ERROR; 964 } 965 mPipelineBuffers.removeAt(0); 966 } 967 } 968 969 if (mNumFilterBuffers != 0) { 970 for (uint32_t i = 0; i < mNumFilterBuffers; i++) { 971 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i])) 972 ALOGW("%s: failed to destroy va buffer %d", __func__, mFilterBuffers[i]); 973 //return STATUS_ERROR; 974 } 975 mNumFilterBuffers = 0; 976 memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID)); 977 mFilterFrc = VA_INVALID_ID; 978 } 979 980 // we need to clear the cache for reference surfaces 981 if (mForwardReferences != NULL) { 982 free(mForwardReferences); 983 mForwardReferences = NULL; 984 mNumForwardReferences = 0; 985 } 986 987 if (mVAContext != VA_INVALID_ID) { 988 vaDestroyContext(mVADisplay, mVAContext); 989 mVAContext = VA_INVALID_ID; 990 } 991 VAStatus vaStatus = vaCreateContext(mVADisplay, mVAConfig, mWidth, mHeight, 0, NULL, 0, &mVAContext); 992 CHECK_VASTATUS("vaCreateContext"); 993 994 return setupFilters(); 995 } 996 997 uint32_t ISVWorker::getVppOutputFps() { 998 uint32_t outputFps; 999 //mFilterParam.frcRate is 1 if FRC is disabled or input FPS is not changed by VPP. 1000 if (FRC_RATE_2_5X == mFilterParam.frcRate) { 1001 outputFps = mFilterParam.frameRate * 5 / 2; 1002 } else { 1003 outputFps = mFilterParam.frameRate * mFilterParam.frcRate; 1004 } 1005 1006 ALOGV("vpp is on in settings %d %d %d", outputFps, mFilterParam.frameRate, mFilterParam.frcRate); 1007 return outputFps; 1008 } 1009 1010 1011 status_t ISVWorker::writeNV12(int width, int height, unsigned char *out_buf, int y_pitch, int uv_pitch) { 1012 size_t result; 1013 int frame_size; 1014 unsigned char *y_start, *uv_start; 1015 int h; 1016 1017 FILE *ofile = fopen(FRAME_OUTPUT_FILE_NV12, "ab"); 1018 if(ofile == NULL) { 1019 ALOGE("Open %s failed!", FRAME_OUTPUT_FILE_NV12); 1020 return STATUS_ERROR; 1021 } 1022 1023 if (out_buf == NULL) 1024 { 1025 fclose(ofile); 1026 return STATUS_ERROR; 1027 } 1028 if ((width % 2) || (height % 2)) 1029 { 1030 fclose(ofile); 1031 return STATUS_ERROR; 1032 } 1033 // Set frame size 1034 frame_size = height * width * 3/2; 1035 1036 /* write y */ 1037 y_start = out_buf; 1038 for (h = 0; h < height; ++h) { 1039 result = fwrite(y_start, sizeof(unsigned char), width, ofile); 1040 y_start += y_pitch; 1041 } 1042 1043 /* write uv */ 1044 uv_start = out_buf + uv_pitch * height; 1045 for (h = 0; h < height / 2; ++h) { 1046 result = fwrite(uv_start, sizeof(unsigned char), width, ofile); 1047 uv_start += uv_pitch; 1048 } 1049 // Close file 1050 fclose(ofile); 1051 return STATUS_OK; 1052 } 1053 1054