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