Chromium Code Reviews| Index: services/shape_detection/face_detection_impl_mac.mm |
| diff --git a/services/shape_detection/face_detection_impl_mac.mm b/services/shape_detection/face_detection_impl_mac.mm |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..924f05786566aa8f53e5b08d1b51321121588f1f |
| --- /dev/null |
| +++ b/services/shape_detection/face_detection_impl_mac.mm |
| @@ -0,0 +1,124 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "services/shape_detection/face_detection_impl_mac.h" |
| + |
| +#include "base/mac/scoped_cftyperef.h" |
| +#include "base/mac/scoped_nsobject.h" |
| +#include "base/memory/shared_memory.h" |
| +#include "media/capture/video/scoped_result_callback.h" |
| +#include "mojo/public/cpp/bindings/strong_binding.h" |
| +#include "mojo/public/cpp/system/platform_handle.h" |
| + |
| +namespace shape_detection { |
| + |
| +// kCIFormatRGBA8 is not exposed to public until Mac 10.11. So we define the |
| +// same constant to support RGBA8 format in earlier versions. |
| + |
| +#if !defined(MAC_OS_X_VERSION_10_11) || \ |
| + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11 |
| +namespace { |
| + |
| +const int kCIFormatRGBA8 = 24; |
| + |
| +} // anonymous namespace |
| +#endif |
| + |
| +void FaceDetectionImpl::Create(blink::mojom::FaceDetectionRequest request) { |
| + mojo::MakeStrongBinding(base::MakeUnique<FaceDetectionImplMac>(), |
| + std::move(request)); |
| +} |
| + |
| +FaceDetectionImplMac::FaceDetectionImplMac() { |
| + context_.reset([[CIContext alloc] init]); |
| + NSDictionary* const opts = @{CIDetectorAccuracy : CIDetectorAccuracyHigh}; |
| + detector_.reset([[CIDetector detectorOfType:CIDetectorTypeFace |
| + context:context_ |
| + options:opts] retain]); |
| +} |
| + |
| +FaceDetectionImplMac::~FaceDetectionImplMac() {} |
| + |
| +void FaceDetectionImplMac::Detect(mojo::ScopedSharedBufferHandle frame_data, |
| + uint32_t width, |
| + uint32_t height, |
| + blink::mojom::FaceDetectorOptionsPtr options, |
| + const DetectCallback& callback) { |
| + media::ScopedResultCallback<DetectCallback> scoped_callback( |
| + base::Bind(&FaceDetectionImplMac::RunCallbackWithFaces, callback), |
| + base::Bind(&FaceDetectionImplMac::RunCallbackWithNoFaces)); |
| + |
| + base::CheckedNumeric<uint32_t> num_pixels = |
| + base::CheckedNumeric<uint32_t>(width) * height; |
| + base::CheckedNumeric<uint32_t> num_bytes = num_pixels * 4; |
| + if (!num_bytes.IsValid()) { |
| + DLOG(ERROR) << "Data overflow"; |
| + return; |
| + } |
| + |
| + base::SharedMemoryHandle memory_handle; |
| + size_t memory_size = 0; |
| + bool read_only_flag = false; |
| + const MojoResult result = mojo::UnwrapSharedMemoryHandle( |
| + std::move(frame_data), &memory_handle, &memory_size, &read_only_flag); |
| + DCHECK_EQ(MOJO_RESULT_OK, result) << "Failed to unwrap SharedBufferHandle"; |
| + if (!memory_size || memory_size != num_bytes.ValueOrDie()) { |
| + DLOG(ERROR) << "Invalid image size"; |
| + return; |
| + } |
| + |
| + std::unique_ptr<base::SharedMemory> shared_memory( |
| + new base::SharedMemory(memory_handle, true /* read_only */)); |
|
Avi (use Gerrit)
2016/12/06 05:44:21
Can we do
auto shared_memory = base::MakeUnique<b
xianglu
2016/12/08 01:20:54
Done.
|
| + if (!shared_memory->Map(memory_size)) { |
| + DLOG(ERROR) << "Failed to map bytes from shared memory"; |
| + return; |
| + } |
| + |
| + NSData* byte_data = [NSData dataWithBytesNoCopy:shared_memory->memory() |
| + length:num_bytes.ValueOrDie() |
| + freeWhenDone:NO]; |
| + |
| + base::ScopedCFTypeRef<CGColorSpaceRef> colorspace( |
| + CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); |
| + |
| + // CIImage will return nil when RGBA8 is not supported in a certain sion. |
|
Avi (use Gerrit)
2016/12/06 05:44:21
"sion"? Do you mean version?
Have you actually te
xianglu
2016/12/08 01:20:54
Yes. The format is supported since 10.4.
|
| + base::scoped_nsobject<CIImage> ci_image([[CIImage alloc] |
| + initWithBitmapData:byte_data |
| + bytesPerRow:width * 4 |
| + size:CGSizeMake(width, height) |
| + format:kCIFormatRGBA8 |
| + colorSpace:colorspace]); |
| + if (!ci_image) { |
| + DLOG(ERROR) << "Failed to create CIImage"; |
| + return; |
| + } |
| + |
| + NSArray* const features = [detector_ featuresInImage:ci_image]; |
| + |
| + blink::mojom::FaceDetectionResultPtr faces = |
| + blink::mojom::FaceDetectionResult::New(); |
| + for (CIFaceFeature* const f in features) { |
| + // In the default Core Graphics coordinate space, the origin is located |
| + // in the lower-left corner, and thus |ci_image| is flipped vertically. |
| + // We need to adjust |y| coordinate of bounding box before sending it . |
|
Avi (use Gerrit)
2016/12/06 05:44:21
no space before the .
xianglu
2016/12/08 01:20:54
Done.
|
| + gfx::RectF boundingbox(f.bounds.origin.x, |
| + height - f.bounds.origin.y - f.bounds.size.height, |
| + f.bounds.size.width, f.bounds.size.height); |
| + faces->bounding_boxes.push_back(boundingbox); |
| + } |
| + scoped_callback.Run(std::move(faces)); |
| +} |
| + |
| +void FaceDetectionImplMac::RunCallbackWithFaces( |
| + const DetectCallback& callback, |
| + blink::mojom::FaceDetectionResultPtr faces) { |
| + callback.Run(std::move(faces)); |
| +} |
| + |
| +void FaceDetectionImplMac::RunCallbackWithNoFaces( |
| + const DetectCallback& callback) { |
| + callback.Run(blink::mojom::FaceDetectionResult::New()); |
| +} |
| + |
| +} // namespace shape_detection |