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 &params,
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 &params)
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