|
1 <!DOCTYPE HTML> |
|
2 <html> |
|
3 <!-- |
|
4 https://bugzilla.mozilla.org/show_bug.cgi?id=965420 |
|
5 --> |
|
6 <head> |
|
7 <title>Bug 965420 - Test camera hardware API for face detection</title> |
|
8 <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> |
|
9 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> |
|
10 <script type="text/javascript" src="camera_common.js"></script> |
|
11 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> |
|
12 </head> |
|
13 <body> |
|
14 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=965420">Mozilla Bug 965420</a> |
|
15 <video id="viewfinder" width = "200" height = "200" autoplay></video> |
|
16 <img src="#" alt="This image is going to load" id="testimage"/> |
|
17 |
|
18 <script class="testbody" type="text/javascript;version=1.7"> |
|
19 |
|
20 var whichCamera = navigator.mozCameras.getListOfCameras()[0]; |
|
21 var initialConfig = { |
|
22 mode: 'picture', |
|
23 recorderProfile: 'cif', |
|
24 previewSize: { |
|
25 width: 352, |
|
26 height: 288 |
|
27 } |
|
28 }; |
|
29 |
|
30 const PREF_FACEDETECTION_ENABLED = "camera.control.face_detection.enabled"; |
|
31 |
|
32 var cameraObj; |
|
33 var oldPref; |
|
34 |
|
35 // Shorthand functions |
|
36 function end() { |
|
37 function reallyEnd() { |
|
38 CameraTest.end(); |
|
39 } |
|
40 if (oldPref) { |
|
41 SpecialPowers.pushPrefEnv( |
|
42 {'set': [[PREF_FACEDETECTION_ENABLED, oldPref]]}, reallyEnd); |
|
43 } else { |
|
44 SpecialPowers.pushPrefEnv( |
|
45 {'clear': [[PREF_FACEDETECTION_ENABLED]]}, reallyEnd); |
|
46 } |
|
47 } |
|
48 function next() { |
|
49 CameraTest.next(); |
|
50 } |
|
51 |
|
52 function compareFaces(aFaces, expected) |
|
53 { |
|
54 ok(aFaces, "have detected faces object"); |
|
55 ok(aFaces.length == expected.faces.length, |
|
56 "expected=" + expected.faces.length + ", got=" + aFaces.length); |
|
57 aFaces.forEach(function (face, index) { |
|
58 let result = compareFace(face, expected.faces[index]); |
|
59 ok(result === "ok", "face check: " + result); |
|
60 if (result !== "ok") { |
|
61 return false; |
|
62 } |
|
63 }); |
|
64 return true; |
|
65 } |
|
66 |
|
67 function compareFace(aFace, expected) |
|
68 { |
|
69 if (aFace.id != expected.id) { |
|
70 return "expected face.id=" + expected.id + ", got=" + aFace.id; |
|
71 } |
|
72 if (aFace.score != expected.score) { |
|
73 return "expected face.score=" + expected.score + ", got=" + aFace.score; |
|
74 } |
|
75 if (!aFace.bounds) { |
|
76 return "face.bounds is missing"; |
|
77 } |
|
78 if (aFace.bounds.left != expected.bounds.left || |
|
79 aFace.bounds.top != expected.bounds.top || |
|
80 aFace.bounds.right != expected.bounds.right || |
|
81 aFace.bounds.bottom != expected.bounds.bottom) { |
|
82 return "expected face.bounds=" + expected.bounds.toSource() + |
|
83 ", got=({left:" + aFace.bounds.left + ", top:" + aFace.bounds.top + ", right:" + aFace.bounds.right + ", bottom:" + aFace.bounds.bottom + "})"; |
|
84 } |
|
85 |
|
86 if (aFace.leftEye && !expected.leftEye) { |
|
87 return "expected null face.leftEye, got=({x:" + aFace.leftEye.x + ", y:" + aFace.leftEye.y + "})"; |
|
88 } |
|
89 if (!aFace.leftEye && expected.leftEye) { |
|
90 return "expected face.leftEye=" + expected.leftEye.toSource() + ", got null leftEye"; |
|
91 } |
|
92 if (aFace.leftEye && expected.leftEye && |
|
93 (aFace.leftEye.x != expected.leftEye.x || aFace.leftEye.y != expected.leftEye.y)) { |
|
94 return "expected face.leftEye=" + expected.leftEye.toSource() + |
|
95 ", got=({x:" + aFace.leftEye.x + ", y:" + aFace.leftEye.y + "})"; |
|
96 } |
|
97 |
|
98 if (aFace.rightEye && !expected.rightEye) { |
|
99 return "expected null face.rightEye, got=({x:" + aFace.rightEye.x + ", y:" + aFace.rightEye.y + "})"; |
|
100 } |
|
101 if (!aFace.rightEye && expected.rightEye) { |
|
102 return "expected face.rightEye=" + expected.rightEye.toSource() + ", got null rightEye"; |
|
103 } |
|
104 if (aFace.rightEye && expected.rightEye && |
|
105 (aFace.rightEye.x != expected.rightEye.x || aFace.rightEye.y != expected.rightEye.y)) { |
|
106 return "expected face.rightEye=" + expected.rightEye.toSource() + |
|
107 ", got=({x:" + aFace.rightEye.x + ", y:" + aFace.rightEye.y + "})"; |
|
108 } |
|
109 |
|
110 if (aFace.mouth && !expected.mouth) { |
|
111 return "expected null face.mouth, got=({x:" + aFace.mouth.x + ", y:" + aFace.mouth.y + "})"; |
|
112 } |
|
113 if (!aFace.mouth && expected.mouth) { |
|
114 return "expected face.mouth=" + expected.mouth.toSource() + ", got null mouth"; |
|
115 } |
|
116 if (aFace.mouth && expected.mouth && |
|
117 (aFace.mouth.x != expected.mouth.x || aFace.mouth.y != expected.mouth.y)) { |
|
118 return "expected face.mouth=" + expected.mouth.toSource() + |
|
119 ", got=({x:" + aFace.mouth.x + ", y:" + aFace.mouth.y + "})"; |
|
120 } |
|
121 |
|
122 return "ok"; |
|
123 } |
|
124 |
|
125 var tests = [ |
|
126 { |
|
127 key: "face-detection-detected-one-face", |
|
128 func: function testFaceDetectionFoundOneFace(camera) { |
|
129 var expected = { |
|
130 faces: [ { |
|
131 id: 1, |
|
132 score: 2, |
|
133 bounds: { |
|
134 left: 3, |
|
135 top: 4, |
|
136 right: 5, |
|
137 bottom: 6 |
|
138 }, |
|
139 leftEye: { |
|
140 x: 7, |
|
141 y: 8 |
|
142 }, |
|
143 rightEye: { |
|
144 x: 9, |
|
145 y: 10 |
|
146 }, |
|
147 mouth: { |
|
148 x: 11, |
|
149 y: 12 |
|
150 } |
|
151 } ] |
|
152 }; |
|
153 camera.onFacesDetected = function(aFaces) { |
|
154 ok(compareFaces(aFaces, expected), |
|
155 "onFaceDetected received the detected faces correctly"); |
|
156 camera.stopFaceDetection(); |
|
157 next(); |
|
158 } |
|
159 camera.startFaceDetection(); |
|
160 } |
|
161 }, |
|
162 { |
|
163 key: "face-detection-detected-two-faces", |
|
164 func: function testFaceDetectionFoundTwoFace(camera) { |
|
165 var expected = { |
|
166 faces: [ { |
|
167 id: 1, |
|
168 score: 2, |
|
169 bounds: { |
|
170 left: 3, |
|
171 top: 4, |
|
172 right: 5, |
|
173 bottom: 6 |
|
174 }, |
|
175 leftEye: { |
|
176 x: 7, |
|
177 y: 8 |
|
178 }, |
|
179 rightEye: { |
|
180 x: 9, |
|
181 y: 10 |
|
182 }, |
|
183 mouth: { |
|
184 x: 11, |
|
185 y: 12 |
|
186 } |
|
187 }, |
|
188 { |
|
189 id: 13, |
|
190 score: 14, |
|
191 bounds: { |
|
192 left: 15, |
|
193 top: 16, |
|
194 right: 17, |
|
195 bottom: 18 |
|
196 }, |
|
197 leftEye: { |
|
198 x: 19, |
|
199 y: 20 |
|
200 }, |
|
201 rightEye: { |
|
202 x: 21, |
|
203 y: 22 |
|
204 }, |
|
205 mouth: { |
|
206 x: 23, |
|
207 y: 24 |
|
208 } |
|
209 } ] |
|
210 }; |
|
211 camera.onFacesDetected = function(aFaces) { |
|
212 ok(compareFaces(aFaces, expected), |
|
213 "onFaceDetected received the detected faces correctly"); |
|
214 camera.stopFaceDetection(); |
|
215 next(); |
|
216 } |
|
217 camera.startFaceDetection(); |
|
218 } |
|
219 }, |
|
220 { |
|
221 key: "face-detection-detected-one-face-no-features", |
|
222 func: function (camera) { |
|
223 var expected = { |
|
224 faces: [ { |
|
225 id: 1, |
|
226 score: 100, |
|
227 bounds: { |
|
228 left: 3, |
|
229 top: 4, |
|
230 right: 5, |
|
231 bottom: 6 |
|
232 }, |
|
233 leftEye: null, |
|
234 rightEye: null, |
|
235 mouth: null |
|
236 } ] |
|
237 }; |
|
238 camera.onFacesDetected = function(aFaces) { |
|
239 ok(compareFaces(aFaces, expected), |
|
240 "onFaceDetected received the detected faces correctly"); |
|
241 camera.stopFaceDetection(); |
|
242 next(); |
|
243 } |
|
244 camera.startFaceDetection(); |
|
245 } |
|
246 }, |
|
247 { |
|
248 key: "face-detection-no-faces-detected", |
|
249 func: function (camera) { |
|
250 var expected = { |
|
251 faces: [] |
|
252 }; |
|
253 camera.onFacesDetected = function(aFaces) { |
|
254 ok(compareFaces(aFaces, expected), |
|
255 "onFaceDetected received the detected faces correctly"); |
|
256 camera.stopFaceDetection(); |
|
257 next(); |
|
258 } |
|
259 camera.startFaceDetection(); |
|
260 } |
|
261 }, |
|
262 ]; |
|
263 |
|
264 var testGenerator = function() { |
|
265 for (var i = 0; i < tests.length; ++i ) { |
|
266 yield tests[i]; |
|
267 } |
|
268 }(); |
|
269 |
|
270 window.addEventListener('beforeunload', function() { |
|
271 document.getElementById('viewfinder').mozSrcObject = null; |
|
272 if (cameraObj) { |
|
273 cameraObj.release(); |
|
274 cameraObj = null; |
|
275 } |
|
276 }); |
|
277 |
|
278 // Must call CameraTest.begin() before any other async methods. |
|
279 CameraTest.begin("hardware", function(test) { |
|
280 // If the pref doesn't exist, this get will fail; catch it and continue. |
|
281 try { |
|
282 oldPref = SpecialPowers.getBoolPref(PREF_FACEDETECTION_ENABLED); |
|
283 } catch(e) { } |
|
284 |
|
285 SpecialPowers.pushPrefEnv({'set': [[PREF_FACEDETECTION_ENABLED, true]]}, function() { |
|
286 var enabled; |
|
287 try { |
|
288 enabled = SpecialPowers.getBoolPref(PREF_FACEDETECTION_ENABLED); |
|
289 } catch(e) { } |
|
290 ok(enabled, PREF_FACEDETECTION_ENABLED + " is " + enabled); |
|
291 |
|
292 function onSuccess(camera, config) { |
|
293 document.getElementById('viewfinder').mozSrcObject = camera; |
|
294 cameraObj = camera; |
|
295 CameraTest.next = function() { |
|
296 try { |
|
297 var t = testGenerator.next(); |
|
298 test.set(t.key, t.func.bind(undefined, camera)); |
|
299 } catch(e) { |
|
300 if (e instanceof StopIteration) { |
|
301 end(); |
|
302 } else { |
|
303 throw e; |
|
304 } |
|
305 } |
|
306 }; |
|
307 next(); |
|
308 } |
|
309 function onError(error) { |
|
310 ok(false, "getCamera() failed with: " + error); |
|
311 end(); |
|
312 } |
|
313 navigator.mozCameras.getCamera(whichCamera, initialConfig, onSuccess, onError); |
|
314 }) |
|
315 }); |
|
316 |
|
317 </script> |
|
318 </body> |
|
319 |
|
320 </html> |