1/*
2 * Copyright (C) 2008 The Android Open Source Project
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/* ---- includes ----------------------------------------------------------- */
18
19#include "DCR_Internal.h"
20
21/* ---- related objects  --------------------------------------------------- */
22
23/* ---- typedefs ----------------------------------------------------------- */
24
25/* ---- constants ---------------------------------------------------------- */
26
27/* ------------------------------------------------------------------------- */
28
29/* ========================================================================= */
30/*                                                                           */
31/* ---- functions ---------------------------------------------------------- */
32/*                                                                           */
33/* ========================================================================= */
34
35/* ------------------------------------------------------------------------- */
36
37void btk_DCR_init( struct bbs_Context* cpA, struct btk_DCR* ptrA )
38{
39	ptrA->hsdkE = NULL;
40	ptrA->hidE = btk_HID_DCR;
41	bpi_DCR_init( cpA, &ptrA->dcrE );
42}
43
44/* ------------------------------------------------------------------------- */
45
46void btk_DCR_exit( struct bbs_Context* cpA, struct btk_DCR* ptrA )
47{
48	ptrA->hsdkE = NULL;
49	ptrA->hidE = btk_HID_DCR;
50	bpi_DCR_exit( cpA, &ptrA->dcrE );
51}
52
53/* ------------------------------------------------------------------------- */
54
55btk_DCRCreateParam btk_DCR_defaultParam()
56{
57	btk_DCRCreateParam paramL;
58	paramL.reserved = 0;
59	return paramL;
60}
61
62/* ------------------------------------------------------------------------- */
63
64btk_Status btk_DCR_create( btk_HSDK hsdkA,
65						   const btk_DCRCreateParam* pCreateParamA,
66						   btk_HDCR* hpdcrA )
67{
68	btk_HDCR hdcrL = NULL;
69
70	if( hpdcrA == NULL )						return btk_STATUS_INVALID_HANDLE;
71	if( *hpdcrA != NULL )						return btk_STATUS_INVALID_HANDLE;
72	if( hsdkA == NULL )							return btk_STATUS_INVALID_HANDLE;
73	if( hsdkA->hidE != btk_HID_SDK )			return btk_STATUS_INVALID_HANDLE;
74	if( pCreateParamA == NULL )					return btk_STATUS_INVALID_HANDLE;
75	if( bbs_Context_error( &hsdkA->contextE ) ) return btk_STATUS_PREEXISTING_ERROR;
76
77	hdcrL = ( btk_HDCR )bbs_MemSeg_alloc( &hsdkA->contextE, hsdkA->contextE.memTblE.espArrE[ 0 ], bbs_SIZEOF16( struct btk_DCR ) );
78	if( bbs_Context_error( &hsdkA->contextE ) ) return btk_STATUS_ERROR;
79
80	btk_DCR_init( &hsdkA->contextE, hdcrL );
81	hdcrL->hsdkE = hsdkA;
82
83	if( bbs_Context_error( &hsdkA->contextE ) ) return btk_STATUS_ERROR;
84
85	bpi_DCR_create( &hsdkA->contextE,
86		            &hdcrL->dcrE,
87					hsdkA->maxImageWidthE,
88					hsdkA->maxImageHeightE,
89#ifdef btk_FRSDK
90					6000 >> 1,
91#else
92                        0,
93#endif
94					&hsdkA->contextE.memTblE );
95
96	if( bbs_Context_error( &hsdkA->contextE ) ) return btk_STATUS_ERROR;
97
98	*hpdcrA = hdcrL;
99	hsdkA->refCtrE++;
100
101	return btk_STATUS_OK;
102}
103
104/* ------------------------------------------------------------------------- */
105
106btk_Status btk_DCR_close( btk_HDCR hdcrA )
107{
108	btk_HSDK hsdkL = NULL;
109	if( hdcrA == NULL )					return btk_STATUS_INVALID_HANDLE;
110	if( hdcrA->hidE != btk_HID_DCR )	return btk_STATUS_INVALID_HANDLE;
111	if( hdcrA->hsdkE == NULL )			return btk_STATUS_INVALID_HANDLE;
112	hsdkL = hdcrA->hsdkE;
113	if( bbs_Context_error( &hsdkL->contextE ) ) return btk_STATUS_PREEXISTING_ERROR;
114
115	hsdkL->refCtrE--;
116
117	btk_DCR_exit( &hsdkL->contextE, hdcrA );
118	if( bbs_Context_error( &hsdkL->contextE ) ) return btk_STATUS_ERROR;
119
120	bbs_MemSeg_free( &hsdkL->contextE, hsdkL->contextE.memTblE.espArrE[ 0 ], hdcrA );
121	if( bbs_Context_error( &hsdkL->contextE ) ) return btk_STATUS_ERROR;
122
123	return btk_STATUS_OK;
124}
125
126/* ------------------------------------------------------------------------- */
127
128btk_Status btk_DCR_assignGrayByteImage( btk_HDCR hdcrA,
129									    const void* pDataA,
130										u32 widthA,
131										u32 heightA )
132{
133	return btk_DCR_assignImage( hdcrA, pDataA, widthA, heightA );
134}
135
136/* ------------------------------------------------------------------------- */
137
138btk_Status btk_DCR_assignImage( btk_HDCR hdcrA,
139							    const void* pDataA,
140								u32 widthA,
141								u32 heightA )
142{
143	const char* fNameL = "btk_DCR_assignImage";
144
145	btk_HSDK hsdkL = NULL;
146	if( hdcrA == NULL )					return btk_STATUS_INVALID_HANDLE;
147	if( hdcrA->hidE != btk_HID_DCR )	return btk_STATUS_INVALID_HANDLE;
148	hsdkL = hdcrA->hsdkE;
149	if( bbs_Context_error( &hsdkL->contextE ) ) return btk_STATUS_PREEXISTING_ERROR;
150
151	if( pDataA == NULL )
152	{
153		bbs_Context_pushError( &hsdkL->contextE,
154			                   bbs_Error_create( bbs_ERR_ERROR, 0, NULL, "%s:\nAssigned image references inavlid memory", fNameL ) );
155
156		return btk_STATUS_ERROR;
157	}
158
159	if( widthA == 0 || heightA == 0 )
160	{
161		bbs_Context_pushError( &hsdkL->contextE,
162			                   bbs_Error_create( bbs_ERR_ERROR, 0, NULL, "%s:\nAssigned image has size 0", fNameL ) );
163
164		return btk_STATUS_ERROR;
165	}
166
167	bpi_DCR_assignGrayByteImage( &hsdkL->contextE, &hdcrA->dcrE, pDataA, widthA, heightA );
168	if( bbs_Context_error( &hsdkL->contextE ) ) return btk_STATUS_ERROR;
169
170	return btk_STATUS_OK;
171}
172
173/* ------------------------------------------------------------------------- */
174
175btk_Status btk_DCR_assignGrayByteImageROI( btk_HDCR hdcrA,
176										   const void* pDataA,
177										   u32 widthA,
178										   u32 heightA,
179										   const btk_Rect* pRectA )
180{
181	return btk_DCR_assignImageROI( hdcrA, pDataA, widthA, heightA, pRectA );
182}
183
184/* ------------------------------------------------------------------------- */
185
186btk_Status btk_DCR_assignImageROI( btk_HDCR hdcrA,
187								   const void* pDataA,
188								   u32 widthA,
189								   u32 heightA,
190								   const btk_Rect* pRectA )
191{
192	const char* fNameL = "btk_DCR_assignGrayByteImageROI";
193
194	btk_HSDK hsdkL = NULL;
195	if( hdcrA == NULL )					return btk_STATUS_INVALID_HANDLE;
196	if( hdcrA->hidE != btk_HID_DCR )	return btk_STATUS_INVALID_HANDLE;
197	hsdkL = hdcrA->hsdkE;
198	if( bbs_Context_error( &hsdkL->contextE ) ) return btk_STATUS_PREEXISTING_ERROR;
199
200	if( pDataA == NULL )
201	{
202		bbs_Context_pushError( &hsdkL->contextE,
203			                   bbs_Error_create( bbs_ERR_ERROR, 0, NULL, "%s:\nAssigned image references invalid memory", fNameL ) );
204		return btk_STATUS_ERROR;
205	}
206
207	if( widthA == 0 || heightA == 0 )
208	{
209		bbs_Context_pushError( &hsdkL->contextE,
210			                   bbs_Error_create( bbs_ERR_ERROR, 0, NULL, "%s:\nAssigned image has size 0", fNameL ) );
211		return btk_STATUS_ERROR;
212	}
213
214	if( pRectA == NULL )
215	{
216		bbs_Context_pushError( &hsdkL->contextE,
217			                   bbs_Error_create( bbs_ERR_ERROR, 0, NULL, "%s:\nAssigned ROI rectangle references invalid memory", fNameL ) );
218		return btk_STATUS_ERROR;
219	}
220
221	if( pRectA->xMax <= pRectA->xMin || pRectA->yMax <= pRectA->yMin )
222	{
223		bbs_Context_pushError( &hsdkL->contextE,
224			                   bbs_Error_create( bbs_ERR_ERROR, 0, NULL, "%s:\nAssigned ROI rectangle is inverted (max<min) or zero", fNameL ) );
225		return btk_STATUS_ERROR;
226	}
227
228	{
229		struct bts_Int16Rect rectL;
230		rectL = bts_Int16Rect_create( pRectA->xMin >> 16,
231									  pRectA->yMin >> 16,
232									  pRectA->xMax >> 16,
233									  pRectA->yMax >> 16 );
234
235		/* rect must stay within image boundaries - adjust coordinates if necessary */
236		rectL.x1E = rectL.x1E < 0         ? 0 : rectL.x1E;
237		rectL.y1E = rectL.y1E < 0         ? 0 : rectL.y1E;
238		rectL.x2E = rectL.x2E > ( int32 )widthA    ? widthA : rectL.x2E;
239		rectL.y2E = rectL.y2E > ( int32 )heightA   ? heightA : rectL.y2E;
240
241		bpi_DCR_assignGrayByteImageROI( &hsdkL->contextE, &hdcrA->dcrE, pDataA, widthA, heightA, &rectL );
242	}
243	if( bbs_Context_error( &hsdkL->contextE ) ) return btk_STATUS_ERROR;
244
245	return btk_STATUS_OK;
246}
247
248/* ------------------------------------------------------------------------- */
249
250u32 btk_DCR_nodeCount( btk_HDCR hdcrA )
251{
252	if( hdcrA == NULL )					return 0;
253	if( hdcrA->hidE != btk_HID_DCR )	return 0;
254	return hdcrA->dcrE.sdkClusterE.clusterE.sizeE;
255}
256
257/* ------------------------------------------------------------------------- */
258
259btk_Status btk_DCR_getNode( btk_HDCR hdcrA,
260						    u32 indexA,
261							btk_Node* nodePtrA )
262{
263	const char* fNameL = "btk_DCR_getNode";
264
265	btk_HSDK hsdkL = NULL;
266	if( hdcrA == NULL )					return btk_STATUS_INVALID_HANDLE;
267	if( hdcrA->hidE != btk_HID_DCR )	return btk_STATUS_INVALID_HANDLE;
268	hsdkL = hdcrA->hsdkE;
269	if( nodePtrA == NULL ) return btk_STATUS_INVALID_HANDLE;
270
271	if( bbs_Context_error( &hsdkL->contextE ) ) return btk_STATUS_PREEXISTING_ERROR;
272
273	if( indexA >= hdcrA->dcrE.sdkClusterE.clusterE.sizeE )
274	{
275		bbs_Context_pushError( &hsdkL->contextE,
276			                   bbs_Error_create( bbs_ERR_ERROR, 0, NULL, "%s:\nIndex is out of range", fNameL ) );
277		return btk_STATUS_ERROR;
278	}
279
280	nodePtrA->id = hdcrA->dcrE.sdkClusterE.idArrE.arrPtrE[ indexA ];
281	nodePtrA->x  = ( ( s16p16 )hdcrA->dcrE.sdkClusterE.clusterE.vecArrE[ indexA ].xE ) << ( 16 - hdcrA->dcrE.sdkClusterE.clusterE.bbpE );
282	nodePtrA->y  = ( ( s16p16 )hdcrA->dcrE.sdkClusterE.clusterE.vecArrE[ indexA ].yE ) << ( 16 - hdcrA->dcrE.sdkClusterE.clusterE.bbpE );
283	if( hdcrA->dcrE.roiRectE.x1E > 0 ) nodePtrA->x += ( int32 )hdcrA->dcrE.roiRectE.x1E << 16;
284	if( hdcrA->dcrE.roiRectE.y1E > 0 ) nodePtrA->y += ( int32 )hdcrA->dcrE.roiRectE.y1E << 16;
285	nodePtrA->x += ( int32 )hdcrA->dcrE.offsE.xE << 16;
286	nodePtrA->y += ( int32 )hdcrA->dcrE.offsE.yE << 16;
287
288	nodePtrA->reserved = 0;
289
290	return btk_STATUS_OK;
291}
292
293/* ------------------------------------------------------------------------- */
294
295btk_Status btk_DCR_getRect( btk_HDCR hdcrA,
296							btk_Rect* pRectA )
297{
298	const char* fNameL = "btk_DCR_getRect";
299
300	btk_HSDK hsdkL = NULL;
301	if( hdcrA == NULL )					return btk_STATUS_INVALID_HANDLE;
302	if( hdcrA->hidE != btk_HID_DCR )	return btk_STATUS_INVALID_HANDLE;
303	hsdkL = hdcrA->hsdkE;
304	if( pRectA == NULL ) return btk_STATUS_INVALID_HANDLE;
305
306	/* find eye nodes */
307	{
308		const struct bbs_Int16Arr* pIdArrL = &hdcrA->dcrE.sdkClusterE.idArrE;
309		int32 lIndexL = -1;
310		int32 rIndexL = -1;
311		uint32 iL;
312		for( iL = 0; iL < pIdArrL->sizeE; iL++ )
313		{
314			if( pIdArrL->arrPtrE[ iL ] == 0 )
315			{
316				lIndexL = iL;
317			}
318			else if( pIdArrL->arrPtrE[ iL ] == 1 )
319			{
320				rIndexL = iL;
321			}
322		}
323
324		if( lIndexL == -1 || rIndexL == -1 )
325		{
326			bbs_Context_pushError( &hsdkL->contextE,
327								   bbs_Error_create( bbs_ERR_ERROR, 0, NULL, "%s:\nFace rectangle is not available", fNameL ) );
328			return btk_STATUS_ERROR;
329		}
330
331		{
332			int32 bbpL = hdcrA->dcrE.sdkClusterE.clusterE.bbpE;
333			int32 lxL = ( hdcrA->dcrE.sdkClusterE.clusterE.vecArrE[ lIndexL ].xE + ( 1 << ( bbpL - 1 ) ) ) >> bbpL;
334			int32 lyL = ( hdcrA->dcrE.sdkClusterE.clusterE.vecArrE[ lIndexL ].yE + ( 1 << ( bbpL - 1 ) ) ) >> bbpL;
335			int32 rxL = ( hdcrA->dcrE.sdkClusterE.clusterE.vecArrE[ rIndexL ].xE + ( 1 << ( bbpL - 1 ) ) ) >> bbpL;
336			int32 ryL = ( hdcrA->dcrE.sdkClusterE.clusterE.vecArrE[ rIndexL ].yE + ( 1 << ( bbpL - 1 ) ) ) >> bbpL;
337			int32 doffL = ( rxL - lxL ) >> 1;
338
339			pRectA->xMin = ( lxL - doffL ) << 16;
340			pRectA->xMax = ( rxL + doffL ) << 16;
341			pRectA->yMin = ( ( ( lyL + ryL + 1 ) >> 1 ) - doffL ) << 16;
342			pRectA->yMax = ( pRectA->yMin + ( pRectA->xMax - pRectA->xMin ) );
343			if( hdcrA->dcrE.roiRectE.x1E > 0 )
344			{
345				pRectA->xMin += ( int32 )hdcrA->dcrE.roiRectE.x1E << 16;
346				pRectA->xMax += ( int32 )hdcrA->dcrE.roiRectE.x1E << 16;
347			}
348			if( hdcrA->dcrE.roiRectE.y1E > 0 )
349			{
350				pRectA->yMin += ( int32 )hdcrA->dcrE.roiRectE.y1E << 16;
351				pRectA->yMax += ( int32 )hdcrA->dcrE.roiRectE.y1E << 16;
352			}
353
354			pRectA->xMin += ( int32 )hdcrA->dcrE.offsE.xE << 16;
355			pRectA->yMin += ( int32 )hdcrA->dcrE.offsE.yE << 16;
356			pRectA->xMax += ( int32 )hdcrA->dcrE.offsE.xE << 16;
357			pRectA->yMax += ( int32 )hdcrA->dcrE.offsE.yE << 16;
358
359		}
360	}
361
362	return btk_STATUS_OK;
363}
364
365
366/* ------------------------------------------------------------------------- */
367
368s8p24 btk_DCR_confidence( btk_HDCR hdcrA )
369{
370	btk_HSDK hsdkL = NULL;
371	if( hdcrA == NULL )					return 0;
372	if( hdcrA->hidE != btk_HID_DCR )	return 0;
373	hsdkL = hdcrA->hsdkE;
374	if( bbs_Context_error( &hsdkL->contextE ) ) return 0;
375
376	return hdcrA->dcrE.confidenceE;
377}
378
379/* ------------------------------------------------------------------------- */
380
381u32 btk_DCR_approved( btk_HDCR hdcrA )
382{
383	btk_HSDK hsdkL = NULL;
384	if( hdcrA == NULL )					return 0;
385	if( hdcrA->hidE != btk_HID_DCR )	return 0;
386	hsdkL = hdcrA->hsdkE;
387	if( bbs_Context_error( &hsdkL->contextE ) ) return 0;
388
389	return ( u32 )hdcrA->dcrE.approvedE;
390}
391
392/* ------------------------------------------------------------------------- */
393
394/* ========================================================================= */
395