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..e32a5e0a6d3bddc5c6046ffa03eef3020fd75745 |
| --- /dev/null |
| +++ b/services/shape_detection/face_detection_impl_mac.mm |
| @@ -0,0 +1,111 @@ |
| +// 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 "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 s |
|
mcasas
2016/12/06 00:04:24
nit: s/s/the/ (at the end of the sentence).
xianglu
2016/12/08 01:20:54
Done.
|
| +// same constant to support RGBA8 format in earlier versions. |
| +#if !defined(MAC_OS_X_VERSION_10_11) |
|
mcasas
2016/12/06 00:04:24
We should use here
#if MAC_OS_X_VERSION_MIN_REQUI
xianglu
2016/12/08 01:20:54
Done.
|
| +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) { |
| + blink::mojom::FaceDetectionResultPtr faces = |
| + blink::mojom::FaceDetectionResult::New(); |
| + |
| + 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"; |
| + callback.Run(std::move(faces)); |
|
mcasas
2016/12/06 00:04:23
Having to Run the callback with an empty Face arra
xianglu
2016/12/08 01:20:53
Done.
|
| + 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 redBufferHandle"; |
|
mcasas
2016/12/06 00:04:24
nit: s/redBufferHandle/SharedBuffer/ ?
xianglu
2016/12/08 01:20:53
Done.
|
| + if (!memory_size || memory_size != num_bytes.ValueOrDie()) { |
| + DLOG(ERROR) << "Invalid image size"; |
| + callback.Run(std::move(faces)); |
| + return; |
| + } |
| + |
| + std::unique_ptr<base::SharedMemory> shared_memory( |
| + new base::SharedMemory(memory_handle, true /* read_only */)); |
| + if (!shared_memory->Map(memory_size)) { |
| + DLOG(ERROR) << "Failed to map bytes from shared memory"; |
| + callback.Run(std::move(faces)); |
| + 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. |
| + base::scoped_nsobject<CIImage> ciimage([[CIImage alloc] |
|
mcasas
2016/12/06 00:04:23
s/ciimage/ci_image/
xianglu
2016/12/08 01:20:53
Done.
|
| + initWithBitmapData:byte_data |
| + bytesPerRow:width * 4 |
| + size:CGSizeMake(width, height) |
| + format:kCIFormatRGBA8 |
| + colorSpace:colorspace]); |
| + if (!ciimage) { |
| + DLOG(ERROR) << "Failed to create CIImage"; |
| + callback.Run(std::move(faces)); |
| + return; |
| + } |
| + |
| + NSArray* const features = [detector_ featuresInImage:ciimage]; |
| + |
| + for (CIFaceFeature* const f in features) { |
| + // In the default Core Graphics coordinate space, the origin is located |
| + // in the lower-left corner, and thus |ciimage| is flipped vertically. |
| + // We need to adjust |y| coordinate of bounding box before sending it . |
| + 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); |
| + } |
| + callback.Run(std::move(faces)); |
| +} |
| + |
| +} // namespace shape_detection |