Home | History | Annotate | Download | only in OMXCameraAdapter
      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 * @file OMXFD.cpp
     19 *
     20 * This file contains functionality for handling face detection.
     21 *
     22 */
     23 
     24 #undef LOG_TAG
     25 
     26 #define LOG_TAG "CameraHAL"
     27 
     28 #include "CameraHal.h"
     29 #include "OMXCameraAdapter.h"
     30 
     31 #define FACE_DETECTION_THRESHOLD 80
     32 
     33 // constants used for face smooth filtering
     34 static const int HorizontalFilterThreshold = 40;
     35 static const int VerticalFilterThreshold = 40;
     36 static const int HorizontalFaceSizeThreshold = 30;
     37 static const int VerticalFaceSizeThreshold = 30;
     38 
     39 
     40 namespace android {
     41 
     42 status_t OMXCameraAdapter::setParametersFD(const CameraParameters &params,
     43                                            BaseCameraAdapter::AdapterState state)
     44 {
     45     status_t ret = NO_ERROR;
     46 
     47     LOG_FUNCTION_NAME;
     48 
     49     LOG_FUNCTION_NAME_EXIT;
     50 
     51     return ret;
     52 }
     53 
     54 status_t OMXCameraAdapter::startFaceDetection()
     55 {
     56     status_t ret = NO_ERROR;
     57 
     58     Mutex::Autolock lock(mFaceDetectionLock);
     59 
     60     ret = setFaceDetection(true, mDeviceOrientation);
     61     if (ret != NO_ERROR) {
     62         goto out;
     63     }
     64 
     65     if ( mFaceDetectionRunning ) {
     66         mFDSwitchAlgoPriority = true;
     67     }
     68 
     69     // Note: White balance will not be face prioritized, since
     70     // the algorithm needs full frame statistics, and not face
     71     // regions alone.
     72 
     73     faceDetectionNumFacesLastOutput = 0;
     74  out:
     75     return ret;
     76 }
     77 
     78 status_t OMXCameraAdapter::stopFaceDetection()
     79 {
     80     status_t ret = NO_ERROR;
     81     const char *str = NULL;
     82     BaseCameraAdapter::AdapterState state;
     83     BaseCameraAdapter::getState(state);
     84 
     85     Mutex::Autolock lock(mFaceDetectionLock);
     86 
     87     ret = setFaceDetection(false, mDeviceOrientation);
     88     if (ret != NO_ERROR) {
     89         goto out;
     90     }
     91 
     92     // Reset 3A settings
     93     ret = setParameters3A(mParams, state);
     94     if (ret != NO_ERROR) {
     95         goto out;
     96     }
     97 
     98     if (mPending3Asettings) {
     99         apply3Asettings(mParameters3A);
    100     }
    101 
    102     faceDetectionNumFacesLastOutput = 0;
    103  out:
    104     return ret;
    105 }
    106 
    107 void OMXCameraAdapter::pauseFaceDetection(bool pause)
    108 {
    109     Mutex::Autolock lock(mFaceDetectionLock);
    110     // pausing will only take affect if fd is already running
    111     if (mFaceDetectionRunning) {
    112         mFaceDetectionPaused = pause;
    113         faceDetectionNumFacesLastOutput = 0;
    114     }
    115 }
    116 
    117 status_t OMXCameraAdapter::setFaceDetection(bool enable, OMX_U32 orientation)
    118 {
    119     status_t ret = NO_ERROR;
    120     OMX_ERRORTYPE eError = OMX_ErrorNone;
    121     OMX_CONFIG_OBJDETECTIONTYPE objDetection;
    122 
    123     LOG_FUNCTION_NAME;
    124 
    125     if ( OMX_StateInvalid == mComponentState )
    126         {
    127         CAMHAL_LOGEA("OMX component is in invalid state");
    128         ret = -EINVAL;
    129         }
    130 
    131     if ( NO_ERROR == ret )
    132         {
    133         if ( orientation > 270 ) {
    134             orientation = 0;
    135         }
    136 
    137         OMX_INIT_STRUCT_PTR (&objDetection, OMX_CONFIG_OBJDETECTIONTYPE);
    138         objDetection.nPortIndex = mCameraAdapterParameters.mPrevPortIndex;
    139         objDetection.nDeviceOrientation = orientation;
    140         if  ( enable )
    141             {
    142             objDetection.bEnable = OMX_TRUE;
    143             }
    144         else
    145             {
    146             objDetection.bEnable = OMX_FALSE;
    147             }
    148 
    149         eError =  OMX_SetConfig(mCameraAdapterParameters.mHandleComp,
    150                                 ( OMX_INDEXTYPE ) OMX_IndexConfigImageFaceDetection,
    151                                 &objDetection);
    152         if ( OMX_ErrorNone != eError )
    153             {
    154             CAMHAL_LOGEB("Error while configuring face detection 0x%x", eError);
    155             ret = -1;
    156             }
    157         else
    158             {
    159             CAMHAL_LOGDA("Face detection configured successfully");
    160             }
    161         }
    162 
    163     if ( NO_ERROR == ret )
    164         {
    165         ret = setExtraData(enable, mCameraAdapterParameters.mPrevPortIndex, OMX_FaceDetection);
    166 
    167         if ( NO_ERROR != ret )
    168             {
    169             CAMHAL_LOGEA("Error while configuring face detection extra data");
    170             }
    171         else
    172             {
    173             CAMHAL_LOGDA("Face detection extra data configured successfully");
    174             }
    175         }
    176 
    177     if ( NO_ERROR == ret )
    178         {
    179         mFaceDetectionRunning = enable;
    180         mFaceDetectionPaused = !enable;
    181         }
    182 
    183     LOG_FUNCTION_NAME_EXIT;
    184 
    185     return ret;
    186 }
    187 
    188 status_t OMXCameraAdapter::detectFaces(OMX_BUFFERHEADERTYPE* pBuffHeader,
    189                                        sp<CameraFDResult> &result,
    190                                        size_t previewWidth,
    191                                        size_t previewHeight)
    192 {
    193     status_t ret = NO_ERROR;
    194     OMX_ERRORTYPE eError = OMX_ErrorNone;
    195     OMX_TI_FACERESULT *faceResult;
    196     OMX_OTHER_EXTRADATATYPE *extraData;
    197     OMX_FACEDETECTIONTYPE *faceData;
    198     OMX_TI_PLATFORMPRIVATE *platformPrivate;
    199     camera_frame_metadata_t *faces;
    200 
    201     LOG_FUNCTION_NAME;
    202 
    203     if ( OMX_StateExecuting != mComponentState ) {
    204         CAMHAL_LOGEA("OMX component is not in executing state");
    205         return NO_INIT;
    206     }
    207 
    208     if ( NULL == pBuffHeader ) {
    209         CAMHAL_LOGEA("Invalid Buffer header");
    210         return-EINVAL;
    211     }
    212 
    213     platformPrivate = (OMX_TI_PLATFORMPRIVATE *) (pBuffHeader->pPlatformPrivate);
    214     if ( NULL != platformPrivate ) {
    215         if ( sizeof(OMX_TI_PLATFORMPRIVATE) == platformPrivate->nSize ) {
    216             CAMHAL_LOGVB("Size = %d, sizeof = %d, pAuxBuf = 0x%x, pAuxBufSize= %d, pMetaDataBufer = 0x%x, nMetaDataSize = %d",
    217                          platformPrivate->nSize,
    218                          sizeof(OMX_TI_PLATFORMPRIVATE),
    219                          platformPrivate->pAuxBuf1,
    220                          platformPrivate->pAuxBufSize1,
    221                          platformPrivate->pMetaDataBuffer,
    222                          platformPrivate->nMetaDataSize);
    223         } else {
    224             CAMHAL_LOGDB("OMX_TI_PLATFORMPRIVATE size mismatch: expected = %d, received = %d",
    225                          ( unsigned int ) sizeof(OMX_TI_PLATFORMPRIVATE),
    226                          ( unsigned int ) platformPrivate->nSize);
    227             return -EINVAL;
    228         }
    229     }  else {
    230         CAMHAL_LOGDA("Invalid OMX_TI_PLATFORMPRIVATE");
    231         return-EINVAL;
    232     }
    233 
    234 
    235     if ( 0 >= platformPrivate->nMetaDataSize ) {
    236         CAMHAL_LOGDB("OMX_TI_PLATFORMPRIVATE nMetaDataSize is size is %d",
    237                      ( unsigned int ) platformPrivate->nMetaDataSize);
    238         return -EINVAL;
    239     }
    240 
    241     extraData = getExtradata((OMX_OTHER_EXTRADATATYPE *) (platformPrivate->pMetaDataBuffer),
    242             (OMX_EXTRADATATYPE)OMX_FaceDetection);
    243 
    244     if ( NULL != extraData ) {
    245         CAMHAL_LOGVB("Size = %d, sizeof = %d, eType = 0x%x, nDataSize= %d, nPortIndex = 0x%x, nVersion = 0x%x",
    246                      extraData->nSize,
    247                      sizeof(OMX_OTHER_EXTRADATATYPE),
    248                      extraData->eType,
    249                      extraData->nDataSize,
    250                      extraData->nPortIndex,
    251                      extraData->nVersion);
    252     } else {
    253         CAMHAL_LOGDA("Invalid OMX_OTHER_EXTRADATATYPE");
    254         return -EINVAL;
    255     }
    256 
    257     faceData = ( OMX_FACEDETECTIONTYPE * ) extraData->data;
    258     if ( NULL != faceData ) {
    259         if ( sizeof(OMX_FACEDETECTIONTYPE) == faceData->nSize ) {
    260             CAMHAL_LOGVB("Faces detected %d",
    261                          faceData->ulFaceCount,
    262                          faceData->nSize,
    263                          sizeof(OMX_FACEDETECTIONTYPE),
    264                          faceData->eCameraView,
    265                          faceData->nPortIndex,
    266                          faceData->nVersion);
    267         } else {
    268             CAMHAL_LOGDB("OMX_FACEDETECTIONTYPE size mismatch: expected = %d, received = %d",
    269                          ( unsigned int ) sizeof(OMX_FACEDETECTIONTYPE),
    270                          ( unsigned int ) faceData->nSize);
    271             return -EINVAL;
    272         }
    273     } else {
    274         CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE");
    275         return -EINVAL;
    276     }
    277 
    278     ret = encodeFaceCoordinates(faceData, &faces, previewWidth, previewHeight);
    279 
    280     if ( NO_ERROR == ret ) {
    281         result = new CameraFDResult(faces);
    282     } else {
    283         result.clear();
    284         result = NULL;
    285     }
    286 
    287     LOG_FUNCTION_NAME_EXIT;
    288 
    289     return ret;
    290 }
    291 
    292 status_t OMXCameraAdapter::encodeFaceCoordinates(const OMX_FACEDETECTIONTYPE *faceData,
    293                                                  camera_frame_metadata_t **pFaces,
    294                                                  size_t previewWidth,
    295                                                  size_t previewHeight)
    296 {
    297     status_t ret = NO_ERROR;
    298     camera_face_t *faces;
    299     camera_frame_metadata_t *faceResult;
    300     size_t hRange, vRange;
    301     double tmp;
    302 
    303     LOG_FUNCTION_NAME;
    304 
    305     if ( NULL == faceData ) {
    306         CAMHAL_LOGEA("Invalid OMX_FACEDETECTIONTYPE parameter");
    307         return EINVAL;
    308     }
    309 
    310     LOG_FUNCTION_NAME
    311 
    312     hRange = CameraFDResult::RIGHT - CameraFDResult::LEFT;
    313     vRange = CameraFDResult::BOTTOM - CameraFDResult::TOP;
    314 
    315     faceResult = ( camera_frame_metadata_t * ) malloc(sizeof(camera_frame_metadata_t));
    316     if ( NULL == faceResult ) {
    317         return -ENOMEM;
    318     }
    319 
    320     if ( 0 < faceData->ulFaceCount ) {
    321         int orient_mult;
    322         int trans_left, trans_top, trans_right, trans_bot;
    323 
    324         faces = ( camera_face_t * ) malloc(sizeof(camera_face_t)*faceData->ulFaceCount);
    325         if ( NULL == faces ) {
    326             return -ENOMEM;
    327         }
    328 
    329         /**
    330         / * When device is 180 degrees oriented to the sensor, need to translate
    331         / * the output from Ducati to what Android expects
    332         / * Ducati always gives face coordinates in this form, irrespective of
    333         / * rotation, i.e (l,t) always represents the point towards the left eye
    334         / * and top of hair.
    335         / * (l, t)
    336         / *   ---------------
    337         / *   -   ,,,,,,,   -
    338         / *   -  |       |  -
    339         / *   -  |<a   <a|  -
    340         / *   - (|   ^   |) -
    341         / *   -  |  -=-  |  -
    342         / *   -   \_____/   -
    343         / *   ---------------
    344         / *               (r, b)
    345         / *
    346         / * However, Android expects the coords to be in respect with what the
    347         / * sensor is viewing, i.e Android expects sensor to see this with (l,t)
    348         / * and (r,b) like so:
    349         / * (l, t)
    350         / *   ---------------
    351         / *   -    _____    -
    352         / *   -   /     \   -
    353         / *   -  |  -=-  |  -
    354         / *   - (|   ^   |) -
    355         / *   -  |a>   a>|  -
    356         / *   -  |       |  -
    357         / *   -   ,,,,,,,   -
    358         / *   ---------------
    359         / *               (r, b)
    360           */
    361 
    362         if (mDeviceOrientation == 180) {
    363             orient_mult = -1;
    364             trans_left = 2; // right is now left
    365             trans_top = 3; // bottom is now top
    366             trans_right = 0; // left is now right
    367             trans_bot = 1; // top is not bottom
    368         } else {
    369             orient_mult = 1;
    370             trans_left = 0; // left
    371             trans_top = 1; // top
    372             trans_right = 2; // right
    373             trans_bot = 3; // bottom
    374         }
    375 
    376         int j = 0, i = 0;
    377         for ( ; j < faceData->ulFaceCount ; j++)
    378             {
    379              OMX_S32 nLeft = 0;
    380              OMX_S32 nTop = 0;
    381              //Face filtering
    382              //For real faces, it is seen that the h/w passes a score >=80
    383              //For false faces, we seem to get even a score of 70 sometimes.
    384              //In order to avoid any issue at application level, we filter
    385              //<=70 score here.
    386             if(faceData->tFacePosition[j].nScore <= FACE_DETECTION_THRESHOLD)
    387              continue;
    388 
    389             if (mDeviceOrientation == 180) {
    390                 // from sensor pov, the left pos is the right corner of the face in pov of frame
    391                 nLeft = faceData->tFacePosition[j].nLeft + faceData->tFacePosition[j].nWidth;
    392                 nTop =  faceData->tFacePosition[j].nTop + faceData->tFacePosition[j].nHeight;
    393             } else {
    394                 nLeft = faceData->tFacePosition[j].nLeft;
    395                 nTop =  faceData->tFacePosition[j].nTop;
    396             }
    397 
    398             tmp = ( double ) nLeft / ( double ) previewWidth;
    399             tmp *= hRange;
    400             tmp -= hRange/2;
    401             faces[i].rect[trans_left] = tmp;
    402 
    403             tmp = ( double ) nTop / ( double )previewHeight;
    404             tmp *= vRange;
    405             tmp -= vRange/2;
    406             faces[i].rect[trans_top] = tmp;
    407 
    408             tmp = ( double ) faceData->tFacePosition[j].nWidth / ( double ) previewWidth;
    409             tmp *= hRange;
    410             tmp *= orient_mult;
    411             faces[i].rect[trans_right] = faces[i].rect[trans_left] + tmp;
    412 
    413             tmp = ( double ) faceData->tFacePosition[j].nHeight / ( double ) previewHeight;
    414             tmp *= vRange;
    415             tmp *= orient_mult;
    416             faces[i].rect[trans_bot] = faces[i].rect[trans_top] + tmp;
    417 
    418             faces[i].score = faceData->tFacePosition[j].nScore;
    419             faces[i].id = 0;
    420             faces[i].left_eye[0] = CameraFDResult::INVALID_DATA;
    421             faces[i].left_eye[1] = CameraFDResult::INVALID_DATA;
    422             faces[i].right_eye[0] = CameraFDResult::INVALID_DATA;
    423             faces[i].right_eye[1] = CameraFDResult::INVALID_DATA;
    424             faces[i].mouth[0] = CameraFDResult::INVALID_DATA;
    425             faces[i].mouth[1] = CameraFDResult::INVALID_DATA;
    426             i++;
    427             }
    428 
    429         faceResult->number_of_faces = i;
    430         faceResult->faces = faces;
    431 
    432         for (int i = 0; i  < faceResult->number_of_faces; i++)
    433         {
    434             int centerX = (faces[i].rect[trans_left] + faces[i].rect[trans_right] ) / 2;
    435             int centerY = (faces[i].rect[trans_top] + faces[i].rect[trans_bot] ) / 2;
    436 
    437             int sizeX = (faces[i].rect[trans_right] - faces[i].rect[trans_left] ) ;
    438             int sizeY = (faces[i].rect[trans_bot] - faces[i].rect[trans_top] ) ;
    439 
    440             for (int j = 0; j < faceDetectionNumFacesLastOutput; j++)
    441             {
    442                 int tempCenterX = (faceDetectionLastOutput[j].rect[trans_left] +
    443                                   faceDetectionLastOutput[j].rect[trans_right] ) / 2;
    444                 int tempCenterY = (faceDetectionLastOutput[j].rect[trans_top] +
    445                                   faceDetectionLastOutput[j].rect[trans_bot] ) / 2;
    446                 int tempSizeX = (faceDetectionLastOutput[j].rect[trans_right] -
    447                                 faceDetectionLastOutput[j].rect[trans_left] ) ;
    448                 int tempSizeY = (faceDetectionLastOutput[j].rect[trans_bot] -
    449                                 faceDetectionLastOutput[j].rect[trans_top] ) ;
    450 
    451                 if ( (abs(tempCenterX - centerX) < HorizontalFilterThreshold) &&
    452                      (abs(tempCenterY - centerY) < VerticalFilterThreshold) )
    453                 {
    454                     // Found Face. It did not move too far.
    455                     // Now check size of rectangle compare to last output
    456                     if ( (abs (tempSizeX -sizeX) < HorizontalFaceSizeThreshold) &&
    457                          (abs (tempSizeY -sizeY) < VerticalFaceSizeThreshold) )
    458                     {
    459                         // Rectangle is almost same as last time
    460                         // Output exactly what was done for this face last time.
    461                         faces[i] = faceDetectionLastOutput[j];
    462                     }
    463                     else
    464                     {
    465                         // TODO(XXX): Rectangle size changed but position is same.
    466                         // Possibly we can apply just positional correctness.
    467                     }
    468                 }
    469             }
    470         }
    471 
    472         // Save this output for next iteration
    473         for (int i = 0; i  < faceResult->number_of_faces; i++)
    474         {
    475             faceDetectionLastOutput[i] = faces[i];
    476         }
    477         faceDetectionNumFacesLastOutput = faceResult->number_of_faces;
    478     } else {
    479         faceResult->number_of_faces = 0;
    480         faceResult->faces = NULL;
    481     }
    482 
    483     *pFaces = faceResult;
    484 
    485     LOG_FUNCTION_NAME_EXIT;
    486 
    487     return ret;
    488 }
    489 
    490 };
    491