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

Unified Diff: media/capture/video/mac/video_capture_device_avfoundation_mac.mm

Issue 2146973002: RELAND: ImageCapture: Implement takePhoto() for Mac AVFoundation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: add a [captureSession_ canAddOutput:stillImageOutput_] guard Created 4 years, 5 months 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: media/capture/video/mac/video_capture_device_avfoundation_mac.mm
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
index 0f89a03119e5b3b75c9de35ddbcc961923fd4bc3..dc711cd6aef0664bbaf4d61d114da5a0c1798e6f 100644
--- a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
+++ b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
@@ -95,8 +95,6 @@ void MaybeWriteUma(int number_of_devices, int number_of_suspended_devices) {
}
}
-} // anonymous namespace
-
// This function translates Mac Core Video pixel formats to Chromium pixel
// formats.
media::VideoPixelFormat FourCCToChromiumPixelFormat(FourCharCode code) {
@@ -112,6 +110,26 @@ media::VideoPixelFormat FourCCToChromiumPixelFormat(FourCharCode code) {
}
}
+// Extracts |base_address| and |length| out of a SampleBuffer.
+void ExtractBaseAddressAndLength(
+ char** base_address,
+ size_t* length,
+ CoreMediaGlue::CMSampleBufferRef sample_buffer) {
+ CoreMediaGlue::CMBlockBufferRef block_buffer =
+ CoreMediaGlue::CMSampleBufferGetDataBuffer(sample_buffer);
+ DCHECK(block_buffer);
+
+ size_t length_at_offset;
+ const OSStatus status = CoreMediaGlue::CMBlockBufferGetDataPointer(
+ block_buffer, 0, &length_at_offset, length, base_address);
+ DCHECK_EQ(noErr, status);
+ // Expect the (M)JPEG data to be available as a contiguous reference, i.e.
+ // not covered by multiple memory blocks.
+ DCHECK_EQ(length_at_offset, *length);
+}
+
+} // anonymous namespace
+
@implementation VideoCaptureDeviceAVFoundation
#pragma mark Class methods
@@ -217,6 +235,8 @@ media::VideoPixelFormat FourCCToChromiumPixelFormat(FourCharCode code) {
// No need to release |captureDeviceInput_|, is owned by the session.
captureDeviceInput_ = nil;
}
+ if (stillImageOutput_)
+ [captureSession_ removeOutput:stillImageOutput_];
return YES;
}
@@ -261,6 +281,14 @@ media::VideoPixelFormat FourCCToChromiumPixelFormat(FourCharCode code) {
queue:dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
[captureSession_ addOutput:captureVideoDataOutput_];
+
+ // Create and plug the still image capture output. This should happen in
+ // advance of the actual picture to allow for the 3A to stabilize.
+ stillImageOutput_.reset(
+ [[AVFoundationGlue::AVCaptureStillImageOutputClass() alloc] init]);
+ if ([captureSession_ canAddOutput:stillImageOutput_])
+ [captureSession_ addOutput:stillImageOutput_];
+
return YES;
}
@@ -359,6 +387,48 @@ media::VideoPixelFormat FourCCToChromiumPixelFormat(FourCharCode code) {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
+- (void)takePhoto {
+ DCHECK(main_thread_checker_.CalledOnValidThread());
+ DCHECK([captureSession_ isRunning]);
+
+ DCHECK_EQ(1u, [[stillImageOutput_ connections] count]);
+ CrAVCaptureConnection* const connection =
+ [[stillImageOutput_ connections] firstObject];
+ if (!connection) {
+ base::AutoLock lock(lock_);
+ frameReceiver_->OnPhotoError();
+ return;
+ }
+
+ const auto handler = ^(CoreMediaGlue::CMSampleBufferRef sampleBuffer,
+ NSError* error) {
+ base::AutoLock lock(lock_);
+ if (!frameReceiver_)
+ return;
+ if (error != nil) {
+ frameReceiver_->OnPhotoError();
+ return;
+ }
+
+ // Recommended compressed pixel format is JPEG, we don't expect surprises.
+ // TODO(mcasas): Consider using [1] for merging EXIF output information:
+ // [1] +(NSData*)jpegStillImageNSDataRepresentation:jpegSampleBuffer;
+ DCHECK_EQ(
+ CoreMediaGlue::kCMVideoCodecType_JPEG,
+ CoreMediaGlue::CMFormatDescriptionGetMediaSubType(
+ CoreMediaGlue::CMSampleBufferGetFormatDescription(sampleBuffer)));
+
+ char* baseAddress = 0;
+ size_t length = 0;
+ ExtractBaseAddressAndLength(&baseAddress, &length, sampleBuffer);
+ frameReceiver_->OnPhotoTaken(reinterpret_cast<uint8_t*>(baseAddress),
+ length, "image/jpeg");
+ };
+
+ [stillImageOutput_ captureStillImageAsynchronouslyFromConnection:connection
+ completionHandler:handler];
+}
+
#pragma mark Private methods
// |captureOutput| is called by the capture device to deliver a new frame.
@@ -381,17 +451,7 @@ didOutputSampleBuffer:(CoreMediaGlue::CMSampleBufferRef)sampleBuffer
size_t frameSize = 0;
CVImageBufferRef videoFrame = nil;
if (fourcc == CoreMediaGlue::kCMVideoCodecType_JPEG_OpenDML) {
- // If MJPEG, use block buffer instead of pixel buffer.
- CoreMediaGlue::CMBlockBufferRef blockBuffer =
- CoreMediaGlue::CMSampleBufferGetDataBuffer(sampleBuffer);
- if (blockBuffer) {
- size_t lengthAtOffset;
- CoreMediaGlue::CMBlockBufferGetDataPointer(
- blockBuffer, 0, &lengthAtOffset, &frameSize, &baseAddress);
- // Expect the MJPEG data to be available as a contiguous reference, i.e.
- // not covered by multiple memory blocks.
- CHECK_EQ(lengthAtOffset, frameSize);
- }
+ ExtractBaseAddressAndLength(&baseAddress, &frameSize, sampleBuffer);
} else {
videoFrame = CoreMediaGlue::CMSampleBufferGetImageBuffer(sampleBuffer);
// Lock the frame and calculate frame size.
« no previous file with comments | « media/capture/video/mac/video_capture_device_avfoundation_mac.h ('k') | media/capture/video/mac/video_capture_device_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698