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#include "CameraHal.h"
25c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev#include "OMXCameraAdapter.h"
26c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
27f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsnamespace Ti {
28f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsnamespace Camera {
297762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
30f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsconst uint32_t OMXCameraAdapter::FACE_DETECTION_THRESHOLD = 80;
317762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
32f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsstatus_t OMXCameraAdapter::setParametersFD(const android::CameraParameters &params,
33c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                           BaseCameraAdapter::AdapterState state)
34c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
35c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    status_t ret = NO_ERROR;
36c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
37c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME;
38c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
39c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME_EXIT;
40c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
41c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    return ret;
42c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
43c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
44c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::startFaceDetection()
45c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
46c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    status_t ret = NO_ERROR;
47c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
48f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android::AutoMutex lock(mFaceDetectionLock);
49c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
50f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    ret = setFaceDetection(true, mFaceOrientation);
51c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    if (ret != NO_ERROR) {
52c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman        goto out;
53c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    }
54c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
55f2170decdf6bf41e590842b0fe5c0ed3852ebec3Emilian Peev    if ( mFaceDetectionRunning ) {
56f2170decdf6bf41e590842b0fe5c0ed3852ebec3Emilian Peev        mFDSwitchAlgoPriority = true;
57f2170decdf6bf41e590842b0fe5c0ed3852ebec3Emilian Peev    }
58c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
597762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    // Note: White balance will not be face prioritized, since
607762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    // the algorithm needs full frame statistics, and not face
617762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    // regions alone.
62c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
637762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    faceDetectionNumFacesLastOutput = 0;
64c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman out:
65c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    return ret;
66c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
67c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
68c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::stopFaceDetection()
69c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
70c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    status_t ret = NO_ERROR;
71c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    const char *str = NULL;
72c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    BaseCameraAdapter::AdapterState state;
73c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    BaseCameraAdapter::getState(state);
74c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
75f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android::AutoMutex lock(mFaceDetectionLock);
76c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
77f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    ret = setFaceDetection(false, mFaceOrientation);
78c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    if (ret != NO_ERROR) {
79c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman        goto out;
80c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    }
81c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
82f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ( mFaceDetectionRunning ) {
83f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        //Enable region priority and disable face priority for AF
84f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        setAlgoPriority(REGION_PRIORITY, FOCUS_ALGO, true);
85f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        setAlgoPriority(FACE_PRIORITY, FOCUS_ALGO , false);
86f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
87f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        //Enable Region priority and disable Face priority
88f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        setAlgoPriority(REGION_PRIORITY, EXPOSURE_ALGO, true);
89f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        setAlgoPriority(FACE_PRIORITY, EXPOSURE_ALGO, false);
90c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    }
91c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
92c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    if (mPending3Asettings) {
93c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman        apply3Asettings(mParameters3A);
94c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    }
95c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman
967762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu    faceDetectionNumFacesLastOutput = 0;
97c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman out:
98c0fc811b503ef0c0ccd024f77f9ac7d6972f77c8Sundar Raman    return ret;
99c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
100c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
101aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luuvoid OMXCameraAdapter::pauseFaceDetection(bool pause)
102aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu{
103f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android::AutoMutex lock(mFaceDetectionLock);
104aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu    // pausing will only take affect if fd is already running
105aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu    if (mFaceDetectionRunning) {
106aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu        mFaceDetectionPaused = pause;
1077762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        faceDetectionNumFacesLastOutput = 0;
108aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu    }
109aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu}
110aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu
111f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsstatus_t OMXCameraAdapter::setFaceDetectionOrientation(OMX_U32 orientation)
112f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons{
113f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    status_t ret = NO_ERROR;
114f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
115f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android::AutoMutex lock(mFaceDetectionLock);
116f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
117f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    mFaceOrientation = orientation;
118f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
119f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if (mFaceDetectionRunning) {
120f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // restart face detection with new rotation
121f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        setFaceDetection(true, orientation);
122f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    }
123f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
124f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    return ret;
125f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons}
126f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
127c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::setFaceDetection(bool enable, OMX_U32 orientation)
128c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
129c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    status_t ret = NO_ERROR;
130c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_ERRORTYPE eError = OMX_ErrorNone;
131c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    OMX_CONFIG_OBJDETECTIONTYPE objDetection;
132c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
133c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME;
134c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
135c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( OMX_StateInvalid == mComponentState )
136c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        {
137c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGEA("OMX component is in invalid state");
138c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        ret = -EINVAL;
139c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
140c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
141c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NO_ERROR == ret )
142c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        {
1437762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        if ( orientation > 270 ) {
144c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            orientation = 0;
145c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
146c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
147c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        OMX_INIT_STRUCT_PTR (&objDetection, OMX_CONFIG_OBJDETECTIONTYPE);
148c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        objDetection.nPortIndex = mCameraAdapterParameters.mPrevPortIndex;
149c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        objDetection.nDeviceOrientation = orientation;
150c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        if  ( enable )
151c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
152c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            objDetection.bEnable = OMX_TRUE;
153c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
154c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        else
155c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
156c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            objDetection.bEnable = OMX_FALSE;
157c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
158c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
159c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        eError =  OMX_SetConfig(mCameraAdapterParameters.mHandleComp,
160c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                ( OMX_INDEXTYPE ) OMX_IndexConfigImageFaceDetection,
161c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                &objDetection);
162c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        if ( OMX_ErrorNone != eError )
163c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
164c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            CAMHAL_LOGEB("Error while configuring face detection 0x%x", eError);
165c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            ret = -1;
166c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
167c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        else
168c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
169c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            CAMHAL_LOGDA("Face detection configured successfully");
170c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
171c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
172c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
173c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NO_ERROR == ret )
174c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        {
175f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // TODO(XXX): Should enable/disable FD extra data separately
176f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // on each port.
177f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        ret = setExtraData(enable, OMX_ALL, OMX_FaceDetection);
178c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
179ef73bec8a83a2fd7fbb072d009382c64eb2da0eeTyler Luu        if ( NO_ERROR != ret )
180c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
181ef73bec8a83a2fd7fbb072d009382c64eb2da0eeTyler Luu            CAMHAL_LOGEA("Error while configuring face detection extra data");
182c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
183c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        else
184c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            {
185c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            CAMHAL_LOGDA("Face detection extra data configured successfully");
186c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
187c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
188c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
189c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NO_ERROR == ret )
190c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        {
191c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        mFaceDetectionRunning = enable;
192aa6e62e279cb54ae76c55ba9f8d02da230ce34e7Tyler Luu        mFaceDetectionPaused = !enable;
193c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
194c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
195c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME_EXIT;
196c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
197c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    return ret;
198c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
199c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
200f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsstatus_t OMXCameraAdapter::createPreviewMetadata(OMX_BUFFERHEADERTYPE* pBuffHeader,
201f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                                          android::sp<CameraMetadataResult> &result,
202f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                                          size_t previewWidth,
203f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                                          size_t previewHeight)
204c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
205c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    status_t ret = NO_ERROR;
206f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    status_t faceRet = NO_ERROR;
207f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    status_t metaRet = NO_ERROR;
208f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    OMX_FACEDETECTIONTYPE *faceData = NULL;
209c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
210c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME;
211c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
212c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( OMX_StateExecuting != mComponentState ) {
213c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGEA("OMX component is not in executing state");
214c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return NO_INIT;
215c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
216c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
217c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    if ( NULL == pBuffHeader ) {
218c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        CAMHAL_LOGEA("Invalid Buffer header");
219c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        return-EINVAL;
220c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
221c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
222f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ( mFaceDetectionRunning && !mFaceDetectionPaused ) {
223f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        OMX_OTHER_EXTRADATATYPE *extraData;
224f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
225f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        extraData = getExtradata(pBuffHeader->pPlatformPrivate,
226f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                                 (OMX_EXTRADATATYPE)OMX_FaceDetection);
227f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
228f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( NULL != extraData ) {
229f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x",
230f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                         extraData->nSize,
231f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                         sizeof(OMX_OTHER_EXTRADATATYPE),
232f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                         extraData->eType,
233f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                         extraData->nDataSize,
234f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                         extraData->nPortIndex,
235f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                         extraData->nVersion);
236c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        } else {
237f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            CAMHAL_LOGD("FD extra data not found!");
23882640237cf0ca200932a66777fd1907d66cd0322Akwasi Boateng            return -EINVAL;
239c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
240c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
241f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        faceData = ( OMX_FACEDETECTIONTYPE * ) extraData->data;
242f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( NULL != faceData ) {
243f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            if ( sizeof(OMX_FACEDETECTIONTYPE) == faceData->nSize ) {
244f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                CAMHAL_LOGVB("Faces detected %d",
245f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                             faceData->ulFaceCount,
246f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                             faceData->nSize,
247f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                             sizeof(OMX_FACEDETECTIONTYPE),
248f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                             faceData->eCameraView,
249f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                             faceData->nPortIndex,
250f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                             faceData->nVersion);
251f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            } else {
252f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                CAMHAL_LOGEB("OMX_FACEDETECTIONTYPE size mismatch: expected = %d, received = %d",
253f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                             ( unsigned int ) sizeof(OMX_FACEDETECTIONTYPE),
254f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                             ( unsigned int ) faceData->nSize);
255f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                return -EINVAL;
256f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            }
257f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        } else {
258f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE");
259f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            return -EINVAL;
260f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        }
261c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
262c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
263f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    result = new (std::nothrow) CameraMetadataResult;
264f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if(NULL == result.get()) {
265f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        ret = NO_MEMORY;
266f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        return ret;
267c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
268c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
269f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    //Encode face coordinates
270f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    faceRet = encodeFaceCoordinates(faceData, result->getMetadataResult()
271f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                                            , previewWidth, previewHeight);
272f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ((NO_ERROR == faceRet) || (NOT_ENOUGH_DATA == faceRet)) {
273f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // Ignore harmless errors (no error and no update) and go ahead and encode
274f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // the preview meta data
275f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        metaRet = encodePreviewMetadata(result->getMetadataResult()
276f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                                        , pBuffHeader->pPlatformPrivate);
277f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if ( (NO_ERROR != metaRet) && (NOT_ENOUGH_DATA != metaRet) )  {
278f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons           // Some 'real' error occurred during preview meta data encod, clear metadata
279f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons           // result and return correct error code
280f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons           result.clear();
281f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons           ret = metaRet;
282c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
283c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    } else {
284f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        //Some real error occurred during face encoding, clear metadata result
285f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        // and return correct error code
286f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        result.clear();
287f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        ret = faceRet;
288c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
289c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
290f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if((NOT_ENOUGH_DATA == faceRet) && (NOT_ENOUGH_DATA == metaRet)) {
291f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        //No point sending the callback if nothing is changed
292c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        result.clear();
293f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        ret = faceRet;
294c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
295c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
296c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME_EXIT;
297c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
298c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    return ret;
299c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
300c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
301c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchevstatus_t OMXCameraAdapter::encodeFaceCoordinates(const OMX_FACEDETECTIONTYPE *faceData,
302f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                                                 camera_frame_metadata_t *metadataResult,
303c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                                 size_t previewWidth,
304c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev                                                 size_t previewHeight)
305c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev{
306c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    status_t ret = NO_ERROR;
307c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    camera_face_t *faces;
308c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    size_t hRange, vRange;
309c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    double tmp;
310f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    bool faceArrayChanged = false;
311c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
312c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME;
313c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
314f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    hRange = CameraMetadataResult::RIGHT - CameraMetadataResult::LEFT;
315f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    vRange = CameraMetadataResult::BOTTOM - CameraMetadataResult::TOP;
316c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
317f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    android::AutoMutex lock(mFaceDetectionLock);
318c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
319f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // Avoid memory leak if called twice on same CameraMetadataResult
320f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ( (0 < metadataResult->number_of_faces) && (NULL != metadataResult->faces) ) {
321f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        free(metadataResult->faces);
322f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        metadataResult->number_of_faces = 0;
323f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        metadataResult->faces = NULL;
324c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
325c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
326f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ( (NULL != faceData) && (0 < faceData->ulFaceCount) ) {
327fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        int orient_mult;
328fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        int trans_left, trans_top, trans_right, trans_bot;
329c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
330c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        faces = ( camera_face_t * ) malloc(sizeof(camera_face_t)*faceData->ulFaceCount);
331c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        if ( NULL == faces ) {
332f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            ret = NO_MEMORY;
333f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            goto out;
334c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev        }
335c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
336fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        /**
337fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * When device is 180 degrees oriented to the sensor, need to translate
338fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * the output from Ducati to what Android expects
339fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * Ducati always gives face coordinates in this form, irrespective of
340fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * rotation, i.e (l,t) always represents the point towards the left eye
341fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * and top of hair.
342fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * (l, t)
343fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   ---------------
344fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -   ,,,,,,,   -
345fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |       |  -
346fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |<a   <a|  -
347fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   - (|   ^   |) -
348fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |  -=-  |  -
349fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -   \_____/   -
350fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   ---------------
351fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *               (r, b)
352fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *
353fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * However, Android expects the coords to be in respect with what the
354fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * sensor is viewing, i.e Android expects sensor to see this with (l,t)
355fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * and (r,b) like so:
356fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / * (l, t)
357fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   ---------------
358fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -    _____    -
359fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -   /     \   -
360fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |  -=-  |  -
361fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   - (|   ^   |) -
362fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |a>   a>|  -
363fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -  |       |  -
364fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   -   ,,,,,,,   -
365fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *   ---------------
366fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu        / *               (r, b)
367fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu          */
368c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
369f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        if (mFaceOrientation == 180) {
3707762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            orient_mult = -1;
3717762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_left = 2; // right is now left
3727762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_top = 3; // bottom is now top
3737762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_right = 0; // left is now right
3747762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_bot = 1; // top is not bottom
3757762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        } else {
3767762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            orient_mult = 1;
3777762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_left = 0; // left
3787762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_top = 1; // top
3797762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_right = 2; // right
3807762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            trans_bot = 3; // bottom
3817762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        }
3827762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
383967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman        int j = 0, i = 0;
384967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman        for ( ; j < faceData->ulFaceCount ; j++)
385967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            {
38652d3388c121469e22bf41d7362640257d8268858Tyler Luu             OMX_S32 nLeft = 0;
387e45763a2a361324f1771a6991525e631365ca954Tyler Luu             OMX_S32 nTop = 0;
388967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //Face filtering
389967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //For real faces, it is seen that the h/w passes a score >=80
390967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //For false faces, we seem to get even a score of 70 sometimes.
391967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //In order to avoid any issue at application level, we filter
392967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             //<=70 score here.
393967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            if(faceData->tFacePosition[j].nScore <= FACE_DETECTION_THRESHOLD)
394967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman             continue;
395967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman
396f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            if (mFaceOrientation == 180) {
39752d3388c121469e22bf41d7362640257d8268858Tyler Luu                // from sensor pov, the left pos is the right corner of the face in pov of frame
3987762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                nLeft = faceData->tFacePosition[j].nLeft + faceData->tFacePosition[j].nWidth;
399e45763a2a361324f1771a6991525e631365ca954Tyler Luu                nTop =  faceData->tFacePosition[j].nTop + faceData->tFacePosition[j].nHeight;
40052d3388c121469e22bf41d7362640257d8268858Tyler Luu            } else {
4017762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                nLeft = faceData->tFacePosition[j].nLeft;
402e45763a2a361324f1771a6991525e631365ca954Tyler Luu                nTop =  faceData->tFacePosition[j].nTop;
40352d3388c121469e22bf41d7362640257d8268858Tyler Luu            }
40452d3388c121469e22bf41d7362640257d8268858Tyler Luu
40552d3388c121469e22bf41d7362640257d8268858Tyler Luu            tmp = ( double ) nLeft / ( double ) previewWidth;
406c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp *= hRange;
407c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp -= hRange/2;
408fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            faces[i].rect[trans_left] = tmp;
409c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
410e45763a2a361324f1771a6991525e631365ca954Tyler Luu            tmp = ( double ) nTop / ( double )previewHeight;
411c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp *= vRange;
412c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp -= vRange/2;
413fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            faces[i].rect[trans_top] = tmp;
414c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
415967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            tmp = ( double ) faceData->tFacePosition[j].nWidth / ( double ) previewWidth;
416c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp *= hRange;
417fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            tmp *= orient_mult;
418fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            faces[i].rect[trans_right] = faces[i].rect[trans_left] + tmp;
419c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
420967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            tmp = ( double ) faceData->tFacePosition[j].nHeight / ( double ) previewHeight;
421c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            tmp *= vRange;
422fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            tmp *= orient_mult;
423fa28dae0efd774ddd8919e99c0add3e69300ea3aTyler Luu            faces[i].rect[trans_bot] = faces[i].rect[trans_top] + tmp;
424c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
425967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            faces[i].score = faceData->tFacePosition[j].nScore;
426c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            faces[i].id = 0;
427f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            faces[i].left_eye[0] = CameraMetadataResult::INVALID_DATA;
428f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            faces[i].left_eye[1] = CameraMetadataResult::INVALID_DATA;
429f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            faces[i].right_eye[0] = CameraMetadataResult::INVALID_DATA;
430f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            faces[i].right_eye[1] = CameraMetadataResult::INVALID_DATA;
431f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            faces[i].mouth[0] = CameraMetadataResult::INVALID_DATA;
432f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            faces[i].mouth[1] = CameraMetadataResult::INVALID_DATA;
433967f1197f015b6d2f3b34e60fa787f7066efb824Sundar Raman            i++;
434c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev            }
435c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
436f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        metadataResult->number_of_faces = i;
437f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        metadataResult->faces = faces;
438c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
439f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        for (int i = 0; i  < metadataResult->number_of_faces; i++)
4407762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        {
441f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            bool faceChanged = true;
4427762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            int centerX = (faces[i].rect[trans_left] + faces[i].rect[trans_right] ) / 2;
4437762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            int centerY = (faces[i].rect[trans_top] + faces[i].rect[trans_bot] ) / 2;
4447762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
4457762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            int sizeX = (faces[i].rect[trans_right] - faces[i].rect[trans_left] ) ;
4467762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            int sizeY = (faces[i].rect[trans_bot] - faces[i].rect[trans_top] ) ;
4477762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
4487762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            for (int j = 0; j < faceDetectionNumFacesLastOutput; j++)
4497762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            {
4507762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                int tempCenterX = (faceDetectionLastOutput[j].rect[trans_left] +
4517762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                                  faceDetectionLastOutput[j].rect[trans_right] ) / 2;
4527762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                int tempCenterY = (faceDetectionLastOutput[j].rect[trans_top] +
4537762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                                  faceDetectionLastOutput[j].rect[trans_bot] ) / 2;
4547762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                int tempSizeX = (faceDetectionLastOutput[j].rect[trans_right] -
4557762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                                faceDetectionLastOutput[j].rect[trans_left] ) ;
4567762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                int tempSizeY = (faceDetectionLastOutput[j].rect[trans_bot] -
4577762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                                faceDetectionLastOutput[j].rect[trans_top] ) ;
4587762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
459f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                if ( ( tempCenterX == centerX) &&
460f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                     ( tempCenterY == centerY) ) {
461f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                    // Found Face.
462f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                    // Now check size of rectangle
463f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                    // compare to last output.
464f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                    if ( ( tempSizeX == sizeX ) &&
465f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                         ( tempSizeY == sizeY ) ) {
466f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                        faceChanged = false;
4677762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                    }
4687762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu                }
4697762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            }
470f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            // Send face detection data after some face coordinate changes
471f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            if (faceChanged) {
472f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons                faceArrayChanged = true;
473f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons            }
4747762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        }
4757762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu
4767762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        // Save this output for next iteration
477f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        for (int i = 0; i  < metadataResult->number_of_faces; i++)
4787762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        {
4797762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu            faceDetectionLastOutput[i] = faces[i];
4807762bf32b7bd874ce34948eb53a3bfa3906f4aefTyler Luu        }
481c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    } else {
482f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        metadataResult->number_of_faces = 0;
483f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        metadataResult->faces = NULL;
484c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    }
485c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
486f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    // Send face detection data after face count changes
487f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if (faceDetectionNumFacesLastOutput != metadataResult->number_of_faces) {
488f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        faceArrayChanged = true;
489f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    }
490f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    faceDetectionNumFacesLastOutput = metadataResult->number_of_faces;
491f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
492f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    if ( !faceArrayChanged ) {
493f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons        ret = NOT_ENOUGH_DATA;
494f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons    }
495c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
496c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    LOG_FUNCTION_NAME_EXIT;
497c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
498f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmonsout:
499f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons
500c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev    return ret;
501c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev}
502c322989ae6ff6769490828de1b5eda12b749cce9Iliyan Malchev
503f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons} // namespace Camera
504f7a4d11e9f710e2cd0592310ac1baecccb85f1d1Jason Simmons} // namespace Ti
505