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 #ifdef TARGET_VPP_USE_GEN 248 case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL: 249 case HAL_PIXEL_FORMAT_NV12_X_TILED_INTEL: 250 //it will be removed in future, it indicate the same format with HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL 251 case HAL_PIXEL_FORMAT_YUV420PackedSemiPlanar_Tiled_INTEL: 252 #else 253 case HAL_PIXEL_FORMAT_NV12_VED: 254 case HAL_PIXEL_FORMAT_NV12_VEDT: 255 #endif 256 vaExtBuf.pixel_format = VA_FOURCC_NV12; 257 vaExtBuf.num_planes = 2; 258 vaExtBuf.pitches[0] = stride; 259 vaExtBuf.pitches[1] = stride; 260 vaExtBuf.pitches[2] = 0; 261 vaExtBuf.pitches[3] = 0; 262 vaExtBuf.offsets[0] = 0; 263 vaExtBuf.offsets[1] = stride * *height; 264 vaExtBuf.offsets[2] = 0; 265 vaExtBuf.offsets[3] = 0; 266 break; 267 default: 268 ALOGE("%s: can't support this format 0x%08x", __func__, format); 269 return STATUS_ERROR; 270 } 271 vaExtBuf.width = *width; 272 vaExtBuf.height = *height; 273 vaExtBuf.data_size = stride * *height * 1.5; 274 vaExtBuf.num_buffers = 1; 275 #ifndef TARGET_VPP_USE_GEN 276 if (format == HAL_PIXEL_FORMAT_NV12_VEDT) { 277 ALOGV("set TILING flag"); 278 vaExtBuf.flags |= VA_SURFACE_EXTBUF_DESC_ENABLE_TILING; 279 } 280 #endif 281 vaExtBuf.flags |= VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC; 282 vaExtBuf.buffers = (long unsigned int*)&handle; 283 284 attribs[0].type = (VASurfaceAttribType)VASurfaceAttribMemoryType; 285 attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE; 286 attribs[0].value.type = VAGenericValueTypeInteger; 287 attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_ANDROID_GRALLOC; 288 289 attribs[1].type = (VASurfaceAttribType)VASurfaceAttribExternalBufferDescriptor; 290 attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE; 291 attribs[1].value.type = VAGenericValueTypePointer; 292 attribs[1].value.value.p = &vaExtBuf; 293 294 attribs[2].type = (VASurfaceAttribType)VASurfaceAttribUsageHint; 295 attribs[2].flags = VA_SURFACE_ATTRIB_SETTABLE; 296 attribs[2].value.type = VAGenericValueTypeInteger; 297 attribs[2].value.value.i = VA_SURFACE_ATTRIB_USAGE_HINT_VPP_READ; 298 299 ALOGV("%s: Ext buffer: width %d, height %d, data_size %d, pitch %d", __func__, 300 vaExtBuf.width, vaExtBuf.height, vaExtBuf.data_size, vaExtBuf.pitches[0]); 301 VAStatus vaStatus = vaCreateSurfaces(mVADisplay, VA_RT_FORMAT_YUV420, vaExtBuf.width, 302 vaExtBuf.height, (VASurfaceID*)surfaceId, 1, attribs, 3); 303 CHECK_VASTATUS("vaCreateSurfaces"); 304 305 return (vaStatus == VA_STATUS_SUCCESS) ? STATUS_OK : STATUS_ERROR; 306 } 307 308 status_t ISVWorker::freeSurface(int32_t* surfaceId) 309 { 310 VAStatus vaStatus = VA_STATUS_SUCCESS; 311 vaDestroySurfaces(mVADisplay, (VASurfaceID*)surfaceId, 1); 312 CHECK_VASTATUS("vaDestroySurfaces"); 313 314 return (vaStatus == VA_STATUS_SUCCESS) ? STATUS_OK : STATUS_ERROR; 315 } 316 317 status_t ISVWorker::configFilters(uint32_t filters, 318 const FilterParam* filterParam) 319 { 320 status_t ret = STATUS_OK; 321 322 if (!filterParam) { 323 ALOGE("%s: invalid filterParam", __func__); 324 return STATUS_ERROR; 325 } 326 327 if (filters != 0) { 328 mFilterParam.srcWidth = filterParam->srcWidth; 329 mFilterParam.srcHeight = filterParam->srcHeight; 330 mFilterParam.dstWidth = filterParam->dstWidth; 331 mFilterParam.dstHeight = filterParam->dstHeight; 332 mFilterParam.frameRate = filterParam->frameRate; 333 mFilterParam.frcRate = filterParam->frcRate; 334 } 335 336 if (mFilters != filters) { 337 mFilters = filters; 338 ALOGI("%s: mFilters 0x%x, fps %d, frc rate %d", __func__, mFilters, mFilterParam.frameRate, mFilterParam.frcRate); 339 ret = setupFilters(); 340 } 341 342 return ret; 343 } 344 345 bool ISVWorker::isFpsSupport(int32_t fps, int32_t *fpsSet, int32_t fpsSetCnt) { 346 bool ret = false; 347 for (int32_t i = 0; i < fpsSetCnt; i++) { 348 if (fps == fpsSet[i]) { 349 ret = true; 350 break; 351 } 352 } 353 354 return ret; 355 } 356 357 status_t ISVWorker::setupFilters() { 358 ALOGV("setupFilters"); 359 VAProcFilterParameterBuffer deblock, denoise, sharpen, stde; 360 VAProcFilterParameterBufferDeinterlacing deint; 361 VAProcFilterParameterBufferColorBalance color[COLOR_NUM]; 362 VAProcFilterParameterBufferFrameRateConversion frc; 363 VABufferID deblockId, denoiseId, deintId, sharpenId, colorId, frcId, stdeId; 364 uint32_t numCaps; 365 VAProcFilterCap deblockCaps, denoiseCaps, sharpenCaps, frcCaps, stdeCaps; 366 VAProcFilterCapDeinterlacing deinterlacingCaps[VAProcDeinterlacingCount]; 367 VAProcFilterCapColorBalance colorCaps[COLOR_NUM]; 368 VAStatus vaStatus; 369 uint32_t numSupportedFilters = VAProcFilterCount; 370 VAProcFilterType supportedFilters[VAProcFilterCount]; 371 372 if (mNumFilterBuffers != 0) { 373 for (uint32_t i = 0; i < mNumFilterBuffers; i++) { 374 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i])) 375 ALOGW("%s: failed to destroy va buffer %d", __func__, mFilterBuffers[i]); 376 //return STATUS_ERROR; 377 } 378 memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID)); 379 mFilterFrc = VA_INVALID_ID; 380 mNumFilterBuffers = 0; 381 } 382 383 // query supported filters 384 vaStatus = vaQueryVideoProcFilters(mVADisplay, mVAContext, supportedFilters, &numSupportedFilters); 385 CHECK_VASTATUS("vaQueryVideoProcFilters"); 386 387 // create filter buffer for each filter 388 for (uint32_t i = 0; i < numSupportedFilters; i++) { 389 switch (supportedFilters[i]) { 390 case VAProcFilterDeblocking: 391 if ((mFilters & FilterDeblocking) != 0) { 392 // check filter caps 393 numCaps = 1; 394 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 395 VAProcFilterDeblocking, 396 &deblockCaps, 397 &numCaps); 398 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for deblocking"); 399 // create parameter buffer 400 deblock.type = VAProcFilterDeblocking; 401 deblock.value = deblockCaps.range.min_value + DENOISE_DEBLOCK_STRENGTH * deblockCaps.range.step; 402 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 403 VAProcFilterParameterBufferType, sizeof(deblock), 1, 404 &deblock, &deblockId); 405 CHECK_VASTATUS("vaCreateBuffer for deblocking"); 406 mFilterBuffers[mNumFilterBuffers] = deblockId; 407 mNumFilterBuffers++; 408 } 409 break; 410 case VAProcFilterNoiseReduction: 411 if((mFilters & FilterNoiseReduction) != 0) { 412 // check filter caps 413 numCaps = 1; 414 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 415 VAProcFilterNoiseReduction, 416 &denoiseCaps, 417 &numCaps); 418 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for denoising"); 419 // create parameter buffer 420 denoise.type = VAProcFilterNoiseReduction; 421 #ifdef TARGET_VPP_USE_GEN 422 char propValueString[PROPERTY_VALUE_MAX]; 423 424 // placeholder for vpg driver: can't support denoise factor auto adjust, so leave config to user. 425 property_get("vpp.filter.denoise.factor", propValueString, "64.0"); 426 denoise.value = atof(propValueString); 427 denoise.value = (denoise.value < 0.0f) ? 0.0f : denoise.value; 428 denoise.value = (denoise.value > 64.0f) ? 64.0f : denoise.value; 429 #else 430 denoise.value = denoiseCaps.range.min_value + DENOISE_DEBLOCK_STRENGTH * denoiseCaps.range.step; 431 #endif 432 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 433 VAProcFilterParameterBufferType, sizeof(denoise), 1, 434 &denoise, &denoiseId); 435 CHECK_VASTATUS("vaCreateBuffer for denoising"); 436 mFilterBuffers[mNumFilterBuffers] = denoiseId; 437 mNumFilterBuffers++; 438 } 439 break; 440 case VAProcFilterDeinterlacing: 441 if ((mFilters & FilterDeinterlacing) != 0) { 442 numCaps = VAProcDeinterlacingCount; 443 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 444 VAProcFilterDeinterlacing, 445 &deinterlacingCaps[0], 446 &numCaps); 447 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for deinterlacing"); 448 for (uint32_t i = 0; i < numCaps; i++) 449 { 450 VAProcFilterCapDeinterlacing * const cap = &deinterlacingCaps[i]; 451 if (cap->type != VAProcDeinterlacingBob) // desired Deinterlacing Type 452 continue; 453 454 deint.type = VAProcFilterDeinterlacing; 455 deint.algorithm = VAProcDeinterlacingBob; 456 vaStatus = vaCreateBuffer(mVADisplay, 457 mVAContext, 458 VAProcFilterParameterBufferType, 459 sizeof(deint), 1, 460 &deint, &deintId); 461 CHECK_VASTATUS("vaCreateBuffer for deinterlacing"); 462 mFilterBuffers[mNumFilterBuffers] = deintId; 463 mNumFilterBuffers++; 464 } 465 } 466 break; 467 case VAProcFilterSharpening: 468 if((mFilters & FilterSharpening) != 0) { 469 // check filter caps 470 numCaps = 1; 471 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 472 VAProcFilterSharpening, 473 &sharpenCaps, 474 &numCaps); 475 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for sharpening"); 476 // create parameter buffer 477 sharpen.type = VAProcFilterSharpening; 478 #ifdef TARGET_VPP_USE_GEN 479 char propValueString[PROPERTY_VALUE_MAX]; 480 481 // placeholder for vpg driver: can't support sharpness factor auto adjust, so leave config to user. 482 property_get("vpp.filter.sharpen.factor", propValueString, "8.0"); 483 sharpen.value = atof(propValueString); 484 sharpen.value = (sharpen.value < 0.0f) ? 0.0f : sharpen.value; 485 sharpen.value = (sharpen.value > 64.0f) ? 64.0f : sharpen.value; 486 #else 487 sharpen.value = sharpenCaps.range.default_value; 488 #endif 489 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 490 VAProcFilterParameterBufferType, sizeof(sharpen), 1, 491 &sharpen, &sharpenId); 492 CHECK_VASTATUS("vaCreateBuffer for sharpening"); 493 mFilterBuffers[mNumFilterBuffers] = sharpenId; 494 mNumFilterBuffers++; 495 } 496 break; 497 case VAProcFilterColorBalance: 498 if((mFilters & FilterColorBalance) != 0) { 499 uint32_t featureCount = 0; 500 // check filter caps 501 // FIXME: it's not used at all! 502 numCaps = COLOR_NUM; 503 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 504 VAProcFilterColorBalance, 505 colorCaps, 506 &numCaps); 507 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for color balance"); 508 // create parameter buffer 509 for (uint32_t i = 0; i < numCaps; i++) { 510 if (colorCaps[i].type == VAProcColorBalanceAutoSaturation) { 511 color[i].type = VAProcFilterColorBalance; 512 color[i].attrib = VAProcColorBalanceAutoSaturation; 513 color[i].value = colorCaps[i].range.min_value + COLOR_STRENGTH * colorCaps[i].range.step; 514 featureCount++; 515 } 516 else if (colorCaps[i].type == VAProcColorBalanceAutoBrightness) { 517 color[i].type = VAProcFilterColorBalance; 518 color[i].attrib = VAProcColorBalanceAutoBrightness; 519 color[i].value = colorCaps[i].range.min_value + COLOR_STRENGTH * colorCaps[i].range.step; 520 featureCount++; 521 } 522 } 523 #ifdef TARGET_VPP_USE_GEN 524 //TODO: VPG need to support check input value by colorCaps. 525 enum {kHue = 0, kSaturation, kBrightness, kContrast}; 526 char propValueString[PROPERTY_VALUE_MAX]; 527 color[kHue].type = VAProcFilterColorBalance; 528 color[kHue].attrib = VAProcColorBalanceHue; 529 530 // placeholder for vpg driver: can't support auto color balance, so leave config to user. 531 property_get("vpp.filter.procamp.hue", propValueString, "179.0"); 532 color[kHue].value = atof(propValueString); 533 color[kHue].value = (color[kHue].value < -180.0f) ? -180.0f : color[kHue].value; 534 color[kHue].value = (color[kHue].value > 180.0f) ? 180.0f : color[kHue].value; 535 featureCount++; 536 537 color[kSaturation].type = VAProcFilterColorBalance; 538 color[kSaturation].attrib = VAProcColorBalanceSaturation; 539 property_get("vpp.filter.procamp.saturation", propValueString, "1.0"); 540 color[kSaturation].value = atof(propValueString); 541 color[kSaturation].value = (color[kSaturation].value < 0.0f) ? 0.0f : color[kSaturation].value; 542 color[kSaturation].value = (color[kSaturation].value > 10.0f) ? 10.0f : color[kSaturation].value; 543 featureCount++; 544 545 color[kBrightness].type = VAProcFilterColorBalance; 546 color[kBrightness].attrib = VAProcColorBalanceBrightness; 547 property_get("vpp.filter.procamp.brightness", propValueString, "0.0"); 548 color[kBrightness].value = atof(propValueString); 549 color[kBrightness].value = (color[kBrightness].value < -100.0f) ? -100.0f : color[kBrightness].value; 550 color[kBrightness].value = (color[kBrightness].value > 100.0f) ? 100.0f : color[kBrightness].value; 551 featureCount++; 552 553 color[kContrast].type = VAProcFilterColorBalance; 554 color[kContrast].attrib = VAProcColorBalanceContrast; 555 property_get("vpp.filter.procamp.contrast", propValueString, "1.0"); 556 color[kContrast].value = atof(propValueString); 557 color[kContrast].value = (color[kContrast].value < 0.0f) ? 0.0f : color[kContrast].value; 558 color[kContrast].value = (color[kContrast].value > 10.0f) ? 10.0f : color[kContrast].value; 559 featureCount++; 560 #endif 561 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 562 VAProcFilterParameterBufferType, sizeof(*color), featureCount, 563 color, &colorId); 564 CHECK_VASTATUS("vaCreateBuffer for color balance"); 565 mFilterBuffers[mNumFilterBuffers] = colorId; 566 mNumFilterBuffers++; 567 } 568 break; 569 case VAProcFilterFrameRateConversion: 570 if((mFilters & FilterFrameRateConversion) != 0) { 571 frc.type = VAProcFilterFrameRateConversion; 572 frc.input_fps = mFilterParam.frameRate; 573 switch (mFilterParam.frcRate){ 574 case FRC_RATE_1X: 575 frc.output_fps = frc.input_fps; 576 break; 577 case FRC_RATE_2X: 578 frc.output_fps = frc.input_fps * 2; 579 break; 580 case FRC_RATE_2_5X: 581 frc.output_fps = frc.input_fps * 5/2; 582 break; 583 case FRC_RATE_4X: 584 frc.output_fps = frc.input_fps * 4; 585 break; 586 } 587 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 588 VAProcFilterParameterBufferType, sizeof(frc), 1, 589 &frc, &frcId); 590 CHECK_VASTATUS("vaCreateBuffer for frc"); 591 mFilterBuffers[mNumFilterBuffers] = frcId; 592 mNumFilterBuffers++; 593 mFilterFrc = frcId; 594 } 595 break; 596 case VAProcFilterSkinToneEnhancement: 597 if((mFilters & FilterSkinToneEnhancement) != 0) { 598 // check filter caps 599 numCaps = 1; 600 vaStatus = vaQueryVideoProcFilterCaps(mVADisplay, mVAContext, 601 VAProcFilterSkinToneEnhancement, 602 &stdeCaps, 603 &numCaps); 604 CHECK_VASTATUS("vaQueryVideoProcFilterCaps for skintone"); 605 // create parameter buffer 606 stde.type = VAProcFilterSkinToneEnhancement; 607 #ifdef TARGET_VPP_USE_GEN 608 char propValueString[PROPERTY_VALUE_MAX]; 609 610 // placeholder for vpg driver: can't support skintone factor auto adjust, so leave config to user. 611 property_get("vpp.filter.skintone.factor", propValueString, "8.0"); 612 stde.value = atof(propValueString); 613 stde.value = (stde.value < 0.0f) ? 0.0f : stde.value; 614 stde.value = (stde.value > 8.0f) ? 8.0f : stde.value; 615 #else 616 stde.value = stdeCaps.range.default_value; 617 #endif 618 vaStatus = vaCreateBuffer(mVADisplay, mVAContext, 619 VAProcFilterParameterBufferType, sizeof(stde), 1, 620 &stde, &stdeId); 621 CHECK_VASTATUS("vaCreateBuffer for skintone"); 622 mFilterBuffers[mNumFilterBuffers] = stdeId; 623 mNumFilterBuffers++; 624 } 625 break; 626 default: 627 ALOGW("%s: Not supported filter 0x%08x", __func__, supportedFilters[i]); 628 break; 629 } 630 } 631 632 return setupPipelineCaps(); 633 } 634 635 status_t ISVWorker::setupPipelineCaps() { 636 ALOGV("setupPipelineCaps"); 637 //TODO color standards 638 VAProcPipelineCaps pipelineCaps; 639 VAStatus vaStatus; 640 pipelineCaps.input_color_standards = in_color_standards; 641 pipelineCaps.num_input_color_standards = VAProcColorStandardCount; 642 pipelineCaps.output_color_standards = out_color_standards; 643 pipelineCaps.num_output_color_standards = VAProcColorStandardCount; 644 645 vaStatus = vaQueryVideoProcPipelineCaps(mVADisplay, mVAContext, 646 mFilterBuffers, mNumFilterBuffers, 647 &pipelineCaps); 648 CHECK_VASTATUS("vaQueryVideoProcPipelineCaps"); 649 650 if (mForwardReferences != NULL) { 651 free(mForwardReferences); 652 mForwardReferences = NULL; 653 mNumForwardReferences = 0; 654 } 655 656 mNumForwardReferences = pipelineCaps.num_forward_references; 657 if (mNumForwardReferences > 0) { 658 mForwardReferences = (VASurfaceID*)malloc(mNumForwardReferences * sizeof(VASurfaceID)); 659 if (mForwardReferences == NULL) 660 return STATUS_ALLOCATION_ERROR; 661 memset(mForwardReferences, 0, mNumForwardReferences * sizeof(VASurfaceID)); 662 } 663 return STATUS_OK; 664 } 665 666 status_t ISVWorker::process(ISVBuffer* inputBuffer, Vector<ISVBuffer*> outputBuffer, 667 uint32_t outputCount, bool isEOS, uint32_t flags) { 668 ALOGV("process: outputCount=%d, mInputIndex=%d", outputCount, mInputIndex); 669 VASurfaceID input; 670 VASurfaceID output[MAX_FRC_OUTPUT]; 671 VABufferID pipelineId; 672 VAProcPipelineParameterBuffer *pipeline; 673 VAProcFilterParameterBufferFrameRateConversion *frc; 674 VAStatus vaStatus = STATUS_OK; 675 uint32_t i = 0; 676 677 if (isEOS) { 678 if (mInputIndex == 0) { 679 ALOGV("%s: don't need to flush VSP", __func__); 680 return STATUS_OK; 681 } 682 input = VA_INVALID_SURFACE; 683 outputCount = 1; 684 output[0] = mPrevOutput; 685 } else { 686 if (!inputBuffer || outputBuffer.size() != outputCount) { 687 ALOGE("%s: invalid input/output buffer", __func__); 688 return STATUS_ERROR; 689 } 690 691 if (outputCount < 1 || outputCount > 4) { 692 ALOGE("%s: invalid outputCount", __func__); 693 return STATUS_ERROR; 694 } 695 696 input = inputBuffer->getSurface(); 697 for (i = 0; i < outputCount; i++) { 698 output[i] = outputBuffer[i]->getSurface(); 699 if (output[i] == VA_INVALID_SURFACE) { 700 ALOGE("invalid output buffer"); 701 return STATUS_ERROR; 702 } 703 } 704 } 705 706 // reference frames setting 707 if (mNumForwardReferences > 0) { 708 /* add previous frame into reference array*/ 709 for (i = 1; i < mNumForwardReferences; i++) { 710 mForwardReferences[i - 1] = mForwardReferences[i]; 711 } 712 713 //make last reference to input 714 mForwardReferences[mNumForwardReferences - 1] = mPrevInput; 715 } 716 717 mPrevInput = input; 718 719 // create pipeline parameter buffer 720 vaStatus = vaCreateBuffer(mVADisplay, 721 mVAContext, 722 VAProcPipelineParameterBufferType, 723 sizeof(VAProcPipelineParameterBuffer), 724 1, 725 NULL, 726 &pipelineId); 727 CHECK_VASTATUS("vaCreateBuffer for VAProcPipelineParameterBufferType"); 728 729 ALOGV("before vaBeginPicture"); 730 vaStatus = vaBeginPicture(mVADisplay, mVAContext, output[0]); 731 CHECK_VASTATUS("vaBeginPicture"); 732 733 // map pipeline paramter buffer 734 vaStatus = vaMapBuffer(mVADisplay, pipelineId, (void**)&pipeline); 735 CHECK_VASTATUS("vaMapBuffer for pipeline parameter buffer"); 736 737 // frc pamameter setting 738 if ((mFilters & FilterFrameRateConversion) != 0) { 739 vaStatus = vaMapBuffer(mVADisplay, mFilterFrc, (void **)&frc); 740 CHECK_VASTATUS("vaMapBuffer for frc parameter buffer"); 741 if (isEOS) 742 frc->num_output_frames = 0; 743 else 744 frc->num_output_frames = outputCount - 1; 745 frc->output_frames = output + 1; 746 } 747 748 // pipeline parameter setting 749 VARectangle dst_region; 750 dst_region.x = 0; 751 dst_region.y = 0; 752 dst_region.width = mFilterParam.dstWidth; 753 dst_region.height = mFilterParam.dstHeight; 754 755 VARectangle src_region; 756 src_region.x = 0; 757 src_region.y = 0; 758 src_region.width = mFilterParam.srcWidth; 759 src_region.height = mFilterParam.srcHeight; 760 761 if (isEOS) { 762 pipeline->surface = 0; 763 pipeline->pipeline_flags = VA_PIPELINE_FLAG_END; 764 } 765 else { 766 pipeline->surface = input; 767 pipeline->pipeline_flags = 0; 768 } 769 #ifdef TARGET_VPP_USE_GEN 770 pipeline->surface_region = &src_region; 771 pipeline->output_region = &dst_region; 772 pipeline->surface_color_standard = VAProcColorStandardBT601; 773 pipeline->output_color_standard = VAProcColorStandardBT601; 774 #else 775 pipeline->surface_region = NULL; 776 pipeline->output_region = NULL;//&output_region; 777 pipeline->surface_color_standard = VAProcColorStandardNone; 778 pipeline->output_color_standard = VAProcColorStandardNone; 779 /* real rotate state will be decided in psb video */ 780 pipeline->rotation_state = 0; 781 #endif 782 /* FIXME: set more meaningful background color */ 783 pipeline->output_background_color = 0; 784 pipeline->filters = mFilterBuffers; 785 pipeline->num_filters = mNumFilterBuffers; 786 pipeline->forward_references = mForwardReferences; 787 pipeline->num_forward_references = mNumForwardReferences; 788 pipeline->backward_references = NULL; 789 pipeline->num_backward_references = 0; 790 791 //currently, we only transfer TOP field to frame, no frame rate change. 792 if (flags & (OMX_BUFFERFLAG_TFF | OMX_BUFFERFLAG_BFF)) { 793 pipeline->filter_flags = VA_TOP_FIELD; 794 } else { 795 pipeline->filter_flags = VA_FRAME_PICTURE; 796 } 797 798 if ((mFilters & FilterFrameRateConversion) != 0) { 799 vaStatus = vaUnmapBuffer(mVADisplay, mFilterFrc); 800 CHECK_VASTATUS("vaUnmapBuffer for frc parameter buffer"); 801 } 802 803 vaStatus = vaUnmapBuffer(mVADisplay, pipelineId); 804 CHECK_VASTATUS("vaUnmapBuffer for pipeline parameter buffer"); 805 806 ALOGV("before vaRenderPicture"); 807 // Send parameter to driver 808 vaStatus = vaRenderPicture(mVADisplay, mVAContext, &pipelineId, 1); 809 CHECK_VASTATUS("vaRenderPicture"); 810 811 ALOGV("before vaEndPicture"); 812 vaStatus = vaEndPicture(mVADisplay, mVAContext); 813 CHECK_VASTATUS("vaEndPicture"); 814 815 if (isEOS) { 816 vaStatus = vaSyncSurface(mVADisplay, mPrevOutput); 817 CHECK_VASTATUS("vaSyncSurface"); 818 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineId)) { 819 ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineId); 820 return STATUS_ERROR; 821 } 822 return STATUS_OK; 823 } 824 825 mPrevOutput = output[0]; 826 mInputIndex++; 827 828 Mutex::Autolock autoLock(mPipelineBufferLock); 829 mPipelineBuffers.push_back(pipelineId); 830 831 ALOGV("process, exit"); 832 return STATUS_OK; 833 } 834 835 status_t ISVWorker::fill(Vector<ISVBuffer*> outputBuffer, uint32_t outputCount) { 836 ALOGV("fill, outputCount=%d, mOutputIndex=%d",outputCount, mOutputIndex); 837 // get output surface 838 VASurfaceID output[MAX_FRC_OUTPUT]; 839 VAStatus vaStatus; 840 VASurfaceStatus surStatus; 841 842 if (outputCount < 1) 843 return STATUS_ERROR; 844 // map GraphicBuffer to VASurface 845 for (uint32_t i = 0; i < outputCount; i++) { 846 847 output[i] = outputBuffer[i]->getSurface(); 848 if (output[i] == VA_INVALID_SURFACE) { 849 ALOGE("invalid output buffer"); 850 return STATUS_ERROR; 851 } 852 //FIXME: only enable sync mode 853 #if 0 854 vaStatus = vaQuerySurfaceStatus(mVADisplay, output[i],&surStatus); 855 CHECK_VASTATUS("vaQuerySurfaceStatus"); 856 if (surStatus == VASurfaceRendering) { 857 ALOGV("Rendering %d", i); 858 /* The behavior of driver is: all output of one process task are return in one interruption. 859 The whole outputs of one FRC task are all ready or none of them is ready. 860 If the behavior changed, it hurts the performance. 861 */ 862 if (0 != i) { 863 ALOGW("*****Driver behavior changed. The performance is hurt."); 864 ALOGW("Please check driver behavior: all output of one task return in one interruption."); 865 } 866 vaStatus = STATUS_DATA_RENDERING; 867 break; 868 } 869 870 if ((surStatus != VASurfaceRendering) && (surStatus != VASurfaceReady)) { 871 ALOGE("surface statu Error %d", surStatus); 872 vaStatus = STATUS_ERROR; 873 } 874 #endif 875 vaStatus = vaSyncSurface(mVADisplay, output[i]); 876 CHECK_VASTATUS("vaSyncSurface"); 877 vaStatus = STATUS_OK; 878 mOutputCount++; 879 //dumpYUVFrameData(output[i]); 880 } 881 882 { 883 Mutex::Autolock autoLock(mPipelineBufferLock); 884 if (vaStatus == STATUS_OK) { 885 VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0); 886 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) { 887 ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineBuffer); 888 return STATUS_ERROR; 889 } 890 mPipelineBuffers.removeAt(0); 891 mOutputIndex++; 892 } 893 } 894 895 ALOGV("fill, exit"); 896 return vaStatus; 897 } 898 899 // Debug only 900 #define FRAME_OUTPUT_FILE_NV12 "/storage/sdcard0/vpp_output.nv12" 901 status_t ISVWorker::dumpYUVFrameData(VASurfaceID surfaceID) { 902 status_t ret; 903 if (surfaceID == VA_INVALID_SURFACE) 904 return STATUS_ERROR; 905 906 VAStatus vaStatus; 907 VAImage image; 908 unsigned char *data_ptr; 909 910 vaStatus = vaDeriveImage(mVADisplay, 911 surfaceID, 912 &image); 913 CHECK_VASTATUS("vaDeriveImage"); 914 915 vaStatus = vaMapBuffer(mVADisplay, image.buf, (void **)&data_ptr); 916 CHECK_VASTATUS("vaMapBuffer"); 917 918 ret = writeNV12(mFilterParam.srcWidth, mFilterParam.srcHeight, data_ptr, image.pitches[0], image.pitches[1]); 919 if (ret != STATUS_OK) { 920 ALOGV("writeNV12 error"); 921 return STATUS_ERROR; 922 } 923 924 vaStatus = vaUnmapBuffer(mVADisplay, image.buf); 925 CHECK_VASTATUS("vaUnMapBuffer"); 926 927 vaStatus = vaDestroyImage(mVADisplay,image.image_id); 928 CHECK_VASTATUS("vaDestroyImage"); 929 930 return STATUS_OK; 931 } 932 933 status_t ISVWorker::reset() { 934 status_t ret; 935 ALOGV("reset"); 936 if (mOutputCount > 0) { 937 ALOGI("======mVPPInputCount=%d, mVPPRenderCount=%d======", 938 mInputIndex, mOutputCount); 939 } 940 mInputIndex = 0; 941 mOutputIndex = 0; 942 mOutputCount = 0; 943 944 { 945 Mutex::Autolock autoLock(mPipelineBufferLock); 946 while (!mPipelineBuffers.isEmpty()) { 947 VABufferID pipelineBuffer = mPipelineBuffers.itemAt(0); 948 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, pipelineBuffer)) { 949 ALOGE("%s: failed to destroy va buffer %d", __func__, pipelineBuffer); 950 return STATUS_ERROR; 951 } 952 mPipelineBuffers.removeAt(0); 953 } 954 } 955 956 if (mNumFilterBuffers != 0) { 957 for (uint32_t i = 0; i < mNumFilterBuffers; i++) { 958 if (VA_STATUS_SUCCESS != vaDestroyBuffer(mVADisplay, mFilterBuffers[i])) 959 ALOGW("%s: failed to destroy va buffer %d", __func__, mFilterBuffers[i]); 960 //return STATUS_ERROR; 961 } 962 mNumFilterBuffers = 0; 963 memset(&mFilterBuffers, VA_INVALID_ID, VAProcFilterCount * sizeof(VABufferID)); 964 mFilterFrc = VA_INVALID_ID; 965 } 966 967 // we need to clear the cache for reference surfaces 968 if (mForwardReferences != NULL) { 969 free(mForwardReferences); 970 mForwardReferences = NULL; 971 mNumForwardReferences = 0; 972 } 973 974 if (mVAContext != VA_INVALID_ID) { 975 vaDestroyContext(mVADisplay, mVAContext); 976 mVAContext = VA_INVALID_ID; 977 } 978 VAStatus vaStatus = vaCreateContext(mVADisplay, mVAConfig, mWidth, mHeight, 0, NULL, 0, &mVAContext); 979 CHECK_VASTATUS("vaCreateContext"); 980 981 return setupFilters(); 982 } 983 984 uint32_t ISVWorker::getVppOutputFps() { 985 uint32_t outputFps; 986 //mFilterParam.frcRate is 1 if FRC is disabled or input FPS is not changed by VPP. 987 if (FRC_RATE_2_5X == mFilterParam.frcRate) { 988 outputFps = mFilterParam.frameRate * 5 / 2; 989 } else { 990 outputFps = mFilterParam.frameRate * mFilterParam.frcRate; 991 } 992 993 ALOGV("vpp is on in settings %d %d %d", outputFps, mFilterParam.frameRate, mFilterParam.frcRate); 994 return outputFps; 995 } 996 997 998 status_t ISVWorker::writeNV12(int width, int height, unsigned char *out_buf, int y_pitch, int uv_pitch) { 999 size_t result; 1000 int frame_size; 1001 unsigned char *y_start, *uv_start; 1002 int h; 1003 1004 FILE *ofile = fopen(FRAME_OUTPUT_FILE_NV12, "ab"); 1005 if(ofile == NULL) { 1006 ALOGE("Open %s failed!", FRAME_OUTPUT_FILE_NV12); 1007 return STATUS_ERROR; 1008 } 1009 1010 if (out_buf == NULL) 1011 { 1012 fclose(ofile); 1013 return STATUS_ERROR; 1014 } 1015 if ((width % 2) || (height % 2)) 1016 { 1017 fclose(ofile); 1018 return STATUS_ERROR; 1019 } 1020 // Set frame size 1021 frame_size = height * width * 3/2; 1022 1023 /* write y */ 1024 y_start = out_buf; 1025 for (h = 0; h < height; ++h) { 1026 result = fwrite(y_start, sizeof(unsigned char), width, ofile); 1027 y_start += y_pitch; 1028 } 1029 1030 /* write uv */ 1031 uv_start = out_buf + uv_pitch * height; 1032 for (h = 0; h < height / 2; ++h) { 1033 result = fwrite(uv_start, sizeof(unsigned char), width, ofile); 1034 uv_start += uv_pitch; 1035 } 1036 // Close file 1037 fclose(ofile); 1038 return STATUS_OK; 1039 } 1040 1041