From 4ad12a680c03deb0c4d9ff6065831dad036de312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Devernay?= Date: Fri, 26 Jul 2013 18:39:03 +0200 Subject: [PATCH] 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 --- modules/highgui/src/cap_qtkit.mm | 91 +++++++++++++++++++------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/modules/highgui/src/cap_qtkit.mm b/modules/highgui/src/cap_qtkit.mm index c7afffa075..2335e5c215 100644 --- a/modules/highgui/src/cap_qtkit.mm +++ b/modules/highgui/src/cap_qtkit.mm @@ -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);