1c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev/*
2c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * Copyright (C) Texas Instruments - http://www.ti.com/
3c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev *
4c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * Licensed under the Apache License, Version 2.0 (the "License");
5c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * you may not use this file except in compliance with the License.
6c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * You may obtain a copy of the License at
7c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev *
8c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev *      http://www.apache.org/licenses/LICENSE-2.0
9c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev *
10c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * Unless required by applicable law or agreed to in writing, software
11c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * distributed under the License is distributed on an "AS IS" BASIS,
12c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * See the License for the specific language governing permissions and
14c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev * limitations under the License.
15c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev */
16c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
17c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev/**
18c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev* @file OMXFD.cpp
19c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev*
20c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev* This file contains functionality for handling face detection.
21c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev*
22c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev*/
23c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
24c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev#undef LOG_TAG
25c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
26c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev#define LOG_TAG "CameraHAL"
27c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
28c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev#include "CameraHal.h"
29c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev#include "OMXCameraAdapter.h"
30c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
31967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman#define FACE_DETECTION_THRESHOLD 80
32967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman
337762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu// constants used for face smooth filtering
347762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luustatic const int HorizontalFilterThreshold = 40;
357762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luustatic const int VerticalFilterThreshold = 40;
367762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luustatic const int HorizontalFaceSizeThreshold = 30;
377762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luustatic const int VerticalFaceSizeThreshold = 30;
387762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
397762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
40c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevnamespace android {
41c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
42c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::setParametersFD(const CameraParameters &params,
43c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                           BaseCameraAdapter::AdapterState state)
44c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
45c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    status_t ret = NO_ERROR;
46c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
47c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME;
48c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
49c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME_EXIT;
50c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
51c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    return ret;
52c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
53c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
54c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::startFaceDetection()
55c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
56c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    status_t ret = NO_ERROR;
57c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
58c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    Mutex::Autolock lock(mFaceDetectionLock);
59c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
60c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    ret = setFaceDetection(true, mDeviceOrientation);
61c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    if (ret != NO_ERROR) {
62c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman        goto out;
63c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    }
64c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
65f2170decdf6bf41e590842b0fe5c0ed3852ebec3Emilian Peev    if ( mFaceDetectionRunning ) {
66f2170decdf6bf41e590842b0fe5c0ed3852ebec3Emilian Peev        mFDSwitchAlgoPriority = true;
67f2170decdf6bf41e590842b0fe5c0ed3852ebec3Emilian Peev    }
68c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
697762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    // Note: White balance will not be face prioritized, since
707762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    // the algorithm needs full frame statistics, and not face
717762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    // regions alone.
72c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
737762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    faceDetectionNumFacesLastOutput = 0;
74c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman out:
75c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    return ret;
76c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
77c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
78c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::stopFaceDetection()
79c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
80c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    status_t ret = NO_ERROR;
81c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    const char *str = NULL;
82c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    BaseCameraAdapter::AdapterState state;
83c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    BaseCameraAdapter::getState(state);
84c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
85c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    Mutex::Autolock lock(mFaceDetectionLock);
86c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
87c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    ret = setFaceDetection(false, mDeviceOrientation);
88c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    if (ret != NO_ERROR) {
89c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman        goto out;
90c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    }
91c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
92c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    // Reset 3A settings
93c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    ret = setParameters3A(mParams, state);
94c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    if (ret != NO_ERROR) {
95c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman        goto out;
96c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    }
97c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
98c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    if (mPending3Asettings) {
99c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman        apply3Asettings(mParameters3A);
100c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    }
101c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
1027762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    faceDetectionNumFacesLastOutput = 0;
103c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman out:
104c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    return ret;
105c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
106c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
107aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luuvoid OMXCameraAdapter::pauseFaceDetection(bool pause)
108aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu{
109aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu    Mutex::Autolock lock(mFaceDetectionLock);
110aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu    // pausing will only take affect if fd is already running
111aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu    if (mFaceDetectionRunning) {
112aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu        mFaceDetectionPaused = pause;
1137762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        faceDetectionNumFacesLastOutput = 0;
114aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu    }
115aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu}
116aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu
117c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::setFaceDetection(bool enable, OMX_U32 orientation)
118c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
119c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    status_t ret = NO_ERROR;
120c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_ERRORTYPE eError = OMX_ErrorNone;
121c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_CONFIG_OBJDETECTIONTYPE objDetection;
122c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
123c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME;
124c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
125c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( OMX_StateInvalid == mComponentState )
126c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        {
127c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGEA("OMX component is in invalid state");
128c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        ret = -EINVAL;
129c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
130c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
131c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NO_ERROR == ret )
132c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        {
1337762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        if ( orientation > 270 ) {
134c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            orientation = 0;
135c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
136c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
137c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        OMX_INIT_STRUCT_PTR (&objDetection, OMX_CONFIG_OBJDETECTIONTYPE);
138c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        objDetection.nPortIndex = mCameraAdapterParameters.mPrevPortIndex;
139c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        objDetection.nDeviceOrientation = orientation;
140c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        if  ( enable )
141c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
142c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            objDetection.bEnable = OMX_TRUE;
143c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
144c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        else
145c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
146c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            objDetection.bEnable = OMX_FALSE;
147c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
148c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
149c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        eError =  OMX_SetConfig(mCameraAdapterParameters.mHandleComp,
150c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                ( OMX_INDEXTYPE ) OMX_IndexConfigImageFaceDetection,
151c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                &objDetection);
152c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        if ( OMX_ErrorNone != eError )
153c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
154c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            CAMHAL_LOGEB("Error while configuring face detection 0x%x", eError);
155c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            ret = -1;
156c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
157c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        else
158c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
159c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            CAMHAL_LOGDA("Face detection configured successfully");
160c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
161c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
162c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
163c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NO_ERROR == ret )
164c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        {
165ef73bec8a83a2fd7fbb072d009382c64eb2da0eeTyler Luu        ret = setExtraData(enable, mCameraAdapterParameters.mPrevPortIndex, OMX_FaceDetection);
166c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
167ef73bec8a83a2fd7fbb072d009382c64eb2da0eeTyler Luu        if ( NO_ERROR != ret )
168c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
169ef73bec8a83a2fd7fbb072d009382c64eb2da0eeTyler Luu            CAMHAL_LOGEA("Error while configuring face detection extra data");
170c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
171c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        else
172c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
173c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            CAMHAL_LOGDA("Face detection extra data configured successfully");
174c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
175c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
176c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
177c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NO_ERROR == ret )
178c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        {
179c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        mFaceDetectionRunning = enable;
180aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu        mFaceDetectionPaused = !enable;
181c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
182c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
183c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME_EXIT;
184c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
185c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    return ret;
186c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
187c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
188c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::detectFaces(OMX_BUFFERHEADERTYPE* pBuffHeader,
189c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                       sp<CameraFDResult> &result,
190c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                       size_t previewWidth,
191c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                       size_t previewHeight)
192c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
193c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    status_t ret = NO_ERROR;
194c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_ERRORTYPE eError = OMX_ErrorNone;
195c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_TI_FACERESULT *faceResult;
196c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_OTHER_EXTRADATATYPE *extraData;
197c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_FACEDETECTIONTYPE *faceData;
198c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_TI_PLATFORMPRIVATE *platformPrivate;
199c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    camera_frame_metadata_t *faces;
200c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
201c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME;
202c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
203c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( OMX_StateExecuting != mComponentState ) {
204c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGEA("OMX component is not in executing state");
205c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return NO_INIT;
206c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
207c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
208c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NULL == pBuffHeader ) {
209c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGEA("Invalid Buffer header");
210c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return-EINVAL;
211c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
212c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
213c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    platformPrivate = (OMX_TI_PLATFORMPRIVATE *) (pBuffHeader->pPlatformPrivate);
214c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NULL != platformPrivate ) {
215c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        if ( sizeof(OMX_TI_PLATFORMPRIVATE) == platformPrivate->nSize ) {
216c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            CAMHAL_LOGVB("Size = %d, sizeof = %d, pAuxBuf = 0x%x, pAuxBufSize= %d, pMetaDataBufer = 0x%x, nMetaDataSize = %d",
217c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         platformPrivate->nSize,
218c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         sizeof(OMX_TI_PLATFORMPRIVATE),
219c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         platformPrivate->pAuxBuf1,
220c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         platformPrivate->pAuxBufSize1,
221c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         platformPrivate->pMetaDataBuffer,
222c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         platformPrivate->nMetaDataSize);
223c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        } else {
22441a31123a0fc59b8112460285d3f1ba73c5537c0Emilian Peev            CAMHAL_LOGDB("OMX_TI_PLATFORMPRIVATE size mismatch: expected = %d, received = %d",
225c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         ( unsigned int ) sizeof(OMX_TI_PLATFORMPRIVATE),
226c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         ( unsigned int ) platformPrivate->nSize);
22782640237cf0ca200932a66777fd1907d66cd0322Akwasi Boateng            return -EINVAL;
228c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
229c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }  else {
23041a31123a0fc59b8112460285d3f1ba73c5537c0Emilian Peev        CAMHAL_LOGDA("Invalid OMX_TI_PLATFORMPRIVATE");
231c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return-EINVAL;
232c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
233c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
234c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
235c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( 0 >= platformPrivate->nMetaDataSize ) {
23641a31123a0fc59b8112460285d3f1ba73c5537c0Emilian Peev        CAMHAL_LOGDB("OMX_TI_PLATFORMPRIVATE nMetaDataSize is size is %d",
237c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                     ( unsigned int ) platformPrivate->nMetaDataSize);
238c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return -EINVAL;
239c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
240c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
241cf0a61f13533d70cb7ad700330de94142c2afe6aMilen Mitkov    extraData = getExtradata((OMX_OTHER_EXTRADATATYPE *) (platformPrivate->pMetaDataBuffer),
242cf0a61f13533d70cb7ad700330de94142c2afe6aMilen Mitkov            (OMX_EXTRADATATYPE)OMX_FaceDetection);
243cf0a61f13533d70cb7ad700330de94142c2afe6aMilen Mitkov
244c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NULL != extraData ) {
245c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x",
246c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                     extraData->nSize,
247c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                     sizeof(OMX_OTHER_EXTRADATATYPE),
248c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                     extraData->eType,
249c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                     extraData->nDataSize,
250c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                     extraData->nPortIndex,
251c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                     extraData->nVersion);
252c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    } else {
25341a31123a0fc59b8112460285d3f1ba73c5537c0Emilian Peev        CAMHAL_LOGDA("Invalid OMX_OTHER_EXTRADATATYPE");
254c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return -EINVAL;
255c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
256c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
257c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    faceData = ( OMX_FACEDETECTIONTYPE * ) extraData->data;
258c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NULL != faceData ) {
259c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        if ( sizeof(OMX_FACEDETECTIONTYPE) == faceData->nSize ) {
260c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            CAMHAL_LOGVB("Faces detected %d",
261c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         faceData->ulFaceCount,
262c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         faceData->nSize,
263c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         sizeof(OMX_FACEDETECTIONTYPE),
264c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         faceData->eCameraView,
265c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         faceData->nPortIndex,
266c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         faceData->nVersion);
267c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        } else {
26841a31123a0fc59b8112460285d3f1ba73c5537c0Emilian Peev            CAMHAL_LOGDB("OMX_FACEDETECTIONTYPE size mismatch: expected = %d, received = %d",
269c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         ( unsigned int ) sizeof(OMX_FACEDETECTIONTYPE),
270c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                         ( unsigned int ) faceData->nSize);
271c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            return -EINVAL;
272c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
273c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    } else {
274c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE");
275c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return -EINVAL;
276c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
277c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
278c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    ret = encodeFaceCoordinates(faceData, &faces, previewWidth, previewHeight);
279c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
280c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NO_ERROR == ret ) {
281c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        result = new CameraFDResult(faces);
282c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    } else {
283c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        result.clear();
284c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        result = NULL;
285c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
286c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
287c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME_EXIT;
288c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
289c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    return ret;
290c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
291c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
292c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::encodeFaceCoordinates(const OMX_FACEDETECTIONTYPE *faceData,
293c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                                 camera_frame_metadata_t **pFaces,
294c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                                 size_t previewWidth,
295c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                                 size_t previewHeight)
296c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
297c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    status_t ret = NO_ERROR;
298c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    camera_face_t *faces;
299c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    camera_frame_metadata_t *faceResult;
300c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    size_t hRange, vRange;
301c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    double tmp;
302c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
303c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME;
304c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
305c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NULL == faceData ) {
306c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE parameter");
307c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return EINVAL;
308c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
309c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
310c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME
311c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
312c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    hRange = CameraFDResult::RIGHT - CameraFDResult::LEFT;
313c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    vRange = CameraFDResult::BOTTOM - CameraFDResult::TOP;
314c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
315c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    faceResult = ( camera_frame_metadata_t * ) malloc(sizeof(camera_frame_metadata_t));
316c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NULL == faceResult ) {
317c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return -ENOMEM;
318c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
319c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
320c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( 0 < faceData->ulFaceCount ) {
321fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        int orient_mult;
322fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        int trans_left, trans_top, trans_right, trans_bot;
323c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
324c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        faces = ( camera_face_t * ) malloc(sizeof(camera_face_t)*faceData->ulFaceCount);
325c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        if ( NULL == faces ) {
326c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            return -ENOMEM;
327c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
328c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
329fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        /**
330fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * When device is 180 degrees oriented to the sensor, need to translate
331fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * the output from Ducati to what Android expects
332fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * Ducati always gives face coordinates in this form, irrespective of
333fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * rotation, i.e (l,t) always represents the point towards the left eye
334fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * and top of hair.
335fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * (l, t)
336fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   ---------------
337fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -   ,,,,,,,   -
338fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |       |  -
339fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |<a   <a|  -
340fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   - (|   ^   |) -
341fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |  -=-  |  -
342fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -   \_____/   -
343fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   ---------------
344fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *               (r, b)
345fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *
346fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * However, Android expects the coords to be in respect with what the
347fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * sensor is viewing, i.e Android expects sensor to see this with (l,t)
348fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * and (r,b) like so:
349fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * (l, t)
350fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   ---------------
351fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -    _____    -
352fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -   /     \   -
353fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |  -=-  |  -
354fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   - (|   ^   |) -
355fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |a>   a>|  -
356fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |       |  -
357fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -   ,,,,,,,   -
358fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   ---------------
359fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *               (r, b)
360fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu          */
361c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
3627762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        if (mDeviceOrientation == 180) {
3637762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            orient_mult = -1;
3647762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_left = 2; // right is now left
3657762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_top = 3; // bottom is now top
3667762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_right = 0; // left is now right
3677762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_bot = 1; // top is not bottom
3687762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        } else {
3697762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            orient_mult = 1;
3707762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_left = 0; // left
3717762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_top = 1; // top
3727762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_right = 2; // right
3737762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_bot = 3; // bottom
3747762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        }
3757762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
376967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman        int j = 0, i = 0;
377967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman        for ( ; j < faceData->ulFaceCount ; j++)
378967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            {
37952d3388c121469e22bf41d7362640257d8268858Tyler Luu             OMX_S32 nLeft = 0;
380e45763a2a361324f1771a6991525e631365ca954Tyler Luu             OMX_S32 nTop = 0;
381967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //Face filtering
382967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //For real faces, it is seen that the h/w passes a score >=80
383967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //For false faces, we seem to get even a score of 70 sometimes.
384967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //In order to avoid any issue at application level, we filter
385967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //<=70 score here.
386967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            if(faceData->tFacePosition[j].nScore <= FACE_DETECTION_THRESHOLD)
387967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             continue;
388967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman
38952d3388c121469e22bf41d7362640257d8268858Tyler Luu            if (mDeviceOrientation == 180) {
39052d3388c121469e22bf41d7362640257d8268858Tyler Luu                // from sensor pov, the left pos is the right corner of the face in pov of frame
3917762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                nLeft = faceData->tFacePosition[j].nLeft + faceData->tFacePosition[j].nWidth;
392e45763a2a361324f1771a6991525e631365ca954Tyler Luu                nTop =  faceData->tFacePosition[j].nTop + faceData->tFacePosition[j].nHeight;
39352d3388c121469e22bf41d7362640257d8268858Tyler Luu            } else {
3947762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                nLeft = faceData->tFacePosition[j].nLeft;
395e45763a2a361324f1771a6991525e631365ca954Tyler Luu                nTop =  faceData->tFacePosition[j].nTop;
39652d3388c121469e22bf41d7362640257d8268858Tyler Luu            }
39752d3388c121469e22bf41d7362640257d8268858Tyler Luu
39852d3388c121469e22bf41d7362640257d8268858Tyler Luu            tmp = ( double ) nLeft / ( double ) previewWidth;
399c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp *= hRange;
400c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp -= hRange/2;
401fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            faces[i].rect[trans_left] = tmp;
402c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
403e45763a2a361324f1771a6991525e631365ca954Tyler Luu            tmp = ( double ) nTop / ( double )previewHeight;
404c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp *= vRange;
405c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp -= vRange/2;
406fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            faces[i].rect[trans_top] = tmp;
407c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
408967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            tmp = ( double ) faceData->tFacePosition[j].nWidth / ( double ) previewWidth;
409c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp *= hRange;
410fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            tmp *= orient_mult;
411fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            faces[i].rect[trans_right] = faces[i].rect[trans_left] + tmp;
412c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
413967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            tmp = ( double ) faceData->tFacePosition[j].nHeight / ( double ) previewHeight;
414c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp *= vRange;
415fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            tmp *= orient_mult;
416fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            faces[i].rect[trans_bot] = faces[i].rect[trans_top] + tmp;
417c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
418967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            faces[i].score = faceData->tFacePosition[j].nScore;
419c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            faces[i].id = 0;
420c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            faces[i].left_eye[0] = CameraFDResult::INVALID_DATA;
421c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            faces[i].left_eye[1] = CameraFDResult::INVALID_DATA;
422c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            faces[i].right_eye[0] = CameraFDResult::INVALID_DATA;
423c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            faces[i].right_eye[1] = CameraFDResult::INVALID_DATA;
424c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            faces[i].mouth[0] = CameraFDResult::INVALID_DATA;
425c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            faces[i].mouth[1] = CameraFDResult::INVALID_DATA;
426967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            i++;
427c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
428c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
429967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman        faceResult->number_of_faces = i;
430c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        faceResult->faces = faces;
431c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
4327762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        for (int i = 0; i  < faceResult->number_of_faces; i++)
4337762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        {
4347762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            int centerX = (faces[i].rect[trans_left] + faces[i].rect[trans_right] ) / 2;
4357762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            int centerY = (faces[i].rect[trans_top] + faces[i].rect[trans_bot] ) / 2;
4367762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
4377762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            int sizeX = (faces[i].rect[trans_right] - faces[i].rect[trans_left] ) ;
4387762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            int sizeY = (faces[i].rect[trans_bot] - faces[i].rect[trans_top] ) ;
4397762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
4407762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            for (int j = 0; j < faceDetectionNumFacesLastOutput; j++)
4417762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            {
4427762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                int tempCenterX = (faceDetectionLastOutput[j].rect[trans_left] +
4437762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                                  faceDetectionLastOutput[j].rect[trans_right] ) / 2;
4447762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                int tempCenterY = (faceDetectionLastOutput[j].rect[trans_top] +
4457762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                                  faceDetectionLastOutput[j].rect[trans_bot] ) / 2;
4467762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                int tempSizeX = (faceDetectionLastOutput[j].rect[trans_right] -
4477762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                                faceDetectionLastOutput[j].rect[trans_left] ) ;
4487762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                int tempSizeY = (faceDetectionLastOutput[j].rect[trans_bot] -
4497762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                                faceDetectionLastOutput[j].rect[trans_top] ) ;
4507762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
4517762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                if ( (abs(tempCenterX - centerX) < HorizontalFilterThreshold) &&
4527762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                     (abs(tempCenterY - centerY) < VerticalFilterThreshold) )
4537762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                {
4547762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    // Found Face. It did not move too far.
4557762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    // Now check size of rectangle compare to last output
4567762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    if ( (abs (tempSizeX -sizeX) < HorizontalFaceSizeThreshold) &&
4577762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                         (abs (tempSizeY -sizeY) < VerticalFaceSizeThreshold) )
4587762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    {
4597762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                        // Rectangle is almost same as last time
4607762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                        // Output exactly what was done for this face last time.
4617762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                        faces[i] = faceDetectionLastOutput[j];
4627762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    }
4637762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    else
4647762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    {
4657762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                        // TODO(XXX): Rectangle size changed but position is same.
4667762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                        // Possibly we can apply just positional correctness.
4677762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    }
4687762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                }
4697762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            }
4707762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        }
4717762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
4727762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        // Save this output for next iteration
4737762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        for (int i = 0; i  < faceResult->number_of_faces; i++)
4747762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        {
4757762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            faceDetectionLastOutput[i] = faces[i];
4767762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        }
4777762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        faceDetectionNumFacesLastOutput = faceResult->number_of_faces;
478c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    } else {
479c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        faceResult->number_of_faces = 0;
480c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        faceResult->faces = NULL;
481c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
482c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
483c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    *pFaces = faceResult;
484c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
485c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME_EXIT;
486c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
487c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    return ret;
488c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
489c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
490c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev};
491