OMXFocus.cpp revision 00479a8f1d791824870513b8b0b9edd67d2560ff
1/* 2 * Copyright (C) Texas Instruments - http://www.ti.com/ 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 18/** 19* @file OMXFocus.cpp 20* 21* This file contains functionality for handling focus configurations. 22* 23*/ 24 25#undef LOG_TAG 26 27#define LOG_TAG "CameraHAL" 28 29#include "CameraHal.h" 30#include "OMXCameraAdapter.h" 31#include "ErrorUtils.h" 32 33#define TOUCH_FOCUS_RANGE 0xFF 34#define AF_CALLBACK_TIMEOUT 10000000 //10 seconds timeout 35 36namespace android { 37 38status_t OMXCameraAdapter::setParametersFocus(const CameraParameters ¶ms, 39 BaseCameraAdapter::AdapterState state) 40{ 41 status_t ret = NO_ERROR; 42 const char *str = NULL; 43 44 LOG_FUNCTION_NAME; 45 46 str = params.get(CameraParameters::KEY_FOCUS_AREAS); 47 mFocusAreas.clear(); 48 if ( NULL != str ) { 49 ret = CameraArea::parseFocusArea(str, strlen(str), mFocusAreas); 50 } 51 52 if ( NO_ERROR == ret ) { 53 if ( MAX_FOCUS_AREAS < mFocusAreas.size() ) { 54 CAMHAL_LOGEB("Focus areas supported %d, focus areas set %d", 55 MAX_FOCUS_AREAS, 56 mFocusAreas.size()); 57 ret = -EINVAL; 58 } 59 } 60 61 LOG_FUNCTION_NAME; 62 63 return ret; 64} 65 66status_t OMXCameraAdapter::doAutoFocus() 67{ 68 status_t ret = NO_ERROR; 69 OMX_ERRORTYPE eError = OMX_ErrorNone; 70 OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusControl; 71 size_t top, left, width, height, weight; 72 sp<CameraArea> focusArea = NULL; 73 74 LOG_FUNCTION_NAME; 75 76 if ( OMX_StateExecuting != mComponentState ) 77 { 78 CAMHAL_LOGEA("OMX component not in executing state"); 79 returnFocusStatus(false); 80 return NO_INIT; 81 } 82 83 if ( 0 != mDoAFSem.Count() ) 84 { 85 CAMHAL_LOGEB("Error mDoAFSem semaphore count %d", mDoAFSem.Count()); 86 return NO_INIT; 87 } 88 89 // If the app calls autoFocus, the camera will stop sending face callbacks. 90 pauseFaceDetection(true); 91 92 if ( NO_ERROR == ret ) 93 { 94 if ( !mFocusAreas.isEmpty() ) 95 { 96 focusArea = mFocusAreas.itemAt(0); 97 } 98 99 OMX_INIT_STRUCT_PTR (&focusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); 100 focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) mParameters3A.Focus; 101 102 //If touch AF is set, then necessary configuration first 103 if ( ( NULL != focusArea.get() ) && ( focusArea->isValid() ) ) 104 { 105 106 //Disable face priority first 107 setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, false); 108 109 //Enable region algorithm priority 110 setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, true); 111 112 //Set position 113 OMXCameraPortParameters * mPreviewData = NULL; 114 mPreviewData = &mCameraAdapterParameters.mCameraPortParams[mCameraAdapterParameters.mPrevPortIndex]; 115 focusArea->transfrom(mPreviewData->mWidth, 116 mPreviewData->mHeight, 117 top, 118 left, 119 width, 120 height); 121 setTouchFocus(left, 122 top, 123 width, 124 height, 125 mPreviewData->mWidth, 126 mPreviewData->mHeight); 127 128 //Do normal focus afterwards 129 focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) OMX_IMAGE_FocusControlExtended; 130 131 } 132 else if ( FOCUS_FACE_PRIORITY == focusControl.eFocusControl ) 133 { 134 //Disable region priority first 135 setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false); 136 137 //Enable face algorithm priority 138 setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, true); 139 140 //Do normal focus afterwards 141 focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) OMX_IMAGE_FocusControlExtended; 142 143 } 144 else 145 { 146 147 //Disable both region and face priority 148 setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, false); 149 150 setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO, false); 151 152 } 153 154 if ( ( mParameters3A.Focus != OMX_IMAGE_FocusControlAuto ) && 155 ( mParameters3A.Focus != OMX_IMAGE_FocusControlAutoInfinity ) ) 156 { 157 158 ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, 159 (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, 160 OMX_ALL, 161 OMX_IndexConfigCommonFocusStatus, 162 mDoAFSem); 163 164 if ( NO_ERROR == ret ) 165 { 166 ret = setFocusCallback(true); 167 } 168 } 169 170 eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, 171 OMX_IndexConfigFocusControl, 172 &focusControl); 173 174 if ( OMX_ErrorNone != eError ) 175 { 176 CAMHAL_LOGEB("Error while starting focus 0x%x", eError); 177 return INVALID_OPERATION; 178 } 179 else 180 { 181 CAMHAL_LOGDA("Autofocus started successfully"); 182 } 183 } 184 185 if ( ( mParameters3A.Focus != OMX_IMAGE_FocusControlAuto ) && 186 ( mParameters3A.Focus != OMX_IMAGE_FocusControlAutoInfinity ) ) 187 { 188 ret = mDoAFSem.WaitTimeout(AF_CALLBACK_TIMEOUT); 189 //Disable auto focus callback from Ducati 190 setFocusCallback(false); 191 //Signal a dummy AF event so that in case the callback from ducati 192 //does come then it doesnt crash after 193 //exiting this function since eventSem will go out of scope. 194 if(ret != NO_ERROR) 195 { 196 CAMHAL_LOGEA("Autofocus callback timeout expired"); 197 SignalEvent(mCameraAdapterParameters.mHandleComp, 198 (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, 199 OMX_ALL, 200 OMX_IndexConfigCommonFocusStatus, 201 NULL ); 202 returnFocusStatus(true); 203 } 204 else 205 { 206 CAMHAL_LOGDA("Autofocus callback received"); 207 ret = returnFocusStatus(false); 208 } 209 210 } 211 else 212 { 213 if ( NO_ERROR == ret ) 214 { 215 ret = returnFocusStatus(false); 216 } 217 } 218 219 LOG_FUNCTION_NAME_EXIT; 220 221 return ret; 222} 223 224status_t OMXCameraAdapter::stopAutoFocus() 225{ 226 status_t ret = NO_ERROR; 227 OMX_ERRORTYPE eError = OMX_ErrorNone; 228 OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusControl; 229 230 LOG_FUNCTION_NAME; 231 232 if ( OMX_StateExecuting != mComponentState ) 233 { 234 CAMHAL_LOGEA("OMX component not in executing state"); 235 return NO_INIT; 236 } 237 238 if ( mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity ) { 239 // No need to stop focus if we are in infinity mode. Nothing to stop. 240 return NO_ERROR; 241 } 242 243 if ( NO_ERROR == ret ) 244 { 245 //Disable the callback first 246 ret = setFocusCallback(false); 247 } 248 249 if ( NO_ERROR == ret ) 250 { 251 OMX_INIT_STRUCT_PTR (&focusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); 252 focusControl.eFocusControl = OMX_IMAGE_FocusControlOff; 253 254 eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, 255 OMX_IndexConfigFocusControl, 256 &focusControl); 257 if ( OMX_ErrorNone != eError ) 258 { 259 CAMHAL_LOGEB("Error while stopping focus 0x%x", eError); 260 return ErrorUtils::omxToAndroidError(eError); 261 } 262 } 263 264 //Query current focus distance after AF is complete 265 updateFocusDistances(mParameters); 266 267 LOG_FUNCTION_NAME_EXIT; 268 269 return ret; 270} 271 272status_t OMXCameraAdapter::cancelAutoFocus() 273{ 274 status_t ret = NO_ERROR; 275 OMX_ERRORTYPE eError = OMX_ErrorNone; 276 277 LOG_FUNCTION_NAME; 278 // Unlock 3A locks since they were locked by AF 279 if( set3ALock(OMX_FALSE) != NO_ERROR) { 280 CAMHAL_LOGEA("Error Unlocking 3A locks"); 281 } 282 else{ 283 CAMHAL_LOGDA("AE/AWB unlocked successfully"); 284 } 285 286 stopAutoFocus(); 287 //Signal a dummy AF event so that in case the callback from ducati 288 //does come then it doesnt crash after 289 //exiting this function since eventSem will go out of scope. 290 ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, 291 (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, 292 OMX_ALL, 293 OMX_IndexConfigCommonFocusStatus, 294 NULL ); 295 296 // If the apps call #cancelAutoFocus()}, the face callbacks will also resume. 297 pauseFaceDetection(false); 298 299 LOG_FUNCTION_NAME_EXIT; 300 301 return ret; 302 303} 304 305status_t OMXCameraAdapter::setFocusCallback(bool enabled) 306{ 307 status_t ret = NO_ERROR; 308 OMX_ERRORTYPE eError = OMX_ErrorNone; 309 OMX_CONFIG_CALLBACKREQUESTTYPE focusRequstCallback; 310 311 LOG_FUNCTION_NAME; 312 313 if ( OMX_StateExecuting != mComponentState ) 314 { 315 CAMHAL_LOGEA("OMX component not in executing state"); 316 ret = -1; 317 } 318 319 if ( NO_ERROR == ret ) 320 { 321 322 OMX_INIT_STRUCT_PTR (&focusRequstCallback, OMX_CONFIG_CALLBACKREQUESTTYPE); 323 focusRequstCallback.nPortIndex = OMX_ALL; 324 focusRequstCallback.nIndex = OMX_IndexConfigCommonFocusStatus; 325 326 if ( enabled ) 327 { 328 focusRequstCallback.bEnable = OMX_TRUE; 329 } 330 else 331 { 332 focusRequstCallback.bEnable = OMX_FALSE; 333 } 334 335 eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, 336 (OMX_INDEXTYPE) OMX_IndexConfigCallbackRequest, 337 &focusRequstCallback); 338 if ( OMX_ErrorNone != eError ) 339 { 340 CAMHAL_LOGEB("Error registering focus callback 0x%x", eError); 341 ret = -1; 342 } 343 else 344 { 345 CAMHAL_LOGDB("Autofocus callback for index 0x%x registered successfully", 346 OMX_IndexConfigCommonFocusStatus); 347 } 348 } 349 350 LOG_FUNCTION_NAME_EXIT; 351 352 return ret; 353} 354 355status_t OMXCameraAdapter::returnFocusStatus(bool timeoutReached) 356{ 357 status_t ret = NO_ERROR; 358 OMX_PARAM_FOCUSSTATUSTYPE eFocusStatus; 359 bool focusStatus = false; 360 BaseCameraAdapter::AdapterState state; 361 BaseCameraAdapter::getState(state); 362 363 LOG_FUNCTION_NAME; 364 365 OMX_INIT_STRUCT(eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); 366 367 if( ( AF_ACTIVE & state ) != AF_ACTIVE ) 368 { 369 /// We don't send focus callback if focus was not started 370 return NO_ERROR; 371 } 372 373 if ( NO_ERROR == ret ) 374 { 375 376 if ( !timeoutReached ) 377 { 378 ret = checkFocus(&eFocusStatus); 379 380 if ( NO_ERROR != ret ) 381 { 382 CAMHAL_LOGEA("Focus status check failed!"); 383 } 384 } 385 } 386 387 if ( NO_ERROR == ret ) 388 { 389 390 if ( timeoutReached ) 391 { 392 focusStatus = false; 393 } 394 ///FIXME: The ducati seems to return focus as false always if continuous focus is enabled 395 ///So, return focus as locked always until this is fixed. 396 else if(mParameters3A.Focus == OMX_IMAGE_FocusControlAuto ) 397 { 398 focusStatus = true; 399 } 400 else 401 { 402 switch (eFocusStatus.eFocusStatus) 403 { 404 case OMX_FocusStatusReached: 405 { 406 focusStatus = true; 407 //Lock the AE and AWB here sinc the focus is locked 408 // Apply 3A locks after AF 409 if( set3ALock(OMX_TRUE) != NO_ERROR) { 410 CAMHAL_LOGEA("Error Applying 3A locks"); 411 } 412 else 413 { 414 CAMHAL_LOGDA("Focus locked. Applied focus locks successfully"); 415 } 416 break; 417 } 418 case OMX_FocusStatusOff: 419 case OMX_FocusStatusUnableToReach: 420 case OMX_FocusStatusRequest: 421 default: 422 { 423 focusStatus = false; 424 break; 425 } 426 } 427 428 stopAutoFocus(); 429 } 430 } 431 432 if ( NO_ERROR == ret ) 433 { 434 435 ret = BaseCameraAdapter::setState(CAMERA_CANCEL_AUTOFOCUS); 436 437 if ( NO_ERROR == ret ) 438 { 439 ret = BaseCameraAdapter::commitState(); 440 } 441 else 442 { 443 ret |= BaseCameraAdapter::rollbackState(); 444 } 445 446 } 447 448 if ( NO_ERROR == ret ) 449 { 450 notifyFocusSubscribers(focusStatus); 451 } 452 453 // After focus, face detection will resume sending face callbacks 454 pauseFaceDetection(false); 455 456 LOG_FUNCTION_NAME_EXIT; 457 458 return ret; 459} 460 461status_t OMXCameraAdapter::checkFocus(OMX_PARAM_FOCUSSTATUSTYPE *eFocusStatus) 462{ 463 status_t ret = NO_ERROR; 464 OMX_ERRORTYPE eError = OMX_ErrorNone; 465 466 LOG_FUNCTION_NAME; 467 468 if ( NULL == eFocusStatus ) 469 { 470 CAMHAL_LOGEA("Invalid focus status"); 471 ret = -EINVAL; 472 } 473 474 if ( OMX_StateExecuting != mComponentState ) 475 { 476 CAMHAL_LOGEA("OMX component not in executing state"); 477 ret = -EINVAL; 478 } 479 480 if ( NO_ERROR == ret ) 481 { 482 OMX_INIT_STRUCT_PTR (eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); 483 484 eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, 485 OMX_IndexConfigCommonFocusStatus, 486 eFocusStatus); 487 if ( OMX_ErrorNone != eError ) 488 { 489 CAMHAL_LOGEB("Error while retrieving focus status: 0x%x", eError); 490 ret = -1; 491 } 492 } 493 494 if ( NO_ERROR == ret ) 495 { 496 CAMHAL_LOGDB("Focus Status: %d", eFocusStatus->eFocusStatus); 497 } 498 499 LOG_FUNCTION_NAME_EXIT; 500 501 return ret; 502} 503 504status_t OMXCameraAdapter::updateFocusDistances(CameraParameters ¶ms) 505{ 506 OMX_U32 focusNear, focusOptimal, focusFar; 507 status_t ret = NO_ERROR; 508 509 LOG_FUNCTION_NAME; 510 511 ret = getFocusDistances(focusNear, focusOptimal, focusFar); 512 if ( NO_ERROR == ret) 513 { 514 ret = addFocusDistances(focusNear, focusOptimal, focusFar, params); 515 if ( NO_ERROR != ret ) 516 { 517 CAMHAL_LOGEB("Error in call to addFocusDistances() 0x%x", ret); 518 } 519 } 520 else 521 { 522 CAMHAL_LOGEB("Error in call to getFocusDistances() 0x%x", ret); 523 } 524 525 LOG_FUNCTION_NAME_EXIT; 526 527 return ret; 528} 529 530status_t OMXCameraAdapter::getFocusDistances(OMX_U32 &near,OMX_U32 &optimal, OMX_U32 &far) 531{ 532 status_t ret = NO_ERROR; 533 OMX_ERRORTYPE eError; 534 535 OMX_TI_CONFIG_FOCUSDISTANCETYPE focusDist; 536 537 LOG_FUNCTION_NAME; 538 539 if ( OMX_StateInvalid == mComponentState ) 540 { 541 CAMHAL_LOGEA("OMX component is in invalid state"); 542 ret = UNKNOWN_ERROR; 543 } 544 545 if ( NO_ERROR == ret ) 546 { 547 OMX_INIT_STRUCT_PTR(&focusDist, OMX_TI_CONFIG_FOCUSDISTANCETYPE); 548 focusDist.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; 549 550 eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, 551 ( OMX_INDEXTYPE ) OMX_TI_IndexConfigFocusDistance, 552 &focusDist); 553 if ( OMX_ErrorNone != eError ) 554 { 555 CAMHAL_LOGEB("Error while querying focus distances 0x%x", eError); 556 ret = UNKNOWN_ERROR; 557 } 558 559 } 560 561 if ( NO_ERROR == ret ) 562 { 563 near = focusDist.nFocusDistanceNear; 564 optimal = focusDist.nFocusDistanceOptimal; 565 far = focusDist.nFocusDistanceFar; 566 } 567 568 LOG_FUNCTION_NAME_EXIT; 569 570 return ret; 571} 572 573status_t OMXCameraAdapter::encodeFocusDistance(OMX_U32 dist, char *buffer, size_t length) 574{ 575 status_t ret = NO_ERROR; 576 uint32_t focusScale = 1000; 577 float distFinal; 578 579 LOG_FUNCTION_NAME; 580 581 if(mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity) 582 { 583 dist=0; 584 } 585 586 if ( NO_ERROR == ret ) 587 { 588 if ( 0 == dist ) 589 { 590 strncpy(buffer, CameraParameters::FOCUS_DISTANCE_INFINITY, ( length - 1 )); 591 } 592 else 593 { 594 distFinal = dist; 595 distFinal /= focusScale; 596 snprintf(buffer, ( length - 1 ) , "%5.3f", distFinal); 597 } 598 } 599 600 LOG_FUNCTION_NAME_EXIT; 601 602 return ret; 603} 604 605status_t OMXCameraAdapter::addFocusDistances(OMX_U32 &near, 606 OMX_U32 &optimal, 607 OMX_U32 &far, 608 CameraParameters& params) 609{ 610 status_t ret = NO_ERROR; 611 612 LOG_FUNCTION_NAME; 613 614 if ( NO_ERROR == ret ) 615 { 616 ret = encodeFocusDistance(near, mFocusDistNear, FOCUS_DIST_SIZE); 617 if ( NO_ERROR != ret ) 618 { 619 CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); 620 } 621 } 622 623 if ( NO_ERROR == ret ) 624 { 625 ret = encodeFocusDistance(optimal, mFocusDistOptimal, FOCUS_DIST_SIZE); 626 if ( NO_ERROR != ret ) 627 { 628 CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); 629 } 630 } 631 632 if ( NO_ERROR == ret ) 633 { 634 ret = encodeFocusDistance(far, mFocusDistFar, FOCUS_DIST_SIZE); 635 if ( NO_ERROR != ret ) 636 { 637 CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); 638 } 639 } 640 641 if ( NO_ERROR == ret ) 642 { 643 snprintf(mFocusDistBuffer, ( FOCUS_DIST_BUFFER_SIZE - 1) ,"%s,%s,%s", mFocusDistNear, 644 mFocusDistOptimal, 645 mFocusDistFar); 646 647 params.set(CameraParameters::KEY_FOCUS_DISTANCES, mFocusDistBuffer); 648 } 649 650 LOG_FUNCTION_NAME_EXIT; 651 652 return ret; 653} 654 655status_t OMXCameraAdapter::setTouchFocus(size_t posX, 656 size_t posY, 657 size_t posWidth, 658 size_t posHeight, 659 size_t previewWidth, 660 size_t previewHeight) 661{ 662 status_t ret = NO_ERROR; 663 OMX_ERRORTYPE eError = OMX_ErrorNone; 664 OMX_CONFIG_EXTFOCUSREGIONTYPE touchControl; 665 666 LOG_FUNCTION_NAME; 667 668 if ( OMX_StateInvalid == mComponentState ) 669 { 670 CAMHAL_LOGEA("OMX component is in invalid state"); 671 ret = -1; 672 } 673 674 if ( NO_ERROR == ret ) 675 { 676 OMX_INIT_STRUCT_PTR (&touchControl, OMX_CONFIG_EXTFOCUSREGIONTYPE); 677 touchControl.nLeft = ( posX * TOUCH_FOCUS_RANGE ) / previewWidth; 678 touchControl.nTop = ( posY * TOUCH_FOCUS_RANGE ) / previewHeight; 679 touchControl.nWidth = ( posWidth * TOUCH_FOCUS_RANGE ) / previewWidth; 680 touchControl.nHeight = ( posHeight * TOUCH_FOCUS_RANGE ) / previewHeight; 681 682 eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, 683 ( OMX_INDEXTYPE ) OMX_IndexConfigExtFocusRegion, 684 &touchControl); 685 if ( OMX_ErrorNone != eError ) 686 { 687 CAMHAL_LOGEB("Error while configuring touch focus 0x%x", eError); 688 ret = -1; 689 } 690 else 691 { 692 CAMHAL_LOGDB("Touch focus %d,%d %d,%d configured successfuly", 693 ( int ) touchControl.nLeft, 694 ( int ) touchControl.nTop, 695 ( int ) touchControl.nWidth, 696 ( int ) touchControl.nHeight); 697 } 698 } 699 700 LOG_FUNCTION_NAME_EXIT; 701 702 return ret; 703} 704 705}; 706