OMXFocus.cpp revision aa6e62e279cb54ae76c55ba9f8d02da230ce34e7
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(true);
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        else
393            {
394
395            switch (eFocusStatus.eFocusStatus)
396                {
397                    case OMX_FocusStatusReached:
398                        {
399                        focusStatus = true;
400                        //Lock the AE and AWB here sinc the focus is locked
401                        // Apply 3A locks after AF
402                        if( set3ALock(OMX_TRUE) != NO_ERROR) {
403                            CAMHAL_LOGEA("Error Applying 3A locks");
404                        }
405                        else
406                            {
407                            LOGE("Focus locked. Applied focus locks successfully");
408                            }
409                        break;
410                        }
411                    case OMX_FocusStatusOff:
412                    case OMX_FocusStatusUnableToReach:
413                    case OMX_FocusStatusRequest:
414                    default:
415                        {
416                        focusStatus = false;
417                        break;
418                        }
419                }
420
421            stopAutoFocus();
422            }
423        }
424
425    if ( NO_ERROR == ret )
426        {
427
428        ret =  BaseCameraAdapter::setState(CAMERA_CANCEL_AUTOFOCUS);
429
430        if ( NO_ERROR == ret )
431            {
432            ret = BaseCameraAdapter::commitState();
433            }
434        else
435            {
436            ret |= BaseCameraAdapter::rollbackState();
437            }
438
439        }
440
441    if ( NO_ERROR == ret )
442        {
443        notifyFocusSubscribers(focusStatus);
444        }
445
446    // After focus, face detection will resume sending face callbacks
447    pauseFaceDetection(false);
448
449    LOG_FUNCTION_NAME_EXIT;
450
451    return ret;
452}
453
454status_t OMXCameraAdapter::checkFocus(OMX_PARAM_FOCUSSTATUSTYPE *eFocusStatus)
455{
456    status_t ret = NO_ERROR;
457    OMX_ERRORTYPE eError = OMX_ErrorNone;
458
459    LOG_FUNCTION_NAME;
460
461    if ( NULL == eFocusStatus )
462        {
463        CAMHAL_LOGEA("Invalid focus status");
464        ret = -EINVAL;
465        }
466
467    if ( OMX_StateExecuting != mComponentState )
468        {
469        CAMHAL_LOGEA("OMX component not in executing state");
470        ret = -EINVAL;
471        }
472
473    if ( NO_ERROR == ret )
474        {
475        OMX_INIT_STRUCT_PTR (eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE);
476
477        eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp,
478                               OMX_IndexConfigCommonFocusStatus,
479                               eFocusStatus);
480        if ( OMX_ErrorNone != eError )
481            {
482            CAMHAL_LOGEB("Error while retrieving focus status: 0x%x", eError);
483            ret = -1;
484            }
485        }
486
487    if ( NO_ERROR == ret )
488        {
489        CAMHAL_LOGDB("Focus Status: %d", eFocusStatus->eFocusStatus);
490        }
491
492    LOG_FUNCTION_NAME_EXIT;
493
494    return ret;
495}
496
497status_t OMXCameraAdapter::updateFocusDistances(CameraParameters &params)
498{
499    OMX_U32 focusNear, focusOptimal, focusFar;
500    status_t ret = NO_ERROR;
501
502    LOG_FUNCTION_NAME;
503
504    ret = getFocusDistances(focusNear, focusOptimal, focusFar);
505    if ( NO_ERROR == ret)
506        {
507        ret = addFocusDistances(focusNear, focusOptimal, focusFar, params);
508            if ( NO_ERROR != ret )
509                {
510                CAMHAL_LOGEB("Error in call to addFocusDistances() 0x%x", ret);
511                }
512        }
513    else
514        {
515        CAMHAL_LOGEB("Error in call to getFocusDistances() 0x%x", ret);
516        }
517
518    LOG_FUNCTION_NAME_EXIT;
519
520    return ret;
521}
522
523status_t OMXCameraAdapter::getFocusDistances(OMX_U32 &near,OMX_U32 &optimal, OMX_U32 &far)
524{
525    status_t ret = NO_ERROR;
526    OMX_ERRORTYPE eError;
527
528    OMX_TI_CONFIG_FOCUSDISTANCETYPE focusDist;
529
530    LOG_FUNCTION_NAME;
531
532    if ( OMX_StateInvalid == mComponentState )
533        {
534        CAMHAL_LOGEA("OMX component is in invalid state");
535        ret = UNKNOWN_ERROR;
536        }
537
538    if ( NO_ERROR == ret )
539        {
540        OMX_INIT_STRUCT_PTR(&focusDist, OMX_TI_CONFIG_FOCUSDISTANCETYPE);
541        focusDist.nPortIndex = mCameraAdapterParameters.mPrevPortIndex;
542
543        eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp,
544                               ( OMX_INDEXTYPE ) OMX_TI_IndexConfigFocusDistance,
545                               &focusDist);
546        if ( OMX_ErrorNone != eError )
547            {
548            CAMHAL_LOGEB("Error while querying focus distances 0x%x", eError);
549            ret = UNKNOWN_ERROR;
550            }
551
552        }
553
554    if ( NO_ERROR == ret )
555        {
556        near = focusDist.nFocusDistanceNear;
557        optimal = focusDist.nFocusDistanceOptimal;
558        far = focusDist.nFocusDistanceFar;
559        }
560
561    LOG_FUNCTION_NAME_EXIT;
562
563    return ret;
564}
565
566status_t OMXCameraAdapter::encodeFocusDistance(OMX_U32 dist, char *buffer, size_t length)
567{
568    status_t ret = NO_ERROR;
569    uint32_t focusScale = 1000;
570    float distFinal;
571
572    LOG_FUNCTION_NAME;
573
574    if(mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity)
575        {
576        dist=0;
577        }
578
579    if ( NO_ERROR == ret )
580        {
581        if ( 0 == dist )
582            {
583            strncpy(buffer, CameraParameters::FOCUS_DISTANCE_INFINITY, ( length - 1 ));
584            }
585        else
586            {
587            distFinal = dist;
588            distFinal /= focusScale;
589            snprintf(buffer, ( length - 1 ) , "%5.3f", distFinal);
590            }
591        }
592
593    LOG_FUNCTION_NAME_EXIT;
594
595    return ret;
596}
597
598status_t OMXCameraAdapter::addFocusDistances(OMX_U32 &near,
599                                             OMX_U32 &optimal,
600                                             OMX_U32 &far,
601                                             CameraParameters& params)
602{
603    status_t ret = NO_ERROR;
604
605    LOG_FUNCTION_NAME;
606
607    if ( NO_ERROR == ret )
608        {
609        ret = encodeFocusDistance(near, mFocusDistNear, FOCUS_DIST_SIZE);
610        if ( NO_ERROR != ret )
611            {
612            CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret);
613            }
614        }
615
616    if ( NO_ERROR == ret )
617        {
618        ret = encodeFocusDistance(optimal, mFocusDistOptimal, FOCUS_DIST_SIZE);
619        if ( NO_ERROR != ret )
620            {
621            CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret);
622            }
623        }
624
625    if ( NO_ERROR == ret )
626        {
627        ret = encodeFocusDistance(far, mFocusDistFar, FOCUS_DIST_SIZE);
628        if ( NO_ERROR != ret )
629            {
630            CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret);
631            }
632        }
633
634    if ( NO_ERROR == ret )
635        {
636        snprintf(mFocusDistBuffer, ( FOCUS_DIST_BUFFER_SIZE - 1) ,"%s,%s,%s", mFocusDistNear,
637                                                                              mFocusDistOptimal,
638                                                                              mFocusDistFar);
639
640        params.set(CameraParameters::KEY_FOCUS_DISTANCES, mFocusDistBuffer);
641        }
642
643    LOG_FUNCTION_NAME_EXIT;
644
645    return ret;
646}
647
648status_t OMXCameraAdapter::setTouchFocus(size_t posX,
649                                         size_t posY,
650                                         size_t posWidth,
651                                         size_t posHeight,
652                                         size_t previewWidth,
653                                         size_t previewHeight)
654{
655    status_t ret = NO_ERROR;
656    OMX_ERRORTYPE eError = OMX_ErrorNone;
657    OMX_CONFIG_EXTFOCUSREGIONTYPE touchControl;
658
659    LOG_FUNCTION_NAME;
660
661    if ( OMX_StateInvalid == mComponentState )
662        {
663        CAMHAL_LOGEA("OMX component is in invalid state");
664        ret = -1;
665        }
666
667    if ( NO_ERROR == ret )
668        {
669        OMX_INIT_STRUCT_PTR (&touchControl, OMX_CONFIG_EXTFOCUSREGIONTYPE);
670        touchControl.nLeft = ( posX * TOUCH_FOCUS_RANGE ) / previewWidth;
671        touchControl.nTop =  ( posY * TOUCH_FOCUS_RANGE ) / previewHeight;
672        touchControl.nWidth = ( posWidth * TOUCH_FOCUS_RANGE ) / previewWidth;
673        touchControl.nHeight = ( posHeight * TOUCH_FOCUS_RANGE ) / previewHeight;
674
675        eError =  OMX_SetConfig(mCameraAdapterParameters.mHandleComp,
676                                ( OMX_INDEXTYPE ) OMX_IndexConfigExtFocusRegion,
677                                &touchControl);
678        if ( OMX_ErrorNone != eError )
679            {
680            CAMHAL_LOGEB("Error while configuring touch focus 0x%x", eError);
681            ret = -1;
682            }
683        else
684            {
685            CAMHAL_LOGDB("Touch focus %d,%d %d,%d configured successfuly",
686                         ( int ) touchControl.nLeft,
687                         ( int ) touchControl.nTop,
688                         ( int ) touchControl.nWidth,
689                         ( int ) touchControl.nHeight);
690            }
691        }
692
693    LOG_FUNCTION_NAME_EXIT;
694
695    return ret;
696}
697
698};
699