Removed Mac capture crash and memory leak.
BUG=1697,1761 R=xians@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1465005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4023 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
a6ff84503e
commit
bb984f516e
@ -12,15 +12,12 @@
|
||||
#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_MAC_QTKIT_VIDEO_CAPTURE_QTKIT_H_
|
||||
|
||||
#import <QTKit/QTKit.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../video_capture_impl.h"
|
||||
#include "video_capture_qtkit_utility.h"
|
||||
#include "../../device_info_impl.h"
|
||||
#include "webrtc/modules/video_capture/video_capture_impl.h"
|
||||
#include "webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_utility.h"
|
||||
#include "webrtc/modules/video_capture/device_info_impl.h"
|
||||
|
||||
|
||||
// Forward declaraion
|
||||
@class VideoCaptureMacQTKitObjC;
|
||||
@class VideoCaptureMacQTKitInfoObjC;
|
||||
|
||||
|
||||
@ -45,6 +45,7 @@ VideoCaptureMacQTKit::~VideoCaptureMacQTKit()
|
||||
"~VideoCaptureMacQTKit() called");
|
||||
if(_captureDevice)
|
||||
{
|
||||
[_captureDevice registerOwner:nil];
|
||||
[_captureDevice stopCapture];
|
||||
[_captureDevice release];
|
||||
}
|
||||
@ -79,12 +80,7 @@ int32_t VideoCaptureMacQTKit::Init(
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(-1 == [[_captureDevice registerOwner:this]intValue])
|
||||
{
|
||||
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, id,
|
||||
"Failed to register owner for _captureDevice");
|
||||
return -1;
|
||||
}
|
||||
[_captureDevice registerOwner:this];
|
||||
|
||||
if(0 == strcmp((char*)iDeviceUniqueIdUTF8, ""))
|
||||
{
|
||||
@ -148,8 +144,7 @@ int32_t VideoCaptureMacQTKit::Init(
|
||||
|
||||
// at this point we know that the user has passed in a valid camera. Let's
|
||||
// set it as the current.
|
||||
if(-1 == [[_captureDevice
|
||||
setCaptureDeviceById:(char*)deviceUniqueIdUTF8]intValue])
|
||||
if(![_captureDevice setCaptureDeviceById:(char*)deviceUniqueIdUTF8])
|
||||
{
|
||||
strcpy((char*)_deviceUniqueId, (char*)deviceUniqueIdUTF8);
|
||||
WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
|
||||
@ -174,19 +169,11 @@ int32_t VideoCaptureMacQTKit::StartCapture(
|
||||
_captureFrameRate = capability.maxFPS;
|
||||
_captureDelay = 120;
|
||||
|
||||
if(-1 == [[_captureDevice setCaptureHeight:_captureHeight
|
||||
AndWidth:_captureWidth AndFrameRate:_captureFrameRate]intValue])
|
||||
{
|
||||
WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
|
||||
"Could not set width=%d height=%d frameRate=%d",
|
||||
_captureWidth, _captureHeight, _captureFrameRate);
|
||||
return -1;
|
||||
}
|
||||
[_captureDevice setCaptureHeight:_captureHeight
|
||||
width:_captureWidth
|
||||
frameRate:_captureFrameRate];
|
||||
|
||||
if(-1 == [[_captureDevice startCapture]intValue])
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
[_captureDevice startCapture];
|
||||
_isCapturing = true;
|
||||
return 0;
|
||||
}
|
||||
@ -194,7 +181,6 @@ int32_t VideoCaptureMacQTKit::StartCapture(
|
||||
int32_t VideoCaptureMacQTKit::StopCapture()
|
||||
{
|
||||
[_captureDevice stopCapture];
|
||||
|
||||
_isCapturing = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -23,58 +23,38 @@
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
|
||||
#import "video_capture_recursive_lock.h"
|
||||
|
||||
#include "video_capture_qtkit.h"
|
||||
|
||||
@interface VideoCaptureMacQTKitObjC : NSObject{
|
||||
// class properties
|
||||
bool _capturing;
|
||||
int _frameRate;
|
||||
int _frameWidth;
|
||||
int _frameHeight;
|
||||
int _framesDelivered;
|
||||
int _framesRendered;
|
||||
bool _OSSupported;
|
||||
bool _captureInitialized;
|
||||
|
||||
// WebRTC Custom classes
|
||||
webrtc::videocapturemodule::VideoCaptureMacQTKit* _owner;
|
||||
VideoCaptureRecursiveLock* _rLock;
|
||||
|
||||
// QTKit variables
|
||||
QTCaptureSession* _captureSession;
|
||||
QTCaptureDeviceInput* _captureVideoDeviceInput;
|
||||
QTCaptureDecompressedVideoOutput* _captureDecompressedVideoOutput;
|
||||
NSArray* _captureDevices;
|
||||
int _captureDeviceCount;
|
||||
char _captureDeviceNameUTF8[1024];
|
||||
char _captureDeviceNameUniqueID[1024];
|
||||
@interface VideoCaptureMacQTKitObjC : NSObject {
|
||||
bool _capturing;
|
||||
int _frameRate;
|
||||
int _frameWidth;
|
||||
int _frameHeight;
|
||||
int _framesDelivered;
|
||||
int _framesRendered;
|
||||
bool _captureInitialized;
|
||||
|
||||
webrtc::videocapturemodule::VideoCaptureMacQTKit* _owner;
|
||||
NSLock* lock_;
|
||||
|
||||
QTCaptureSession* _captureSession;
|
||||
QTCaptureDeviceInput* _captureVideoDeviceInput;
|
||||
QTCaptureDecompressedVideoOutput* _captureDecompressedVideoOutput;
|
||||
NSArray* _captureDevices;
|
||||
int _captureDeviceCount;
|
||||
char _captureDeviceNameUTF8[1024];
|
||||
char _captureDeviceNameUniqueID[1024];
|
||||
}
|
||||
/**************************************************************************
|
||||
*
|
||||
* The following functions are considered to be private.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
- (NSNumber*)getCaptureDevices;
|
||||
- (NSNumber*)initializeVideoCapture;
|
||||
- (NSNumber*)initializeVariables;
|
||||
- (void)checkOSSupported;
|
||||
- (void)getCaptureDevices;
|
||||
- (BOOL)initializeVideoCapture;
|
||||
- (BOOL)initializeVariables;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* The following functions are considered public and to be called by the VideoCaptureMacQTKit class.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
- (NSNumber*)registerOwner:(webrtc::videocapturemodule::VideoCaptureMacQTKit*)owner;
|
||||
- (NSNumber*)setCaptureDeviceById:(char*)uniqueId;
|
||||
- (NSNumber*)setCaptureHeight:(int)height AndWidth:(int)width AndFrameRate:(int)frameRate;
|
||||
- (NSNumber*)startCapture;
|
||||
- (NSNumber*)stopCapture;
|
||||
- (void)registerOwner:(webrtc::videocapturemodule::VideoCaptureMacQTKit*)owner;
|
||||
- (BOOL)setCaptureDeviceById:(char*)uniqueId;
|
||||
- (void)setCaptureHeight:(int)height width:(int)width frameRate:(int)frameRate;
|
||||
- (void)startCapture;
|
||||
- (void)stopCapture;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -10,451 +10,250 @@
|
||||
|
||||
#define DEFAULT_CAPTURE_DEVICE_INDEX 1
|
||||
#define DEFAULT_FRAME_RATE 30
|
||||
#define DEFAULT_FRAME_WIDTH 352
|
||||
#define DEFAULT_FRAME_WIDTH 352
|
||||
#define DEFAULT_FRAME_HEIGHT 288
|
||||
#define ROTATE_CAPTURED_FRAME 1
|
||||
#define LOW_QUALITY 1
|
||||
|
||||
#import "video_capture_qtkit_objc.h"
|
||||
#include "video_capture_qtkit_utility.h"
|
||||
#include "trace.h"
|
||||
#import "webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.h"
|
||||
|
||||
#include "webrtc/system_wrappers/interface/trace.h"
|
||||
|
||||
using namespace webrtc;
|
||||
using namespace videocapturemodule;
|
||||
|
||||
@implementation VideoCaptureMacQTKitObjC
|
||||
|
||||
#pragma mark **** over-written OS methods
|
||||
|
||||
/// ***** Objective-C. Similar to C++ constructor, although must be invoked
|
||||
/// manually.
|
||||
/// ***** Potentially returns an instance of self
|
||||
-(id)init{
|
||||
self = [super init];
|
||||
if(nil != self)
|
||||
{
|
||||
[self checkOSSupported];
|
||||
[self initializeVariables];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
return self;
|
||||
-(id)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self initializeVariables];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/// ***** Objective-C. Similar to C++ destructor
|
||||
/// ***** Returns nothing
|
||||
- (void)dealloc {
|
||||
if(_captureSession)
|
||||
[_captureSession stopRunning];
|
||||
if (_captureSession)
|
||||
[_captureSession stopRunning];
|
||||
|
||||
if (_captureVideoDeviceInput)
|
||||
{
|
||||
if([[_captureVideoDeviceInput device] isOpen])
|
||||
[[_captureVideoDeviceInput device] close];
|
||||
if (_captureVideoDeviceInput) {
|
||||
if ([[_captureVideoDeviceInput device] isOpen])
|
||||
[[_captureVideoDeviceInput device] close];
|
||||
|
||||
[_captureVideoDeviceInput release];
|
||||
}
|
||||
[_captureVideoDeviceInput release];
|
||||
}
|
||||
|
||||
[_captureDecompressedVideoOutput release];
|
||||
[_captureSession release];
|
||||
[_captureDevices release];
|
||||
[_rLock release];
|
||||
[_captureDecompressedVideoOutput release];
|
||||
[_captureSession release];
|
||||
[_captureDevices release];
|
||||
|
||||
[super dealloc];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark **** public methods
|
||||
#pragma mark Public methods
|
||||
|
||||
|
||||
|
||||
/// ***** Registers the class's owner, which is where the delivered frames are
|
||||
/// sent
|
||||
/// ***** Returns 0 on success, -1 otherwise.
|
||||
- (NSNumber*)registerOwner:(VideoCaptureMacQTKit*)owner{
|
||||
if(!owner){
|
||||
return [NSNumber numberWithInt:-1];
|
||||
}
|
||||
_owner = owner;
|
||||
return [NSNumber numberWithInt:0];
|
||||
- (void)registerOwner:(VideoCaptureMacQTKit*)owner {
|
||||
[lock_ lock];
|
||||
_owner = owner;
|
||||
[lock_ unlock];
|
||||
}
|
||||
|
||||
/// ***** Sets the QTCaptureSession's input device from a char*
|
||||
/// ***** Sets several member variables. Can signal the error system if one has
|
||||
/// occurred
|
||||
/// ***** Returns 0 on success, -1 otherwise.
|
||||
- (NSNumber*)setCaptureDeviceById:(char*)uniqueId{
|
||||
if(NO == _OSSupported)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideoCapture, 0,
|
||||
"%s:%d OS version does not support necessary APIs",
|
||||
__FUNCTION__, __LINE__);
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
if(!uniqueId || (0 == strcmp("", uniqueId)))
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideoCapture, 0,
|
||||
"%s:%d \"\" was passed in for capture device name",
|
||||
__FUNCTION__, __LINE__);
|
||||
memset(_captureDeviceNameUTF8, 0, 1024);
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
if(0 == strcmp(uniqueId, _captureDeviceNameUniqueID))
|
||||
{
|
||||
// camera already set
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideoCapture, 0,
|
||||
"%s:%d Capture device is already set to %s", __FUNCTION__,
|
||||
__LINE__, _captureDeviceNameUTF8);
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
bool success = NO;
|
||||
QTCaptureDevice* tempCaptureDevice;
|
||||
for(int index = 0; index < _captureDeviceCount; index++)
|
||||
{
|
||||
tempCaptureDevice = (QTCaptureDevice*)[_captureDevices
|
||||
objectAtIndex:index];
|
||||
char tempCaptureDeviceId[1024] = "";
|
||||
[[tempCaptureDevice uniqueID]
|
||||
getCString:tempCaptureDeviceId maxLength:1024
|
||||
encoding:NSUTF8StringEncoding];
|
||||
if(0 == strcmp(uniqueId, tempCaptureDeviceId))
|
||||
{
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideoCapture, 0,
|
||||
"%s:%d Found capture device id %s as index %d",
|
||||
__FUNCTION__, __LINE__, tempCaptureDeviceId, index);
|
||||
success = YES;
|
||||
[[tempCaptureDevice localizedDisplayName]
|
||||
getCString:_captureDeviceNameUTF8
|
||||
maxLength:1024
|
||||
encoding:NSUTF8StringEncoding];
|
||||
[[tempCaptureDevice uniqueID]
|
||||
getCString:_captureDeviceNameUniqueID
|
||||
maxLength:1024
|
||||
encoding:NSUTF8StringEncoding];
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(NO == success)
|
||||
{
|
||||
// camera not found
|
||||
// nothing has been changed yet, so capture device will stay in it's
|
||||
// state
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideoCapture, 0,
|
||||
"%s:%d Capture device id %s was not found in list of "
|
||||
"available devices.", __FUNCTION__, __LINE__, uniqueId);
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
NSError* error;
|
||||
success = [tempCaptureDevice open:&error];
|
||||
if(!success)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceVideoCapture, 0,
|
||||
"%s:%d Failed to open capture device: %s",
|
||||
__FUNCTION__, __LINE__, _captureDeviceNameUTF8);
|
||||
return [NSNumber numberWithInt:-1];
|
||||
}
|
||||
|
||||
if(_captureVideoDeviceInput)
|
||||
{
|
||||
[_captureVideoDeviceInput release];
|
||||
}
|
||||
_captureVideoDeviceInput = [[QTCaptureDeviceInput alloc]
|
||||
initWithDevice:tempCaptureDevice];
|
||||
|
||||
success = [_captureSession addInput:_captureVideoDeviceInput error:&error];
|
||||
if(!success)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceVideoCapture, 0,
|
||||
"%s:%d Failed to add input from %s to the capture session",
|
||||
__FUNCTION__, __LINE__, _captureDeviceNameUTF8);
|
||||
return [NSNumber numberWithInt:-1];
|
||||
}
|
||||
|
||||
- (BOOL)setCaptureDeviceById:(char*)uniqueId {
|
||||
if (uniqueId == nil || !strcmp("", uniqueId)) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideoCapture, 0,
|
||||
"%s:%d successfully added capture device: %s", __FUNCTION__,
|
||||
__LINE__, _captureDeviceNameUTF8);
|
||||
return [NSNumber numberWithInt:0];
|
||||
"Incorrect capture id argument");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!strcmp(uniqueId, _captureDeviceNameUniqueID))
|
||||
return YES;
|
||||
|
||||
QTCaptureDevice* captureDevice;
|
||||
for(int index = 0; index < _captureDeviceCount; index++) {
|
||||
captureDevice = (QTCaptureDevice*)[_captureDevices objectAtIndex:index];
|
||||
char captureDeviceId[1024] = "";
|
||||
[[captureDevice uniqueID] getCString:captureDeviceId
|
||||
maxLength:1024
|
||||
encoding:NSUTF8StringEncoding];
|
||||
if (strcmp(uniqueId, captureDeviceId) == 0) {
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideoCapture, 0,
|
||||
"%s:%d Found capture device id %s as index %d",
|
||||
__FUNCTION__, __LINE__, captureDeviceId, index);
|
||||
[[captureDevice localizedDisplayName] getCString:_captureDeviceNameUTF8
|
||||
maxLength:1024
|
||||
encoding:NSUTF8StringEncoding];
|
||||
[[captureDevice uniqueID] getCString:_captureDeviceNameUniqueID
|
||||
maxLength:1024
|
||||
encoding:NSUTF8StringEncoding];
|
||||
break;
|
||||
}
|
||||
captureDevice = nil;
|
||||
}
|
||||
|
||||
if (!captureDevice)
|
||||
return NO;
|
||||
|
||||
NSError* error;
|
||||
if (![captureDevice open:&error]) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVideoCapture, 0,
|
||||
"Failed to open capture device: %s", _captureDeviceNameUTF8);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (_captureVideoDeviceInput) {
|
||||
[_captureVideoDeviceInput release];
|
||||
}
|
||||
_captureVideoDeviceInput =
|
||||
[[QTCaptureDeviceInput alloc] initWithDevice:captureDevice];
|
||||
|
||||
if (![_captureSession addInput:_captureVideoDeviceInput error:&error]) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceVideoCapture, 0,
|
||||
"Failed to add input from %s to the capture session",
|
||||
_captureDeviceNameUTF8);
|
||||
return NO;
|
||||
}
|
||||
|
||||
WEBRTC_TRACE(kTraceInfo, kTraceVideoCapture, 0,
|
||||
"%s:%d successfully added capture device: %s", __FUNCTION__,
|
||||
__LINE__, _captureDeviceNameUTF8);
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setCaptureHeight:(int)height width:(int)width frameRate:(int)frameRate {
|
||||
_frameWidth = width;
|
||||
_frameHeight = height;
|
||||
_frameRate = frameRate;
|
||||
|
||||
/// ***** Updates the capture devices size and frequency
|
||||
/// ***** Sets member variables _frame* and _captureDecompressedVideoOutput
|
||||
/// ***** Returns 0 on success, -1 otherwise.
|
||||
- (NSNumber*)setCaptureHeight:(int)height AndWidth:(int)width
|
||||
AndFrameRate:(int)frameRate{
|
||||
if(NO == _OSSupported)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
_frameWidth = width;
|
||||
_frameHeight = height;
|
||||
_frameRate = frameRate;
|
||||
|
||||
// TODO(mflodman) Check fps settings.
|
||||
// [_captureDecompressedVideoOutput
|
||||
// setMinimumVideoFrameInterval:(NSTimeInterval)1/(float)_frameRate];
|
||||
NSDictionary* captureDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithDouble:_frameWidth], (id)kCVPixelBufferWidthKey,
|
||||
[NSNumber numberWithDouble:_frameHeight], (id)kCVPixelBufferHeightKey,
|
||||
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB],
|
||||
(id)kCVPixelBufferPixelFormatTypeKey, nil];
|
||||
[_captureDecompressedVideoOutput performSelectorOnMainThread:@selector(setPixelBufferAttributes:) withObject:captureDictionary waitUntilDone:NO];
|
||||
// [_captureDecompressedVideoOutput setPixelBufferAttributes:captureDictionary];
|
||||
|
||||
|
||||
// these methods return type void so there isn't much we can do about
|
||||
// checking success
|
||||
return [NSNumber numberWithInt:0];
|
||||
NSDictionary* captureDictionary =
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithDouble:_frameWidth],
|
||||
(id)kCVPixelBufferWidthKey,
|
||||
[NSNumber numberWithDouble:_frameHeight],
|
||||
(id)kCVPixelBufferHeightKey,
|
||||
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB],
|
||||
(id)kCVPixelBufferPixelFormatTypeKey,
|
||||
nil];
|
||||
[_captureDecompressedVideoOutput
|
||||
performSelectorOnMainThread:@selector(setPixelBufferAttributes:)
|
||||
withObject:captureDictionary
|
||||
waitUntilDone:YES];
|
||||
}
|
||||
|
||||
/// ***** Starts the QTCaptureSession, assuming correct state. Also ensures that
|
||||
/// an NSRunLoop is running
|
||||
/// ***** Without and NSRunLoop to process events, the OS doesn't check for a
|
||||
/// new frame.
|
||||
/// ***** Sets member variables _capturing
|
||||
/// ***** Returns 0 on success, -1 otherwise.
|
||||
- (NSNumber*)startCapture{
|
||||
if(NO == _OSSupported)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
- (void)startCapture {
|
||||
if (_capturing)
|
||||
return;
|
||||
|
||||
if(YES == _capturing)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
// NSLog(@"--------------- before ---------------");
|
||||
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate distantFuture]];
|
||||
// NSLog(@"--------------- after ---------------");
|
||||
|
||||
if(NO == _captureInitialized)
|
||||
{
|
||||
// this should never be called..... it is initialized on class init
|
||||
[self initializeVideoCapture];
|
||||
}
|
||||
[_captureSession startRunning];
|
||||
|
||||
|
||||
_capturing = YES;
|
||||
|
||||
return [NSNumber numberWithInt:0];
|
||||
[_captureSession startRunning];
|
||||
_capturing = YES;
|
||||
}
|
||||
|
||||
/// ***** Stops the QTCaptureSession, assuming correct state
|
||||
/// ***** Sets member variables _capturing
|
||||
/// ***** Returns 0 on success, -1 otherwise.
|
||||
- (NSNumber*)stopCapture{
|
||||
- (void)stopCapture {
|
||||
if (!_capturing)
|
||||
return;
|
||||
|
||||
if(NO == _OSSupported)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
if(nil == _captureSession)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
if(NO == _capturing)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
if(YES == _capturing)
|
||||
{
|
||||
[_captureSession stopRunning];
|
||||
}
|
||||
|
||||
_capturing = NO;
|
||||
return [NSNumber numberWithInt:0];
|
||||
[_captureSession stopRunning];
|
||||
_capturing = NO;
|
||||
}
|
||||
|
||||
// ********** "private" functions below here **********
|
||||
#pragma mark **** "private" methods
|
||||
#pragma mark Private methods
|
||||
|
||||
/// ***** Class member variables are initialized here
|
||||
/// ***** Returns 0 on success, -1 otherwise.
|
||||
- (NSNumber*)initializeVariables{
|
||||
- (BOOL)initializeVariables {
|
||||
if (NSClassFromString(@"QTCaptureSession") == nil)
|
||||
return NO;
|
||||
|
||||
if(NO == _OSSupported)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
memset(_captureDeviceNameUTF8, 0, 1024);
|
||||
_framesDelivered = 0;
|
||||
_framesRendered = 0;
|
||||
_captureDeviceCount = 0;
|
||||
_capturing = NO;
|
||||
_captureInitialized = NO;
|
||||
_frameRate = DEFAULT_FRAME_RATE;
|
||||
_frameWidth = DEFAULT_FRAME_WIDTH;
|
||||
_frameHeight = DEFAULT_FRAME_HEIGHT;
|
||||
lock_ = [[NSLock alloc] init];
|
||||
_captureSession = [[QTCaptureSession alloc] init];
|
||||
_captureDecompressedVideoOutput =
|
||||
[[QTCaptureDecompressedVideoOutput alloc] init];
|
||||
[_captureDecompressedVideoOutput setDelegate:self];
|
||||
|
||||
memset(_captureDeviceNameUTF8, 0, 1024);
|
||||
_framesDelivered = 0;
|
||||
_framesRendered = 0;
|
||||
_captureDeviceCount = 0;
|
||||
_capturing = NO;
|
||||
_captureInitialized = NO;
|
||||
_frameRate = DEFAULT_FRAME_RATE;
|
||||
_frameWidth = DEFAULT_FRAME_WIDTH;
|
||||
_frameHeight = DEFAULT_FRAME_HEIGHT;
|
||||
_rLock = [[VideoCaptureRecursiveLock alloc] init];
|
||||
_captureSession = [[QTCaptureSession alloc] init];
|
||||
_captureDecompressedVideoOutput = [[QTCaptureDecompressedVideoOutput alloc]
|
||||
init];
|
||||
[_captureDecompressedVideoOutput setDelegate:self];
|
||||
|
||||
[self getCaptureDevices];
|
||||
[self initializeVideoCapture];
|
||||
|
||||
return [NSNumber numberWithInt:0];
|
||||
[self getCaptureDevices];
|
||||
if (![self initializeVideoCapture])
|
||||
return NO;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Checks to see if the QTCaptureSession framework is available in the OS
|
||||
// If it is not, isOSSupprted = NO.
|
||||
// Throughout the rest of the class isOSSupprted is checked and functions
|
||||
// are/aren't called depending
|
||||
// The user can use weak linking to the QTKit framework and run on older
|
||||
// versions of the OS. I.E. Backwards compaitibility
|
||||
// Returns nothing. Sets member variable
|
||||
- (void)checkOSSupported{
|
||||
- (void)getCaptureDevices {
|
||||
if (_captureDevices)
|
||||
[_captureDevices release];
|
||||
|
||||
Class osSupportedTest = NSClassFromString(@"QTCaptureSession");
|
||||
_OSSupported = NO;
|
||||
if(nil == osSupportedTest)
|
||||
{
|
||||
}
|
||||
_OSSupported = YES;
|
||||
_captureDevices = [[NSArray alloc] initWithArray:
|
||||
[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo]];
|
||||
|
||||
_captureDeviceCount = _captureDevices.count;
|
||||
}
|
||||
|
||||
/// ***** Retrieves the number of capture devices currently available
|
||||
/// ***** Stores them in an NSArray instance
|
||||
/// ***** Returns 0 on success, -1 otherwise.
|
||||
- (NSNumber*)getCaptureDevices{
|
||||
- (BOOL)initializeVideoCapture{
|
||||
NSDictionary *captureDictionary =
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithDouble:_frameWidth],
|
||||
(id)kCVPixelBufferWidthKey,
|
||||
[NSNumber numberWithDouble:_frameHeight],
|
||||
(id)kCVPixelBufferHeightKey,
|
||||
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB],
|
||||
(id)kCVPixelBufferPixelFormatTypeKey,
|
||||
nil];
|
||||
|
||||
if(NO == _OSSupported)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
[_captureDecompressedVideoOutput setPixelBufferAttributes:captureDictionary];
|
||||
[_captureDecompressedVideoOutput setAutomaticallyDropsLateVideoFrames:YES];
|
||||
[_captureDecompressedVideoOutput
|
||||
setMinimumVideoFrameInterval:(NSTimeInterval)1/(float)_frameRate];
|
||||
|
||||
if(_captureDevices)
|
||||
{
|
||||
[_captureDevices release];
|
||||
}
|
||||
_captureDevices = [[NSArray alloc] initWithArray:
|
||||
[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeVideo]];
|
||||
NSError *error;
|
||||
if (![_captureSession addOutput:_captureDecompressedVideoOutput error:&error])
|
||||
return NO;
|
||||
|
||||
_captureDeviceCount = _captureDevices.count;
|
||||
if(_captureDeviceCount < 1)
|
||||
{
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
return [NSNumber numberWithInt:0];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// Initializes a QTCaptureSession (member variable) to deliver frames via
|
||||
// callback
|
||||
// QTCapture* member variables affected
|
||||
// The image format and frequency are setup here
|
||||
// Returns 0 on success, -1 otherwise.
|
||||
- (NSNumber*)initializeVideoCapture{
|
||||
|
||||
if(YES == _captureInitialized)
|
||||
{
|
||||
return [NSNumber numberWithInt:-1];
|
||||
}
|
||||
|
||||
bool success = NO;
|
||||
NSError* error;
|
||||
|
||||
[_captureDecompressedVideoOutput setPixelBufferAttributes:
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithDouble:_frameWidth], (id)kCVPixelBufferWidthKey,
|
||||
[NSNumber numberWithDouble:_frameHeight], (id)kCVPixelBufferHeightKey,
|
||||
[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB],
|
||||
(id)kCVPixelBufferPixelFormatTypeKey, nil]];
|
||||
|
||||
// TODO(mflodman) Check fps settings.
|
||||
//[_captureDecompressedVideoOutput setMinimumVideoFrameInterval:
|
||||
// (NSTimeInterval)1/(float)_frameRate];
|
||||
//[_captureDecompressedVideoOutput setAutomaticallyDropsLateVideoFrames:YES];
|
||||
|
||||
success = [_captureSession addOutput:_captureDecompressedVideoOutput
|
||||
error:&error];
|
||||
|
||||
if(!success)
|
||||
{
|
||||
return [NSNumber numberWithInt:-1];
|
||||
}
|
||||
|
||||
_captureInitialized = YES;
|
||||
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
|
||||
// This is the callback that is called when the OS has a frame to deliver to us.
|
||||
// Starts being called when [_captureSession startRunning] is called. Stopped
|
||||
// similarly.
|
||||
// Parameter videoFrame contains the image. The format, size, and frequency
|
||||
// were setup earlier.
|
||||
// Returns 0 on success, -1 otherwise.
|
||||
- (void)captureOutput:(QTCaptureOutput *)captureOutput
|
||||
didOutputVideoFrame:(CVImageBufferRef)videoFrame
|
||||
didDropVideoFrameWithSampleBuffer:(QTSampleBuffer *)sampleBuffer
|
||||
fromConnection:(QTCaptureConnection *)connection {
|
||||
// TODO(mflodman) Experiment more when this happens.
|
||||
}
|
||||
|
||||
- (void)captureOutput:(QTCaptureOutput *)captureOutput
|
||||
didOutputVideoFrame:(CVImageBufferRef)videoFrame
|
||||
withSampleBuffer:(QTSampleBuffer *)sampleBuffer
|
||||
fromConnection:(QTCaptureConnection *)connection{
|
||||
fromConnection:(QTCaptureConnection *)connection {
|
||||
|
||||
if(YES == [_rLock tryLock])
|
||||
{
|
||||
[_rLock lock];
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
[lock_ lock];
|
||||
if (!_owner) {
|
||||
[lock_ unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
if(NO == _OSSupported)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int LOCK_FLAGS = 0; // documentation says to pass 0
|
||||
|
||||
// get size of the frame
|
||||
CVPixelBufferLockBaseAddress(videoFrame, LOCK_FLAGS);
|
||||
void* baseAddress = CVPixelBufferGetBaseAddress(videoFrame);
|
||||
const int kFlags = 0;
|
||||
if (CVPixelBufferLockBaseAddress(videoFrame, kFlags) == kCVReturnSuccess) {
|
||||
void *baseAddress = CVPixelBufferGetBaseAddress(videoFrame);
|
||||
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(videoFrame);
|
||||
int frameHeight = CVPixelBufferGetHeight(videoFrame);
|
||||
CVPixelBufferUnlockBaseAddress(videoFrame, LOCK_FLAGS);
|
||||
int frameSize = bytesPerRow * frameHeight;
|
||||
|
||||
if(_owner)
|
||||
{
|
||||
VideoCaptureCapability tempCaptureCapability;
|
||||
tempCaptureCapability.width = _frameWidth;
|
||||
tempCaptureCapability.height = _frameHeight;
|
||||
tempCaptureCapability.maxFPS = _frameRate;
|
||||
// TODO(wu) : Update actual type and not hard-coded value.
|
||||
tempCaptureCapability.rawType = kVideoBGRA;
|
||||
|
||||
int frameSize = bytesPerRow * frameHeight; // 32 bit ARGB format
|
||||
CVBufferRetain(videoFrame);
|
||||
VideoCaptureCapability tempCaptureCapability;
|
||||
tempCaptureCapability.width = _frameWidth;
|
||||
tempCaptureCapability.height = _frameHeight;
|
||||
tempCaptureCapability.maxFPS = _frameRate;
|
||||
// TODO(wu) : Update actual type and not hard-coded value.
|
||||
tempCaptureCapability.rawType = kVideoBGRA;
|
||||
|
||||
_owner->IncomingFrame((unsigned char*)baseAddress,
|
||||
frameSize,
|
||||
tempCaptureCapability,
|
||||
0);
|
||||
|
||||
CVBufferRelease(videoFrame);
|
||||
}
|
||||
|
||||
_framesDelivered++;
|
||||
_framesRendered++;
|
||||
|
||||
if(YES == [_rLock locked])
|
||||
{
|
||||
[_rLock unlock];
|
||||
}
|
||||
_owner->IncomingFrame((unsigned char*)baseAddress, frameSize,
|
||||
tempCaptureCapability, 0);
|
||||
CVPixelBufferUnlockBaseAddress(videoFrame, kFlags);
|
||||
}
|
||||
[lock_ unlock];
|
||||
_framesDelivered++;
|
||||
_framesRendered++;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
//
|
||||
// video_capture_recursive_lock.h
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_MAC_QTKIT_VIDEO_CAPTURE_RECURSIVE_LOCK_H_
|
||||
#define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_MAC_QTKIT_VIDEO_CAPTURE_RECURSIVE_LOCK_H_
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface VideoCaptureRecursiveLock : NSRecursiveLock <NSLocking> {
|
||||
BOOL _locked;
|
||||
}
|
||||
|
||||
@property BOOL locked;
|
||||
|
||||
- (void)lock;
|
||||
- (void)unlock;
|
||||
|
||||
@end
|
||||
|
||||
#endif // WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_MAC_QTKIT_VIDEO_CAPTURE_RECURSIVE_LOCK_H_
|
||||
@ -1,33 +0,0 @@
|
||||
//
|
||||
// video_capture_recursive_lock.mm
|
||||
//
|
||||
//
|
||||
|
||||
#import "video_capture_recursive_lock.h"
|
||||
|
||||
@implementation VideoCaptureRecursiveLock
|
||||
|
||||
@synthesize locked = _locked;
|
||||
|
||||
- (id)init{
|
||||
self = [super init];
|
||||
if(nil == self){
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self setLocked:NO];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)lock{
|
||||
[self setLocked:YES];
|
||||
[super lock];
|
||||
}
|
||||
|
||||
- (void)unlock{
|
||||
[self setLocked:NO];
|
||||
[super unlock];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@ -63,8 +63,6 @@
|
||||
'mac/qtkit/video_capture_qtkit_objc.h',
|
||||
'mac/qtkit/video_capture_qtkit_objc.mm',
|
||||
'mac/qtkit/video_capture_qtkit_utility.h',
|
||||
'mac/qtkit/video_capture_recursive_lock.h',
|
||||
'mac/qtkit/video_capture_recursive_lock.mm',
|
||||
'mac/video_capture_mac.mm',
|
||||
],
|
||||
'include_dirs': [
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user