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