17f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project/*
27f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
37f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project *
47f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
57f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * you may not use this file except in compliance with the License.
67f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * You may obtain a copy of the License at
77f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project *
87f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
97f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project *
107f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
117f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
127f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * See the License for the specific language governing permissions and
147f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project * limitations under the License.
157f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project */
167f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1785ecdac13cf9290e23eae013cd8551ff15d88387Narayan Kamath#include <assert.h>
187f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include <stdlib.h>
197f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include <stdio.h>
207f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include <fcntl.h>
217f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include <unistd.h>
227f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
237f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include <utils/misc.h>
247f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include <utils/String8.h>
257f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include <utils/Log.h>
267f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
27a56610962abd49b99e04ca148d60f9dd28951fd9Derek Sollenberger#include <SkBitmap.h>
287f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
297f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include "jni.h"
307f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project#include "JNIHelp.h"
317f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
327f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectusing namespace android;
337f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
347f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectextern "C"
357f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
367f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    #include <fd_emb_sdk.h>
377f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
387f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
397f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstruct FaceData
407f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
417f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    float confidence;
427f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    float midpointx;
437f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    float midpointy;
447f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    float eyedist;
457f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project};
467f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
477f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstruct FaceOffsets
487f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
497f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    confidence;
507f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    midpointx;
517f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    midpointy;
527f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    eyedist;
537f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    eulerx;
547f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    eulery;
557f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    eulerz;
567f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project} gFaceOffsets;
577f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
587f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstruct FaceDetectorOffsets
597f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
607f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    fd;
617f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    sdk;
627f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    dcr;
637f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    width;
647f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    height;
657f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    maxFaces;
667f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jfieldID    bwbuffer;
677f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project} gFaceDetectorOffsets;
687f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
697f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source ProjectjfieldID nativeBitmapID;
707f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
717f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project// ---------------------------------------------------------------------------
727f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
737f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic void getFaceData(btk_HDCR hdcr, FaceData* fdata)
747f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
757f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_Node leftEye, rightEye;
767f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
777f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_DCR_getNode(hdcr, 0, &leftEye);
787f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_DCR_getNode(hdcr, 1, &rightEye);
797f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
807f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    fdata->eyedist = (float)(rightEye.x - leftEye.x) / (1 << 16);
817f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    fdata->midpointx = (float)(rightEye.x + leftEye.x) / (1 << 17);
827f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    fdata->midpointy = (float)(rightEye.y + leftEye.y) / (1 << 17);
837f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    fdata->confidence = (float)btk_DCR_confidence(hdcr) / (1 << 24);
847f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
857f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
867f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project// ---------------------------------------------------------------------------
877f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
887f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
897f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
907f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jclass npeClazz = env->FindClass(exc);
917f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    env->ThrowNew(npeClazz, msg);
927f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
937f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
947f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic void
957f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source ProjectnativeClassInit
967f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project(JNIEnv *_env, jclass _this)
977f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
98677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    gFaceDetectorOffsets.fd             = _env->GetFieldID(_this, "mFD", "J");
99677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    gFaceDetectorOffsets.sdk            = _env->GetFieldID(_this, "mSDK", "J");
100677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    gFaceDetectorOffsets.dcr            = _env->GetFieldID(_this, "mDCR", "J");
1017f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceDetectorOffsets.width          = _env->GetFieldID(_this, "mWidth", "I");
1027f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceDetectorOffsets.height         = _env->GetFieldID(_this, "mHeight", "I");
1037f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceDetectorOffsets.maxFaces       = _env->GetFieldID(_this, "mMaxFaces", "I");
1047f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceDetectorOffsets.bwbuffer       = _env->GetFieldID(_this, "mBWBuffer", "[B");
1057f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1067f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jclass faceClass = _env->FindClass("android/media/FaceDetector$Face");
1077f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceOffsets.confidence  = _env->GetFieldID(faceClass, "mConfidence", "F");
1087f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceOffsets.midpointx   = _env->GetFieldID(faceClass, "mMidPointX", "F");
1097f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceOffsets.midpointy   = _env->GetFieldID(faceClass, "mMidPointY", "F");
1107f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceOffsets.eyedist     = _env->GetFieldID(faceClass, "mEyesDist", "F");
1117f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceOffsets.eulerx      = _env->GetFieldID(faceClass, "mPoseEulerX", "F");
1127f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceOffsets.eulery      = _env->GetFieldID(faceClass, "mPoseEulerY", "F");
1137f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    gFaceOffsets.eulerz      = _env->GetFieldID(faceClass, "mPoseEulerZ", "F");
1147f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1157f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jclass bitmapClass = _env->FindClass("android/graphics/Bitmap");
116677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    nativeBitmapID = _env->GetFieldID(bitmapClass, "mNativeBitmap", "J");
1177f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
1187f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1197f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project// ---------------------------------------------------------------------------
1207f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1217f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic jint
1227f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectinitialize(JNIEnv *_env, jobject _this,
1237f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project     jint w, jint h, jint maxFaces)
1247f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
1257f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // load the configuration file
1267f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    const char* root = getenv("ANDROID_ROOT");
1277f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    String8 path(root);
1287f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    path.appendPath("usr/share/bmd/RFFstd_501.bmd");
1297f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // path.appendPath("usr/share/bmd/RFFspeed_501.bmd");
1307f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1317f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    const int MAX_FILE_SIZE = 65536;
1327f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    void* initData = malloc( MAX_FILE_SIZE ); /* enough to fit entire file */
1337f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    int filedesc = open(path.string(), O_RDONLY);
1347f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    int initDataSize = read(filedesc, initData, MAX_FILE_SIZE);
1357f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    close(filedesc);
1367f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1377f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // --------------------------------------------------------------------
1387f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_HSDK sdk = NULL;
1397f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_SDKCreateParam sdkParam = btk_SDK_defaultParam();
1407f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    sdkParam.fpMalloc = malloc;
1417f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    sdkParam.fpFree = free;
1427f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    sdkParam.maxImageWidth = w;
1437f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    sdkParam.maxImageHeight = h;
1447f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1457f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_Status status = btk_SDK_create(&sdkParam, &sdk);
1467f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // make sure everything went well
1477f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    if (status != btk_STATUS_OK) {
1487f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        // XXX: be more precise about what went wrong
1497f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        doThrow(_env, "java/lang/OutOfMemoryError", NULL);
1507f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        return 0;
1517f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    }
1527f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1537f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_HDCR dcr = NULL;
1547f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_DCRCreateParam dcrParam = btk_DCR_defaultParam();
1557f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_DCR_create( sdk, &dcrParam, &dcr );
1567f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1577f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_HFaceFinder fd = NULL;
1587f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_FaceFinderCreateParam fdParam = btk_FaceFinder_defaultParam();
1597f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    fdParam.pModuleParam = initData;
1607f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    fdParam.moduleParamSize = initDataSize;
1617f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    fdParam.maxDetectableFaces = maxFaces;
1627f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    status = btk_FaceFinder_create( sdk, &fdParam, &fd );
1637f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_FaceFinder_setRange(fd, 20, w/2); /* set eye distance range */
1647f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1657f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // make sure everything went well
1667f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    if (status != btk_STATUS_OK) {
1677f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        // XXX: be more precise about what went wrong
1687f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        doThrow(_env, "java/lang/OutOfMemoryError", NULL);
1697f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        return 0;
1707f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    }
1717f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1727f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // free the configuration file
1737f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    free(initData);
1747f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1757f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // initialize the java object
176677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    _env->SetLongField(_this, gFaceDetectorOffsets.fd,  (jlong)fd);
177677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    _env->SetLongField(_this, gFaceDetectorOffsets.sdk, (jlong)sdk);
178677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    _env->SetLongField(_this, gFaceDetectorOffsets.dcr, (jlong)dcr);
1797f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1807f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    return 1;
1817f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
1827f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1837f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic void
1847f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectdestroy(JNIEnv *_env, jobject _this)
1857f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
1867f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_HFaceFinder hfd =
187677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland        (btk_HFaceFinder)(_env->GetLongField(_this, gFaceDetectorOffsets.fd));
1887f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_FaceFinder_close( hfd );
1897f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
190677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    btk_HDCR hdcr = (btk_HDCR)(_env->GetLongField(_this, gFaceDetectorOffsets.dcr));
1917f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_DCR_close( hdcr );
1927f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
193677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    btk_HSDK hsdk = (btk_HSDK)(_env->GetLongField(_this, gFaceDetectorOffsets.sdk));
1947f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_SDK_close( hsdk );
1957f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
1967f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
1977f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic jint
1987f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectdetect(JNIEnv *_env, jobject _this,
1997f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project     jobject bitmap)
2007f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
2017f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // get the fields we need
202677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    btk_HDCR hdcr = (btk_HDCR)(_env->GetLongField(_this, gFaceDetectorOffsets.dcr));
2037f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_HFaceFinder hfd =
204677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland        (btk_HFaceFinder)(_env->GetLongField(_this, gFaceDetectorOffsets.fd));
2057f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    u32 maxFaces = _env->GetIntField(_this, gFaceDetectorOffsets.maxFaces);
2067f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    u32 width = _env->GetIntField(_this, gFaceDetectorOffsets.width);
2077f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    u32 height = _env->GetIntField(_this, gFaceDetectorOffsets.height);
2087f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2097f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jbyteArray bwbufferObject = (jbyteArray)
2107f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project            _env->GetObjectField(_this, gFaceDetectorOffsets.bwbuffer);
2117f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2127f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // get to the native bitmap
2137f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    SkBitmap const * nativeBitmap =
214677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland            (SkBitmap const *)_env->GetLongField(bitmap, nativeBitmapID);
2157f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2167f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // get to our BW temporary buffer
2177f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jbyte* bwbuffer = _env->GetByteArrayElements(bwbufferObject, 0);
2187f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2197f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // convert the image to B/W
2207f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    uint8_t* dst = (uint8_t*)bwbuffer;
2217f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2227f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // manage the life-time of locking our pixels
2237f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    SkAutoLockPixels alp(*nativeBitmap);
2247f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2257f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    uint16_t const* src = (uint16_t const*)nativeBitmap->getPixels();
2267f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    int wpr = nativeBitmap->rowBytes() / 2;
2277f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    for (u32 y=0 ; y<height; y++) {
2287f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        for (u32 x=0 ; x<width ; x++) {
2297f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project            uint16_t rgb = src[x];
2307f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project            int r  = rgb >> 11;
2317f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project            int g2 = (rgb >> 5) & 0x3F;
2327f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project            int b  = rgb & 0x1F;
2337f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project            // L coefficients 0.299 0.587 0.11
2347f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project            int L = (r<<1) + (g2<<1) + (g2>>1) + b;
2357f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project            *dst++ = L;
2367f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        }
2377f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        src += wpr;
2387f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    }
2397f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2407f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // run detection
2417f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_DCR_assignGrayByteImage(hdcr, bwbuffer, width, height);
2427f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2437f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    int numberOfFaces = 0;
2447f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    if (btk_FaceFinder_putDCR(hfd, hdcr) == btk_STATUS_OK) {
2457f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        numberOfFaces = btk_FaceFinder_faces(hfd);
246b493ba27fc74ccf339f88a48b29b4fccaf651b86Gloria Wang    } else {
2477f22db82120e7ac17165ab7614e417baa2742623Steve Block        ALOGE("ERROR: Return 0 faces because error exists in btk_FaceFinder_putDCR.\n");
2487f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    }
2497f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2507f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    // release the arrays we're using
2517f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    _env->ReleaseByteArrayElements(bwbufferObject, bwbuffer, 0);
2527f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    return numberOfFaces;
2537f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
2547f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2557f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic void
2567f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectget_face(JNIEnv *_env, jobject _this,
2577f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project     jobject face, jint index)
2587f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
259677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland    btk_HDCR hdcr = (btk_HDCR)(_env->GetLongField(_this, gFaceDetectorOffsets.dcr));
2607f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_HFaceFinder hfd =
261677f669a4e42e9f98cef158cedd2bb254ba6696eMarcus Oakland        (btk_HFaceFinder)(_env->GetLongField(_this, gFaceDetectorOffsets.fd));
2627f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2637f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    FaceData faceData;
2647f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    btk_FaceFinder_getDCR(hfd, hdcr);
2657f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    getFaceData(hdcr, &faceData);
2667f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2677f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    const float X2F = 1.0f / 65536.0f;
2687f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    _env->SetFloatField(face, gFaceOffsets.confidence,  faceData.confidence);
2697f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    _env->SetFloatField(face, gFaceOffsets.midpointx,   faceData.midpointx);
2707f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    _env->SetFloatField(face, gFaceOffsets.midpointy,   faceData.midpointy);
2717f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    _env->SetFloatField(face, gFaceOffsets.eyedist,     faceData.eyedist);
2727f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    _env->SetFloatField(face, gFaceOffsets.eulerx,      0);
2737f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    _env->SetFloatField(face, gFaceOffsets.eulery,      0);
2747f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    _env->SetFloatField(face, gFaceOffsets.eulerz,      0);
2757f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
2767f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2777f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project// ---------------------------------------------------------------------------
2787f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2797f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic const char *classPathName = "android/media/FaceDetector";
2807f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2817f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectstatic JNINativeMethod methods[] = {
2827f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{"nativeClassInit", "()V",                                  (void*)nativeClassInit },
2837f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{"fft_initialize",  "(III)I",                               (void*)initialize },
2847f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{"fft_detect",      "(Landroid/graphics/Bitmap;)I",         (void*)detect },
2857f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{"fft_get_face",    "(Landroid/media/FaceDetector$Face;I)V",(void*)get_face },
2867f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{"fft_destroy",     "()V",                                  (void*)destroy },
2877f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project};
2887f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2897f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectint register_android_media_FaceDetector(JNIEnv *_env)
2907f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
29185ecdac13cf9290e23eae013cd8551ff15d88387Narayan Kamath    return jniRegisterNativeMethods(_env, classPathName, methods, NELEM(methods));
2927f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
2937f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2947f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project// ---------------------------------------------------------------------------
2957f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
2967f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectjint JNI_OnLoad(JavaVM* vm, void* reserved)
2977f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project{
2987f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    JNIEnv* env = NULL;
2997f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    jint result = -1;
3007f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
3017f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
3027f22db82120e7ac17165ab7614e417baa2742623Steve Block        ALOGE("ERROR: GetEnv failed\n");
3037f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        goto bail;
3047f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    }
3057f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    assert(env != NULL);
3067f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
3077f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    if (register_android_media_FaceDetector(env) < 0) {
3087f22db82120e7ac17165ab7614e417baa2742623Steve Block        ALOGE("ERROR: MediaPlayer native registration failed\n");
3097f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project        goto bail;
3107f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    }
3117f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
3127f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    /* success -- return valid version number */
3137f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    result = JNI_VERSION_1_4;
3147f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project
3157f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Projectbail:
3167f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project    return result;
3177f81d9b6fa7f2ec161b682622db577a28c90b49fThe Android Open Source Project}
318