001package net.facelib.mtfsdk;
002
003import net.facelib.jni.BaseJniBridge;
004import net.facelib.jni.FacelibRuntimeParam;
005import net.facelib.jni.SdkInitException;
006import net.facelib.jni.SdkRuntimeException;
007import net.gdface.image.MatType;
008import net.gdface.utils.SimpleLog;
009
010import static net.facelib.mtfsdk.MtfsdkConstant.*;
011
012import java.util.Arrays;
013
014import static net.facelib.jni.BridgeLog.BRIDEG_LOGGER;
015
016import net.facelib.akcore.LicenseManager;
017import net.facelib.jni.SdkStatus;
018import net.facelib.sdk.ImageSupport;
019
020/**
021 * MTFSDK for android/arm JNI 接口<br>
022 * 此类为非线程安全的,不可多线程共享调用,需要在外部进一步封装实现线程安全
023 * 
024 * @author guyadong
025 *
026 */
027public class V2AndroidBridge extends BaseJniBridge {
028        public static final String SDK_VERSION = "MTFSDK512V2";
029        static final String V2_PRODUCT_ID = "MTFSDK512V2_android";
030
031        private final long[] featureHandle = new long[]{-1};
032        /**
033         * 初始化状态
034         */
035        private volatile SdkStatus status = SdkStatus.SDK_UNINITIALIZED;
036        public static V2LicenseManager V2_LICENSE_MANAGER = new V2LicenseManager();
037        static {
038                try {
039                        BRIDEG_LOGGER.log("loadLibrary FS_AndroidFeaV2SDK");
040                        // 加载算法动态库
041                        System.loadLibrary("FS_AndroidFeaV2SDK");
042                } catch (Exception e) {
043                        BRIDEG_LOGGER.log(e.getMessage());
044                        throw new ExceptionInInitializerError(e);
045                }
046
047        }
048
049        public V2AndroidBridge() {
050        }
051
052        @Override
053        public SdkStatus getStatus() {
054                return status;
055        }
056
057        @Override
058        protected void sdkInit(String licenseFile, String licenseKey, String licenseCode) throws SdkInitException {
059                if (SdkStatus.SDK_INIT_OK == status) {
060                        return;
061                }
062                try {
063                                int ffFlag = FFInitV2(
064                                                licenseCode.getBytes(), 
065                                                licenseKey.getBytes(), 
066                                                licenseFile.getBytes(), 
067                                                "\0", 
068                                                featureHandle);
069                                BRIDEG_LOGGER.log("FFInitV2 featureHandle: [{}] ffFlag={}",featureHandle[0],ffFlag);
070                                status = SdkStatus.jniCode(ffFlag);
071                                BRIDEG_LOGGER.log("feature module: {}", this);
072                                if (status != SdkStatus.SDK_INIT_OK) {
073                                        throw new SdkInitException(status);
074                                }
075                } finally {
076                        // 如果没有初始化成功,则destroy已经初始化模块
077                        if (status != SdkStatus.SDK_INIT_OK) {
078                                BRIDEG_LOGGER.log("FFDestroyV2 caused by init fail {}",this);
079                                FFDestroyV2(featureHandle[0]);
080                        }
081                }
082        }
083
084        @Override
085        protected void sdkUninit() {
086                if (featureHandle[0] >= 0) {
087                        BRIDEG_LOGGER.log("FFDestroyV2 {}",this);
088                        status = SdkStatus.SDK_UNINITIALIZED;
089                        FFDestroyV2(featureHandle[0]);
090                        featureHandle[0] = -1;
091                }
092        }
093
094        @Override
095        protected LicenseManager licenseManager() {
096                return BaseJniBridge.getLicenseManager(V2_PRODUCT_ID, V2AndroidBridge.V2_LICENSE_MANAGER);
097        }
098
099        public byte[] feaExtractByte(MatType matType, byte[] matData, int width, int height, double[] rect) {
100                byte[] buffer = new byte[FEATURE_BYTES];
101                //BRIDEG_LOGGER.log("before FFFeaExtractByteV2 {} width={},height={}",this,width, height);
102                byte[] bgr = ImageSupport.toBGR(matType, matData, width, height);
103                int ret = FFFeaExtractByteV2(featureHandle[0], bgr, width, height, buffer, rect);
104                if (ret < 0) {
105                        SdkStatus code = SdkStatus.jniCode(ret);
106                        BRIDEG_LOGGER.log("FFFeaExtractByteV2 code={} {}",code,this);
107                        throw new SdkRuntimeException(code);
108                }
109                return buffer;
110        }
111
112        @Override
113        public V2AndroidBridge setRuntimeParam(String name, Object value) throws SdkRuntimeException {
114                FacelibRuntimeParam r = FacelibRuntimeParam.valueOf(name);
115                switch (r) {
116                case featureThreadNumber:
117                        int featureThreadNumber = value != null ? (Integer) value
118                                        : MtfAndroidConfigProvider.DEFAULT_FEATURE_THREAD_NUMBER;
119                        if (featureThreadNumber > 0) {
120                                int ret = FFSetThreadsNumberV2(featureHandle[0], featureThreadNumber);
121                                if (ret != 0) {
122                                        SdkStatus code = SdkStatus.jniCode(ret);
123                                        BRIDEG_LOGGER.log("FFSetThreadsNumberV2 code={}",code,this);
124                                        throw new SdkRuntimeException(code);
125                                }
126                        }
127                        break;
128                default:
129                        throw new IllegalArgumentException(SimpleLog.logString("INVALID parameter name: {}", name));
130                }
131                return this;
132        }
133
134        //////////////////////////////////////// 特征提取系列///////////////////////////////////////////
135        /**
136         * 人脸识别初始化函数
137         * 
138         * @param licenseCode
139         *            授权码
140         * @param licenseKey
141         *            授权关键字
142         * @param path
143         *            授权码文件本地路径
144         * @param faceDetectionModelPath
145         *            模型路径
146         * @param handle
147         *            [out]句柄
148         * @return 成功(0)或错误代码(< 0),see also {@link SdkStatus}
149         */
150        private static native int FFInitV2(byte[] licenseCode, byte[] licenseKey, byte[] path,
151                        String faceDetectionModelPath, long[] handle);
152
153        /**
154         * 人脸识别模块资源释放函数
155         * 
156         * @param handle
157         *            句柄
158         */
159        static native void FFDestroyV2(long handle);
160
161        /**
162         * 对输入图像中检测到的人脸提取特征
163         * 
164         * @param handle
165         *            操作句柄
166         * @param BGR
167         *            待检测图像BGR格式
168         * @param width
169         *            图像宽度
170         * @param height
171         *            图像高度
172         * @param fea
173         *            [out] 人脸特征 空间在外部申请,长度4096
174         * @param rect
175         *            人脸位置及关键点信息 由人脸检测SDK 产生,参见
176         *            {@link #FDDetect(long, byte[], int, int, int, double[])}
177         * @return 成功(0)或错误代码(< 0),see also {@link SdkStatus}
178         */
179        private static native int FFFeaExtractByteV2(long handle, byte[] BGR, int width, int height, byte[] fea,
180                        double[] rect);
181
182        /**
183         * 人脸相似度比对函数<br>
184         * 对人脸特征feaA和feaB进行相似度比对,返回相似度结果
185         * 
186         * @param feaA
187         *            1024 bytes
188         * @param feaB
189         *            1024 bytes
190         * @return 相似度(0.0~1.0)
191         */
192        public static native double FFSimilarityByteV2(byte[] feaA, byte[] feaB);
193
194        /**
195         * @return 人脸识别模块版本
196         */
197        public static native String FFgetVersionV2();
198
199        private static native int FFSetThreadsNumberV2(long handle, int threadsNumbers);
200
201        @Override
202        public String toString() {
203                StringBuilder builder = new StringBuilder();
204                builder.append("V2AndroidBridge [featureHandle=");
205                builder.append(Arrays.toString(featureHandle));
206                builder.append(", status=");
207                builder.append(status);
208                builder.append("]");
209                return builder.toString();
210        }
211        
212}