OMXFocus.cpp revision c492aa718bc3f43eaf689b72595352f5348a0c39
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    // Unlock 3A locks since they were locked by AF
284    if( set3ALock(OMX_FALSE) != NO_ERROR) {
285      CAMHAL_LOGEA("Error Unlocking 3A locks");
286    }
287    else{
288      CAMHAL_LOGDA("AE/AWB unlocked successfully");
289    }
290
291    stopAutoFocus();
292    //Signal a dummy AF event so that in case the callback from ducati
293    //does come then it doesnt crash after
294    //exiting this function since eventSem will go out of scope.
295    ret |= SignalEvent(mCameraAdapterParameters.mHandleComp,
296                                (OMX_EVENTTYPE) OMX_EventIndexSettingChanged,
297                                OMX_ALL,
298                                OMX_IndexConfigCommonFocusStatus,
299                                NULL );
300
301    // If the apps call #cancelAutoFocus()}, the face callbacks will also resume.
302    pauseFaceDetection(false);
303
304    LOG_FUNCTION_NAME_EXIT;
305
306    return ret;
307
308}
309
310status_t OMXCameraAdapter::setFocusCallback(bool enabled)
311{
312    status_t ret = NO_ERROR;
313    OMX_ERRORTYPE eError = OMX_ErrorNone;
314    OMX_CONFIG_CALLBACKREQUESTTYPE focusRequstCallback;
315
316    LOG_FUNCTION_NAME;
317
318    if ( OMX_StateExecuting != mComponentState )
319        {
320        CAMHAL_LOGEA("OMX component not in executing state");
321        ret = -1;
322        }
323
324    if ( NO_ERROR == ret )
325        {
326
327        OMX_INIT_STRUCT_PTR (&focusRequstCallback, OMX_CONFIG_CALLBACKREQUESTTYPE);
328        focusRequstCallback.nPortIndex = OMX_ALL;
329        focusRequstCallback.nIndex = OMX_IndexConfigCommonFocusStatus;
330
331        if ( enabled )
332            {
333            focusRequstCallback.bEnable = OMX_TRUE;
334            }
335        else
336            {
337            focusRequstCallback.bEnable = OMX_FALSE;
338            }
339
340        eError =  OMX_SetConfig(mCameraAdapterParameters.mHandleComp,
341                                (OMX_INDEXTYPE) OMX_IndexConfigCallbackRequest,
342                                &focusRequstCallback);
343        if ( OMX_ErrorNone != eError )
344            {
345            CAMHAL_LOGEB("Error registering focus callback 0x%x", eError);
346            ret = -1;
347            }
348        else
349            {
350            CAMHAL_LOGDB("Autofocus callback for index 0x%x registered successfully",
351                         OMX_IndexConfigCommonFocusStatus);
352            }
353        }
354
355    LOG_FUNCTION_NAME_EXIT;
356
357    return ret;
358}
359
360status_t OMXCameraAdapter::returnFocusStatus(bool timeoutReached)
361{
362    status_t ret = NO_ERROR;
363    OMX_PARAM_FOCUSSTATUSTYPE eFocusStatus;
364    bool focusStatus = false;
365    BaseCameraAdapter::AdapterState state;
366    BaseCameraAdapter::getState(state);
367
368    LOG_FUNCTION_NAME;
369
370    OMX_INIT_STRUCT(eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE);
371
372    if( ( AF_ACTIVE & state ) != AF_ACTIVE )
373       {
374        /// We don't send focus callback if focus was not started
375       return NO_ERROR;
376       }
377
378    if ( NO_ERROR == ret )
379        {
380
381        if ( !timeoutReached )
382            {
383            ret = checkFocus(&eFocusStatus);
384
385            if ( NO_ERROR != ret )
386                {
387                CAMHAL_LOGEA("Focus status check failed!");
388                }
389            }
390        }
391
392    if ( NO_ERROR == ret )
393        {
394
395        if ( timeoutReached )
396            {
397            focusStatus = false;
398            }
399        ///FIXME: The ducati seems to return focus as false always if continuous focus is enabled
400        ///So, return focus as locked always until this is fixed.
401        else if(mParameters3A.Focus == OMX_IMAGE_FocusControlAuto )
402            {
403            focusStatus = true;
404            }
405        else
406            {
407            switch (eFocusStatus.eFocusStatus)
408                {
409                    case OMX_FocusStatusReached:
410                        {
411                        focusStatus = true;
412                        //Lock the AE and AWB here sinc the focus is locked
413                        // Apply 3A locks after AF
414                        if( set3ALock(OMX_TRUE) != NO_ERROR) {
415                            CAMHAL_LOGEA("Error Applying 3A locks");
416                        }
417                        else
418                            {
419                            CAMHAL_LOGDA("Focus locked. Applied focus locks successfully");
420                            }
421                        break;
422                        }
423                    case OMX_FocusStatusOff:
424                    case OMX_FocusStatusUnableToReach:
425                    case OMX_FocusStatusRequest:
426                    default:
427                        {
428                        focusStatus = false;
429                        break;
430                        }
431                }
432
433            stopAutoFocus();
434            }
435        }
436
437    if ( NO_ERROR == ret )
438        {
439
440        ret =  BaseCameraAdapter::setState(CAMERA_CANCEL_AUTOFOCUS);
441
442        if ( NO_ERROR == ret )
443            {
444            ret = BaseCameraAdapter::commitState();
445            }
446        else
447            {
448            ret |= BaseCameraAdapter::rollbackState();
449            }
450
451        }
452
453    if ( NO_ERROR == ret )
454        {
455        notifyFocusSubscribers(focusStatus);
456        }
457
458    // After focus, face detection will resume sending face callbacks
459    pauseFaceDetection(false);
460
461    LOG_FUNCTION_NAME_EXIT;
462
463    return ret;
464}
465
466status_t OMXCameraAdapter::checkFocus(OMX_PARAM_FOCUSSTATUSTYPE *eFocusStatus)
467{
468    status_t ret = NO_ERROR;
469    OMX_ERRORTYPE eError = OMX_ErrorNone;
470
471    LOG_FUNCTION_NAME;
472
473    if ( NULL == eFocusStatus )
474        {
475        CAMHAL_LOGEA("Invalid focus status");
476        ret = -EINVAL;
477        }
478
479    if ( OMX_StateExecuting != mComponentState )
480        {
481        CAMHAL_LOGEA("OMX component not in executing state");
482        ret = -EINVAL;
483        }
484
485    if ( NO_ERROR == ret )
486        {
487        OMX_INIT_STRUCT_PTR (eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE);
488
489        eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp,
490                               OMX_IndexConfigCommonFocusStatus,
491                               eFocusStatus);
492        if ( OMX_ErrorNone != eError )
493            {
494            CAMHAL_LOGEB("Error while retrieving focus status: 0x%x", eError);
495            ret = -1;
496            }
497        }
498
499    if ( NO_ERROR == ret )
500        {
501        CAMHAL_LOGDB("Focus Status: %d", eFocusStatus->eFocusStatus);
502        }
503
504    LOG_FUNCTION_NAME_EXIT;
505
506    return ret;
507}
508
509status_t OMXCameraAdapter::updateFocusDistances(CameraParameters &params)
510{
511    OMX_U32 focusNear, focusOptimal, focusFar;
512    status_t ret = NO_ERROR;
513
514    LOG_FUNCTION_NAME;
515
516    ret = getFocusDistances(focusNear, focusOptimal, focusFar);
517    if ( NO_ERROR == ret)
518        {
519        ret = addFocusDistances(focusNear, focusOptimal, focusFar, params);
520            if ( NO_ERROR != ret )
521                {
522                CAMHAL_LOGEB("Error in call to addFocusDistances() 0x%x", ret);
523                }
524        }
525    else
526        {
527        CAMHAL_LOGEB("Error in call to getFocusDistances() 0x%x", ret);
528        }
529
530    LOG_FUNCTION_NAME_EXIT;
531
532    return ret;
533}
534
535status_t OMXCameraAdapter::getFocusDistances(OMX_U32 &near,OMX_U32 &optimal, OMX_U32 &far)
536{
537    status_t ret = NO_ERROR;
538    OMX_ERRORTYPE eError;
539
540    OMX_TI_CONFIG_FOCUSDISTANCETYPE focusDist;
541
542    LOG_FUNCTION_NAME;
543
544    if ( OMX_StateInvalid == mComponentState )
545        {
546        CAMHAL_LOGEA("OMX component is in invalid state");
547        ret = UNKNOWN_ERROR;
548        }
549
550    if ( NO_ERROR == ret )
551        {
552        OMX_INIT_STRUCT_PTR(&focusDist, OMX_TI_CONFIG_FOCUSDISTANCETYPE);
553        focusDist.nPortIndex = mCameraAdapterParameters.mPrevPortIndex;
554
555        eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp,
556                               ( OMX_INDEXTYPE ) OMX_TI_IndexConfigFocusDistance,
557                               &focusDist);
558        if ( OMX_ErrorNone != eError )
559            {
560            CAMHAL_LOGEB("Error while querying focus distances 0x%x", eError);
561            ret = UNKNOWN_ERROR;
562            }
563
564        }
565
566    if ( NO_ERROR == ret )
567        {
568        near = focusDist.nFocusDistanceNear;
569        optimal = focusDist.nFocusDistanceOptimal;
570        far = focusDist.nFocusDistanceFar;
571        }
572
573    LOG_FUNCTION_NAME_EXIT;
574
575    return ret;
576}
577
578status_t OMXCameraAdapter::encodeFocusDistance(OMX_U32 dist, char *buffer, size_t length)
579{
580    status_t ret = NO_ERROR;
581    uint32_t focusScale = 1000;
582    float distFinal;
583
584    LOG_FUNCTION_NAME;
585
586    if(mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity)
587        {
588        dist=0;
589        }
590
591    if ( NO_ERROR == ret )
592        {
593        if ( 0 == dist )
594            {
595            strncpy(buffer, CameraParameters::FOCUS_DISTANCE_INFINITY, ( length - 1 ));
596            }
597        else
598            {
599            distFinal = dist;
600            distFinal /= focusScale;
601            snprintf(buffer, ( length - 1 ) , "%5.3f", distFinal);
602            }
603        }
604
605    LOG_FUNCTION_NAME_EXIT;
606
607    return ret;
608}
609
610status_t OMXCameraAdapter::addFocusDistances(OMX_U32 &near,
611                                             OMX_U32 &optimal,
612                                             OMX_U32 &far,
613                                             CameraParameters& params)
614{
615    status_t ret = NO_ERROR;
616
617    LOG_FUNCTION_NAME;
618
619    if ( NO_ERROR == ret )
620        {
621        ret = encodeFocusDistance(near, mFocusDistNear, FOCUS_DIST_SIZE);
622        if ( NO_ERROR != ret )
623            {
624            CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret);
625            }
626        }
627
628    if ( NO_ERROR == ret )
629        {
630        ret = encodeFocusDistance(optimal, mFocusDistOptimal, FOCUS_DIST_SIZE);
631        if ( NO_ERROR != ret )
632            {
633            CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret);
634            }
635        }
636
637    if ( NO_ERROR == ret )
638        {
639        ret = encodeFocusDistance(far, mFocusDistFar, FOCUS_DIST_SIZE);
640        if ( NO_ERROR != ret )
641            {
642            CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret);
643            }
644        }
645
646    if ( NO_ERROR == ret )
647        {
648        snprintf(mFocusDistBuffer, ( FOCUS_DIST_BUFFER_SIZE - 1) ,"%s,%s,%s", mFocusDistNear,
649                                                                              mFocusDistOptimal,
650                                                                              mFocusDistFar);
651
652        params.set(CameraParameters::KEY_FOCUS_DISTANCES, mFocusDistBuffer);
653        }
654
655    LOG_FUNCTION_NAME_EXIT;
656
657    return ret;
658}
659
660status_t OMXCameraAdapter::setTouchFocus(size_t posX,
661                                         size_t posY,
662                                         size_t posWidth,
663                                         size_t posHeight,
664                                         size_t previewWidth,
665                                         size_t previewHeight)
666{
667    status_t ret = NO_ERROR;
668    OMX_ERRORTYPE eError = OMX_ErrorNone;
669    OMX_CONFIG_EXTFOCUSREGIONTYPE touchControl;
670
671    LOG_FUNCTION_NAME;
672
673    if ( OMX_StateInvalid == mComponentState )
674        {
675        CAMHAL_LOGEA("OMX component is in invalid state");
676        ret = -1;
677        }
678
679    if ( NO_ERROR == ret )
680        {
681        OMX_INIT_STRUCT_PTR (&touchControl, OMX_CONFIG_EXTFOCUSREGIONTYPE);
682        touchControl.nLeft = ( posX * TOUCH_FOCUS_RANGE ) / previewWidth;
683        touchControl.nTop =  ( posY * TOUCH_FOCUS_RANGE ) / previewHeight;
684        touchControl.nWidth = ( posWidth * TOUCH_FOCUS_RANGE ) / previewWidth;
685        touchControl.nHeight = ( posHeight * TOUCH_FOCUS_RANGE ) / previewHeight;
686
687        eError =  OMX_SetConfig(mCameraAdapterParameters.mHandleComp,
688                                ( OMX_INDEXTYPE ) OMX_IndexConfigExtFocusRegion,
689                                &touchControl);
690        if ( OMX_ErrorNone != eError )
691            {
692            CAMHAL_LOGEB("Error while configuring touch focus 0x%x", eError);
693            ret = -1;
694            }
695        else
696            {
697            CAMHAL_LOGDB("Touch focus %d,%d %d,%d configured successfuly",
698                         ( int ) touchControl.nLeft,
699                         ( int ) touchControl.nTop,
700                         ( int ) touchControl.nWidth,
701                         ( int ) touchControl.nHeight);
702            }
703        }
704
705    LOG_FUNCTION_NAME_EXIT;
706
707    return ret;
708}
709
710};
711