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