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