Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(117)

Side by Side Diff: third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp

Issue 2455973007: FaceDetection: add support for <video> input (Closed)
Patch Set: xianglu@s comments Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/modules/shapedetection/FaceDetector.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "modules/shapedetection/FaceDetector.h" 5 #include "modules/shapedetection/FaceDetector.h"
6 6
7 #include "core/dom/DOMException.h" 7 #include "core/dom/DOMException.h"
8 #include "core/dom/DOMRect.h" 8 #include "core/dom/DOMRect.h"
9 #include "core/dom/Document.h" 9 #include "core/dom/Document.h"
10 #include "core/fetch/ImageResource.h" 10 #include "core/fetch/ImageResource.h"
11 #include "core/frame/ImageBitmap.h" 11 #include "core/frame/ImageBitmap.h"
12 #include "core/frame/LocalDOMWindow.h" 12 #include "core/frame/LocalDOMWindow.h"
13 #include "core/frame/LocalFrame.h" 13 #include "core/frame/LocalFrame.h"
14 #include "core/html/HTMLImageElement.h" 14 #include "core/html/HTMLImageElement.h"
15 #include "core/html/HTMLVideoElement.h"
15 #include "core/html/canvas/CanvasImageSource.h" 16 #include "core/html/canvas/CanvasImageSource.h"
16 #include "platform/graphics/Image.h" 17 #include "platform/graphics/Image.h"
17 #include "public/platform/InterfaceProvider.h" 18 #include "public/platform/InterfaceProvider.h"
18 #include "third_party/skia/include/core/SkImage.h" 19 #include "third_party/skia/include/core/SkImage.h"
19 #include "third_party/skia/include/core/SkImageInfo.h" 20 #include "third_party/skia/include/core/SkImageInfo.h"
20 #include "wtf/CheckedNumeric.h" 21 #include "wtf/CheckedNumeric.h"
21 22
22 namespace blink { 23 namespace blink {
23 24
24 namespace { 25 namespace {
25 26
26 static CanvasImageSource* toImageSourceInternal( 27 static CanvasImageSource* toImageSourceInternal(
27 const CanvasImageSourceUnion& value) { 28 const CanvasImageSourceUnion& value) {
28 if (value.isHTMLImageElement()) 29 if (value.isHTMLImageElement())
29 return value.getAsHTMLImageElement(); 30 return value.getAsHTMLImageElement();
30 31
31 if (value.isImageBitmap()) { 32 if (value.isImageBitmap() &&
32 if (static_cast<ImageBitmap*>(value.getAsImageBitmap())->isNeutered()) 33 !static_cast<ImageBitmap*>(value.getAsImageBitmap())->isNeutered()) {
33 return nullptr;
34 return value.getAsImageBitmap(); 34 return value.getAsImageBitmap();
35 } 35 }
36 36
37 if (value.isHTMLVideoElement())
38 return value.getAsHTMLVideoElement();
39
37 return nullptr; 40 return nullptr;
38 } 41 }
39 42
40 } // anonymous namespace 43 } // anonymous namespace
41 44
42 FaceDetector* FaceDetector::create(ScriptState* scriptState) { 45 FaceDetector* FaceDetector::create(ScriptState* scriptState) {
43 return new FaceDetector(*scriptState->domWindow()->frame()); 46 return new FaceDetector(*scriptState->domWindow()->frame());
44 } 47 }
45 48
46 FaceDetector::FaceDetector(LocalFrame& frame) { 49 FaceDetector::FaceDetector(LocalFrame& frame) {
(...skipping 12 matching lines...) Expand all
59 if (!imageSourceInternal) { 62 if (!imageSourceInternal) {
60 // TODO(mcasas): Implement more CanvasImageSources, https://crbug.com/659138 63 // TODO(mcasas): Implement more CanvasImageSources, https://crbug.com/659138
61 NOTIMPLEMENTED() << "Unsupported CanvasImageSource"; 64 NOTIMPLEMENTED() << "Unsupported CanvasImageSource";
62 resolver->reject( 65 resolver->reject(
63 DOMException::create(NotFoundError, "Unsupported source.")); 66 DOMException::create(NotFoundError, "Unsupported source."));
64 return promise; 67 return promise;
65 } 68 }
66 69
67 if (imageSourceInternal->wouldTaintOrigin( 70 if (imageSourceInternal->wouldTaintOrigin(
68 scriptState->getExecutionContext()->getSecurityOrigin())) { 71 scriptState->getExecutionContext()->getSecurityOrigin())) {
69 resolver->reject(DOMException::create(SecurityError, 72 resolver->reject(
70 "Image source would taint origin.")); 73 DOMException::create(SecurityError, "Source would taint origin."));
71 return promise; 74 return promise;
72 } 75 }
73 76
74 if (imageSource.isHTMLImageElement()) { 77 if (imageSource.isHTMLImageElement()) {
75 return detectFacesOnImageElement( 78 return detectFacesOnImageElement(
76 resolver, static_cast<HTMLImageElement*>(imageSourceInternal)); 79 resolver, static_cast<HTMLImageElement*>(imageSourceInternal));
77 } 80 }
78 if (imageSourceInternal->isImageBitmap()) { 81 if (imageSourceInternal->isImageBitmap()) {
79 return detectFacesOnImageBitmap( 82 return detectFacesOnImageBitmap(
80 resolver, static_cast<ImageBitmap*>(imageSourceInternal)); 83 resolver, static_cast<ImageBitmap*>(imageSourceInternal));
81 } 84 }
85 if (imageSourceInternal->isVideoElement()) {
86 return detectFacesOnVideoElement(
87 resolver, static_cast<HTMLVideoElement*>(imageSourceInternal));
88 }
89
82 NOTREACHED(); 90 NOTREACHED();
83 return promise; 91 return promise;
84 } 92 }
85 93
86 ScriptPromise FaceDetector::detectFacesOnImageElement( 94 ScriptPromise FaceDetector::detectFacesOnImageElement(
87 ScriptPromiseResolver* resolver, 95 ScriptPromiseResolver* resolver,
88 const HTMLImageElement* img) { 96 const HTMLImageElement* img) {
89 ScriptPromise promise = resolver->promise(); 97 ScriptPromise promise = resolver->promise();
90 if (img->bitmapSourceSize().isZero()) { 98 if (img->bitmapSourceSize().isZero()) {
91 resolver->resolve(HeapVector<Member<DOMRect>>()); 99 resolver->resolve(HeapVector<Member<DOMRect>>());
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 allocationSize = pixmap.getSafeSize(); 196 allocationSize = pixmap.getSafeSize();
189 } else { 197 } else {
190 pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied() 198 pixelData = imageBitmap->copyBitmapData(imageBitmap->isPremultiplied()
191 ? PremultiplyAlpha 199 ? PremultiplyAlpha
192 : DontPremultiplyAlpha, 200 : DontPremultiplyAlpha,
193 N32ColorType); 201 N32ColorType);
194 pixelDataPtr = pixelData->data(); 202 pixelDataPtr = pixelData->data();
195 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */; 203 allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */;
196 } 204 }
197 205
206 return detectFacesOnData(resolver, pixelDataPtr,
207 allocationSize.ValueOrDefault(0),
208 imageBitmap->width(), imageBitmap->height());
209 }
210
211 ScriptPromise FaceDetector::detectFacesOnVideoElement(
212 ScriptPromiseResolver* resolver,
213 const HTMLVideoElement* video) {
214 ScriptPromise promise = resolver->promise();
215
216 // TODO(mcasas): Check if |video| is actually playing a MediaStream by using
217 // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if
218 // there is a local WebCam associated, there might be sophisticated ways to
219 // detect faces on it. Until then, treat as a normal <video> element.
220
221 // !hasAvailableVideoFrame() is a bundle of invalid states.
222 if (!video->hasAvailableVideoFrame()) {
223 resolver->reject(DOMException::create(
224 InvalidStateError, "Invalid HTMLVideoElement or state."));
225 return promise;
226 }
227
228 const FloatSize videoSize(video->videoWidth(), video->videoHeight());
229 SourceImageStatus sourceImageStatus = InvalidSourceImageStatus;
230 RefPtr<Image> image =
231 video->getSourceImageForCanvas(&sourceImageStatus, PreferNoAcceleration,
232 SnapshotReasonDrawImage, videoSize);
233
234 DCHECK_EQ(NormalSourceImageStatus, sourceImageStatus);
235
236 SkPixmap pixmap;
237 RefPtr<Uint8Array> pixelData;
238 uint8_t* pixelDataPtr = nullptr;
239 WTF::CheckedNumeric<int> allocationSize = 0;
240 // Use |skImage|'s pixels if it has direct access to them.
241 sk_sp<SkImage> skImage = image->imageForCurrentFrame();
242 if (skImage->peekPixels(&pixmap)) {
243 pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr());
244 allocationSize = pixmap.getSafeSize();
245 } else {
246 // TODO(mcasas): retrieve the pixels from elsewhere.
247 NOTREACHED();
248 resolver->reject(DOMException::create(
249 InvalidStateError, "Failed to get pixels for current frame."));
250 return promise;
251 }
252
253 return detectFacesOnData(resolver, pixelDataPtr,
254 allocationSize.ValueOrDefault(0), image->width(),
255 image->height());
256 }
257
258 ScriptPromise FaceDetector::detectFacesOnData(ScriptPromiseResolver* resolver,
259 uint8_t* data,
260 int size,
261 int width,
262 int height) {
263 DCHECK(data);
264 DCHECK(size);
265 ScriptPromise promise = resolver->promise();
266
198 mojo::ScopedSharedBufferHandle sharedBufferHandle = 267 mojo::ScopedSharedBufferHandle sharedBufferHandle =
199 mojo::SharedBufferHandle::Create(allocationSize.ValueOrDefault(0)); 268 mojo::SharedBufferHandle::Create(size);
200 269 if (!sharedBufferHandle->is_valid()) {
201 if (!pixelDataPtr || !sharedBufferHandle->is_valid()) {
202 resolver->reject( 270 resolver->reject(
203 DOMException::create(InvalidStateError, "Internal allocation error")); 271 DOMException::create(InvalidStateError, "Internal allocation error"));
204 return promise; 272 return promise;
205 } 273 }
206 274
207 if (!m_service) { 275 if (!m_service) {
208 resolver->reject(DOMException::create( 276 resolver->reject(DOMException::create(
209 NotFoundError, "Face detection service unavailable.")); 277 NotSupportedError, "Face detection service unavailable."));
210 return promise; 278 return promise;
211 } 279 }
212 280
213 const mojo::ScopedSharedBufferMapping mappedBuffer = 281 const mojo::ScopedSharedBufferMapping mappedBuffer =
214 sharedBufferHandle->Map(allocationSize.ValueOrDefault(0)); 282 sharedBufferHandle->Map(size);
215 DCHECK(mappedBuffer.get()); 283 DCHECK(mappedBuffer.get());
216 284
217 memcpy(mappedBuffer.get(), pixelDataPtr, allocationSize.ValueOrDefault(0)); 285 memcpy(mappedBuffer.get(), data, size);
218 286
219 m_serviceRequests.add(resolver); 287 m_serviceRequests.add(resolver);
220 DCHECK(m_service.is_bound()); 288 DCHECK(m_service.is_bound());
221 m_service->DetectFace(std::move(sharedBufferHandle), imageBitmap->width(), 289 m_service->DetectFace(std::move(sharedBufferHandle), width, height,
222 imageBitmap->height(),
223 convertToBaseCallback(WTF::bind( 290 convertToBaseCallback(WTF::bind(
224 &FaceDetector::onDetectFace, wrapPersistent(this), 291 &FaceDetector::onDetectFace, wrapPersistent(this),
225 wrapPersistent(resolver)))); 292 wrapPersistent(resolver))));
226 sharedBufferHandle.reset(); 293 sharedBufferHandle.reset();
227 return promise; 294 return promise;
228 } 295 }
229 296
230 void FaceDetector::onDetectFace( 297 void FaceDetector::onDetectFace(
231 ScriptPromiseResolver* resolver, 298 ScriptPromiseResolver* resolver,
232 mojom::blink::FaceDetectionResultPtr faceDetectionResult) { 299 mojom::blink::FaceDetectionResultPtr faceDetectionResult) {
233 if (!m_serviceRequests.contains(resolver)) 300 if (!m_serviceRequests.contains(resolver))
234 return; 301 return;
235 302
236 HeapVector<Member<DOMRect>> detectedFaces; 303 HeapVector<Member<DOMRect>> detectedFaces;
237 for (const auto& boundingBox : faceDetectionResult->boundingBoxes) { 304 for (const auto& boundingBox : faceDetectionResult->boundingBoxes) {
238 detectedFaces.append(DOMRect::create(boundingBox->x, boundingBox->y, 305 detectedFaces.append(DOMRect::create(boundingBox->x, boundingBox->y,
239 boundingBox->width, 306 boundingBox->width,
240 boundingBox->height)); 307 boundingBox->height));
241 } 308 }
242 309
243 resolver->resolve(detectedFaces); 310 resolver->resolve(detectedFaces);
244 m_serviceRequests.remove(resolver); 311 m_serviceRequests.remove(resolver);
245 } 312 }
246 313
247 DEFINE_TRACE(FaceDetector) { 314 DEFINE_TRACE(FaceDetector) {
248 visitor->trace(m_serviceRequests); 315 visitor->trace(m_serviceRequests);
249 } 316 }
250 317
251 } // namespace blink 318 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/modules/shapedetection/FaceDetector.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698