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