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

Unified Diff: third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp

Issue 2455973007: FaceDetection: add support for <video> input (Closed)
Patch Set: xianglu@ 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 side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
diff --git a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
index 882dc6214fcdbcd3e6a86c5ab33da618b6374e33..a71e792cc3bb45e07d78e6bcc502bf6ef9fd257f 100644
--- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
@@ -12,6 +12,7 @@
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/LocalFrame.h"
#include "core/html/HTMLImageElement.h"
+#include "core/html/HTMLVideoElement.h"
#include "core/html/canvas/CanvasImageSource.h"
#include "platform/graphics/Image.h"
#include "public/platform/InterfaceProvider.h"
@@ -34,6 +35,9 @@ static CanvasImageSource* toImageSourceInternal(
return value.getAsImageBitmap();
}
+ if (value.isHTMLVideoElement())
+ return value.getAsHTMLVideoElement();
+
return nullptr;
}
@@ -66,8 +70,8 @@ ScriptPromise FaceDetector::detect(ScriptState* scriptState,
if (imageSourceInternal->wouldTaintOrigin(
scriptState->getExecutionContext()->getSecurityOrigin())) {
- resolver->reject(DOMException::create(SecurityError,
- "Image source would taint origin."));
+ resolver->reject(
+ DOMException::create(SecurityError, "Source would taint origin."));
return promise;
}
@@ -79,6 +83,11 @@ ScriptPromise FaceDetector::detect(ScriptState* scriptState,
return detectFacesOnImageBitmap(
resolver, static_cast<ImageBitmap*>(imageSourceInternal));
}
+ if (imageSourceInternal->isVideoElement()) {
+ return detectFacesOnVideoElement(
+ resolver, static_cast<HTMLVideoElement*>(imageSourceInternal));
+ }
+
NOTREACHED();
return promise;
}
@@ -195,10 +204,70 @@ ScriptPromise FaceDetector::detectFacesOnImageBitmap(
allocationSize = imageBitmap->size().area() * 4 /* bytes per pixel */;
}
- mojo::ScopedSharedBufferHandle sharedBufferHandle =
- mojo::SharedBufferHandle::Create(allocationSize.ValueOrDefault(0));
+ return detectFacesOnData(resolver, pixelDataPtr,
+ allocationSize.ValueOrDefault(0),
+ imageBitmap->width(), imageBitmap->height());
+}
+
+ScriptPromise FaceDetector::detectFacesOnVideoElement(
+ ScriptPromiseResolver* resolver,
+ const HTMLVideoElement* video) {
+ ScriptPromise promise = resolver->promise();
+
+ // TODO(mcasas): Check if |video| is actually playing a MediaStream by using
+ // HTMLMediaElement::isMediaStreamURL(video->currentSrc().getString()); if
+ // there is a local WebCam associated, there might be sophisticated ways to
+ // detect faces on it. Until then, treat as a normal <video> element.
+
+ // !hasAvailableVideoFrame() is a bundle of invalid states.
+ if (!video->hasAvailableVideoFrame()) {
+ resolver->reject(DOMException::create(
+ InvalidStateError, "Invalid HTMLVideoElement or state."));
+ return promise;
+ }
+
+ const FloatSize videoSize(video->videoWidth(), video->videoHeight());
+ SourceImageStatus sourceImageStatus = InvalidSourceImageStatus;
+ RefPtr<Image> image =
+ video->getSourceImageForCanvas(&sourceImageStatus, PreferNoAcceleration,
+ SnapshotReasonDrawImage, videoSize);
+
+ DCHECK_EQ(NormalSourceImageStatus, sourceImageStatus);
+
+ SkPixmap pixmap;
+ RefPtr<Uint8Array> pixelData;
+ uint8_t* pixelDataPtr = nullptr;
+ WTF::CheckedNumeric<int> allocationSize = 0;
+ // Use |skImage|'s pixels if it has direct access to them.
+ sk_sp<SkImage> skImage = image->imageForCurrentFrame();
+ if (skImage->peekPixels(&pixmap)) {
+ pixelDataPtr = static_cast<uint8_t*>(pixmap.writable_addr());
+ allocationSize = pixmap.getSafeSize();
+ } else {
+ // TODO(mcasas): retrieve the pixels from elsewhere.
+ NOTREACHED();
+ resolver->reject(DOMException::create(
+ InvalidStateError, "Failed to get pixels for current frame."));
+ return promise;
+ }
+
+ return detectFacesOnData(resolver, pixelDataPtr,
+ allocationSize.ValueOrDefault(0), image->width(),
+ image->height());
+}
- if (!pixelDataPtr || !sharedBufferHandle->is_valid()) {
+ScriptPromise FaceDetector::detectFacesOnData(ScriptPromiseResolver* resolver,
+ uint8_t* data,
+ int size,
+ int width,
+ int height) {
+ DCHECK(data);
+ DCHECK(size);
+ ScriptPromise promise = resolver->promise();
+
+ mojo::ScopedSharedBufferHandle sharedBufferHandle =
+ mojo::SharedBufferHandle::Create(size);
+ if (!sharedBufferHandle->is_valid()) {
resolver->reject(
DOMException::create(InvalidStateError, "Internal allocation error"));
return promise;
@@ -206,20 +275,19 @@ ScriptPromise FaceDetector::detectFacesOnImageBitmap(
if (!m_service) {
resolver->reject(DOMException::create(
- NotFoundError, "Face detection service unavailable."));
+ NotSupportedError, "Face detection service unavailable."));
return promise;
}
const mojo::ScopedSharedBufferMapping mappedBuffer =
- sharedBufferHandle->Map(allocationSize.ValueOrDefault(0));
+ sharedBufferHandle->Map(size);
DCHECK(mappedBuffer.get());
- memcpy(mappedBuffer.get(), pixelDataPtr, allocationSize.ValueOrDefault(0));
+ memcpy(mappedBuffer.get(), data, size);
m_serviceRequests.add(resolver);
DCHECK(m_service.is_bound());
- m_service->DetectFace(std::move(sharedBufferHandle), imageBitmap->width(),
- imageBitmap->height(),
+ m_service->DetectFace(std::move(sharedBufferHandle), width, height,
convertToBaseCallback(WTF::bind(
&FaceDetector::onDetectFace, wrapPersistent(this),
wrapPersistent(resolver))));

Powered by Google App Engine
This is Rietveld 408576698