blob: 67cddfdd8b7153ad82ca3993a88bd2a7bc16310d [file] [log] [blame]
// Copyright (c) 2012 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.
#import "media/video/capture/mac/video_capture_device_qtkit_mac.h"
#import <QTKit/QTKit.h>
#include "base/logging.h"
#include "media/video/capture/mac/video_capture_device_mac.h"
#include "media/video/capture/video_capture_device.h"
#include "media/video/capture/video_capture_types.h"
@implementation VideoCaptureDeviceQTKit
#pragma mark Class methods
+ (NSDictionary *)deviceNames {
NSArray *captureDevices =
[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
NSMutableDictionary *deviceNames =
[[[NSMutableDictionary alloc] init] autorelease];
for (QTCaptureDevice* device in captureDevices) {
NSString* qtDeviceName = [device localizedDisplayName];
NSString* qtUniqueId = [device uniqueID];
[deviceNames setObject:qtDeviceName forKey:qtUniqueId];
}
return deviceNames;
}
#pragma mark Public methods
- (id)initWithFrameReceiver:(media::VideoCaptureDeviceMac *)frameReceiver {
self = [super init];
if (self) {
frameReceiver_ = frameReceiver;
}
return self;
}
- (void)dealloc {
[captureSession_ release];
[captureDeviceInput_ release];
[super dealloc];
}
- (BOOL)setCaptureDevice:(NSString *)deviceId {
if (deviceId) {
// Set the capture device.
if (captureDeviceInput_) {
DLOG(ERROR) << "Video capture device already set.";
return NO;
}
NSArray *captureDevices =
[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo];
NSArray *captureDevicesNames =
[captureDevices valueForKey:@"uniqueID"];
NSUInteger index = [captureDevicesNames indexOfObject:deviceId];
if (index == NSNotFound) {
DLOG(ERROR) << "Video capture device not found.";
return NO;
}
QTCaptureDevice *device = [captureDevices objectAtIndex:index];
NSError *error;
if (![device open:&error]) {
DLOG(ERROR) << "Could not open video capture device."
<< [[error localizedDescription] UTF8String];
return NO;
}
captureDeviceInput_ = [[QTCaptureDeviceInput alloc] initWithDevice:device];
captureSession_ = [[QTCaptureSession alloc] init];
QTCaptureDecompressedVideoOutput *captureDecompressedOutput =
[[[QTCaptureDecompressedVideoOutput alloc] init] autorelease];
[captureDecompressedOutput setDelegate:self];
if (![captureSession_ addOutput:captureDecompressedOutput error:&error]) {
DLOG(ERROR) << "Could not connect video capture output."
<< [[error localizedDescription] UTF8String];
return NO;
}
return YES;
} else {
// Remove the previously set capture device.
if (!captureDeviceInput_) {
DLOG(ERROR) << "No video capture device set.";
return YES;
}
if ([[captureSession_ inputs] count] > 0) {
// The device is still running.
[self stopCapture];
}
[captureSession_ release];
captureSession_ = nil;
[captureDeviceInput_ release];
captureDeviceInput_ = nil;
return YES;
}
}
- (BOOL)setCaptureHeight:(int)height width:(int)width frameRate:(int)frameRate {
if (!captureDeviceInput_) {
DLOG(ERROR) << "No video capture device set.";
return NO;
}
if ([[captureSession_ outputs] count] != 1) {
DLOG(ERROR) << "Video capture capabilities already set.";
return NO;
}
frameWidth_ = width;
frameHeight_ = height;
frameRate_ = frameRate;
// Set up desired output properties.
NSDictionary *captureDictionary =
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:frameWidth_],
(id)kCVPixelBufferWidthKey,
[NSNumber numberWithDouble:frameHeight_],
(id)kCVPixelBufferHeightKey,
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA],
(id)kCVPixelBufferPixelFormatTypeKey,
nil];
[[[captureSession_ outputs] objectAtIndex:0]
setPixelBufferAttributes:captureDictionary];
return YES;
}
- (BOOL)startCapture {
if ([[captureSession_ outputs] count] == 0) {
// Capture properties not set.
DLOG(ERROR) << "Video capture device not initialized.";
return NO;
}
if ([[captureSession_ inputs] count] == 0) {
NSError *error;
if (![captureSession_ addInput:captureDeviceInput_ error:&error]) {
DLOG(ERROR) << "Could not connect video capture device."
<< [[error localizedDescription] UTF8String];
return NO;
}
[captureSession_ startRunning];
}
return YES;
}
- (void)stopCapture {
if ([[captureSession_ inputs] count] == 1) {
[captureSession_ removeInput:captureDeviceInput_];
[captureSession_ stopRunning];
}
}
// |captureOutput| is called by the capture device to deliver a new frame.
- (void)captureOutput:(QTCaptureOutput *)captureOutput
didOutputVideoFrame:(CVImageBufferRef)videoFrame
withSampleBuffer:(QTSampleBuffer *)sampleBuffer
fromConnection:(QTCaptureConnection *)connection {
if(!frameReceiver_) {
return;
}
// Lock the frame and calculate frame size.
const int kLockFlags = 0;
if (CVPixelBufferLockBaseAddress(videoFrame, kLockFlags)
== kCVReturnSuccess) {
void *baseAddress = CVPixelBufferGetBaseAddress(videoFrame);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(videoFrame);
int frameHeight = CVPixelBufferGetHeight(videoFrame);
int frameSize = bytesPerRow * frameHeight;
media::VideoCaptureCapability captureCapability;
captureCapability.width = frameWidth_;
captureCapability.height = frameHeight_;
captureCapability.frame_rate = frameRate_;
captureCapability.color = media::VideoCaptureCapability::kARGB;
captureCapability.expected_capture_delay = 0;
captureCapability.interlaced = false;
// Deliver the captured video frame.
frameReceiver_->ReceiveFrame(static_cast<UInt8*>(baseAddress), frameSize,
captureCapability);
CVPixelBufferUnlockBaseAddress(videoFrame, kLockFlags);
}
}
@end