fix cap_qtkit.mm for multithreaded applications

cap_qtkit does not work when the capture is run outside of the main
thread.
If the capture is launched in a separate thread, then [NSRunLoop
currentRunLoop] is not the same as in the main thread, and has no timer.
see
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/F
oundation/Classes/nsrunloop_Class/Reference/Reference.html
"If no input sources or timers are attached to the run loop, this
method exits immediately"

Using usleep() (which I previously proposed, and was reverted) is not a
good alternative, because it may block the GUI.

Here is the new proposed solution:
- create a dummy timer so that runUntilDate does not exit immediately
- simplify the loop by using runUntilDate instead of runMode:beforeDate
- fix potential memory leaks (pointed out by Xcode's static analysis)
- fix init to follow Objective-C guidelines
- fax warnings about conversions from size_t to int
This commit is contained in:
Frédéric Devernay 2013-07-26 18:39:03 +02:00
parent d945b20db9
commit 4ad12a680c

View File

@ -277,11 +277,17 @@ bool CvCaptureCAM::grabFrame(double timeOut) {
double sleepTime = 0.005;
double total = 0;
NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:sleepTime];
while (![capture updateImage] && (total += sleepTime)<=timeOut &&
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
beforeDate:loopUntil])
loopUntil = [NSDate dateWithTimeIntervalSinceNow:sleepTime];
// If the capture is launched in a separate thread, then
// [NSRunLoop currentRunLoop] is not the same as in the main thread, and has no timer.
//see https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsrunloop_Class/Reference/Reference.html
// "If no input sources or timers are attached to the run loop, this
// method exits immediately"
// using usleep() is not a good alternative, because it may block the GUI.
// Create a dummy timer so that runUntilDate does not exit immediately:
[NSTimer scheduledTimerWithTimeInterval:100 target:nil selector:@selector(doFireTimer:) userInfo:nil repeats:YES];
while (![capture updateImage] && (total += sleepTime)<=timeOut) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:sleepTime]];
}
[localpool drain];
@ -326,9 +332,11 @@ int CvCaptureCAM::startCaptureDevice(int cameraNum) {
}
if (cameraNum >= 0) {
int nCameras = [devices count];
if( cameraNum < 0 || cameraNum >= nCameras )
NSUInteger nCameras = [devices count];
if( cameraNum < 0 || cameraNum >= nCameras ) {
[localpool drain];
return 0;
}
device = [devices objectAtIndex:cameraNum] ;
} else {
device = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo] ;
@ -392,6 +400,7 @@ int CvCaptureCAM::startCaptureDevice(int cameraNum) {
grabFrame(60);
[localpool drain];
return 1;
}
@ -415,6 +424,7 @@ void CvCaptureCAM::setWidthHeight() {
double CvCaptureCAM::getProperty(int property_id){
int retval;
NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
NSArray* connections = [mCaptureDeviceInput connections];
@ -424,15 +434,18 @@ double CvCaptureCAM::getProperty(int property_id){
int width=s1.width, height=s1.height;
switch (property_id) {
case CV_CAP_PROP_FRAME_WIDTH:
return width;
retval = width;
break;
case CV_CAP_PROP_FRAME_HEIGHT:
return height;
retval = height;
break;
default:
return 0;
retval = 0;
break;
}
[localpool drain];
return retval;
}
bool CvCaptureCAM::setProperty(int property_id, double value) {
@ -480,13 +493,15 @@ bool CvCaptureCAM::setProperty(int property_id, double value) {
@implementation CaptureDelegate
- (id)init {
[super init];
newFrame = 0;
imagedata = NULL;
bgr_imagedata = NULL;
currSize = 0;
image = NULL;
bgr_image = NULL;
self = [super init];
if (self) {
newFrame = 0;
imagedata = NULL;
bgr_imagedata = NULL;
currSize = 0;
image = NULL;
bgr_image = NULL;
}
return self;
}
@ -561,26 +576,26 @@ didDropVideoFrameWithSampleBuffer:(QTSampleBuffer *)sampleBuffer
memcpy(imagedata, baseaddress, currSize);
if (image == NULL) {
image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 4);
image = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, 4);
}
image->width =width;
image->height = height;
image->width = (int)width;
image->height = (int)height;
image->nChannels = 4;
image->depth = IPL_DEPTH_8U;
image->widthStep = rowBytes;
image->widthStep = (int)rowBytes;
image->imageData = imagedata;
image->imageSize = currSize;
image->imageSize = (int)currSize;
if (bgr_image == NULL) {
bgr_image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 3);
bgr_image = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, 3);
}
bgr_image->width =width;
bgr_image->height = height;
bgr_image->width = (int)width;
bgr_image->height = (int)height;
bgr_image->nChannels = 3;
bgr_image->depth = IPL_DEPTH_8U;
bgr_image->widthStep = rowBytes;
bgr_image->widthStep = (int)rowBytes;
bgr_image->imageData = bgr_imagedata;
bgr_image->imageSize = currSize;
bgr_image->imageSize = (int)currSize;
cvCvtColor(image, bgr_image, CV_BGRA2BGR);
@ -734,29 +749,29 @@ IplImage* CvCaptureFile::retrieveFramePixelBuffer() {
}
if (image == NULL) {
image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 4);
image = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, 4);
}
image->width =width;
image->height = height;
image->width = (int)width;
image->height = (int)height;
image->nChannels = 4;
image->depth = IPL_DEPTH_8U;
image->widthStep = rowBytes;
image->widthStep = (int)rowBytes;
image->imageData = imagedata;
image->imageSize = currSize;
image->imageSize = (int)currSize;
if (bgr_image == NULL) {
bgr_image = cvCreateImageHeader(cvSize(width,height), IPL_DEPTH_8U, 3);
bgr_image = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, 3);
}
bgr_image->width =width;
bgr_image->height = height;
bgr_image->width = (int)width;
bgr_image->height = (int)height;
bgr_image->nChannels = 3;
bgr_image->depth = IPL_DEPTH_8U;
bgr_image->widthStep = rowBytes;
bgr_image->widthStep = (int)rowBytes;
bgr_image->imageData = bgr_imagedata;
bgr_image->imageSize = currSize;
bgr_image->imageSize = (int)currSize;
cvCvtColor(image, bgr_image,CV_BGRA2BGR);