2012-12-10 117 views
2

我有一個攝像頭會話,我從緩衝區採取圖片:製作隊列線程安全

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{ 
    CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer); 

    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];   
    //rotate image 90° 
    ciImage = [ciImage imageByApplyingTransform:CGAffineTransformMakeRotation(-M_PI/2.0)]; 
} 

,我在圖像上應用過濾器,我希望它應用在另一個隊列過濾器,它不是線程安全的,所以如果我把圖像加快,它會將圖像混合在一起(50/50從左到右,我認爲),但我試圖使它線程安全,它不會工作使用NSLock或NSRecursiveLock,因爲它會將圖像混合在一起。

dispatch_async(filterQueue, ^{ 
      CIImage *scaleImage = [CIFilter filterWithName:@"CILanczosScaleTransform" keysAndValues:kCIInputImageKey, ciImage, @"inputScale", [NSNumber numberWithFloat:0.5], nil].outputImage; 

      CGImageRef cgImage = [imageContext createCGImage:scaleImage fromRect:scaleImage.extent]; 
      [self.pictureArray addObject:[UIImage imageWithCGImage:cgImage]]; 
      CGImageRelease(cgImage); 
     }); 

有人能幫助我嗎?我在如何使代碼線程安全

圖像融合這樣沒有多少知識:http://i.stack.imgur.com/wjrIl.png

回答

0

使用@synchronized(個體經營)做出的代碼片段線程安全的。

例如:

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *) 
    //The following code will be thread safe. 
    @synchronized(self) { 
     CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer); 

     CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];   
     //rotate image 90° 
     ciImage = [ciImage imageByApplyingTransform:CGAffineTransformMakeRotation(-M_PI/2.0)]; 
    } 
} 

的@synchronized語句將鎖定的這部分代碼用於單個線程一次。您可以將它應用於需要代碼單線程的任何位置。

希望有所幫助。

+0

不,它不工作:([圖像混合像這樣:](http://i.stack.imgur.com/wjrIl。png) –

+0

嘗試使用dispatch_sync強制執行塊的順序 –

+0

您的filterQueue是否爲併發隊列?你可以嘗試使用一個串行隊列。 –

2

首先,上述代碼中不是線程安全的唯一部分是對addObject:的調用。通過將addObject:調用移動到主線程或使pictureArray訪問更加線程安全,您可以使代碼安全無憂。我們來看看兩者。

移動呼叫

這幾乎可以肯定你想怎麼做。

dispatch_async(filterQueue, ^{ 
    CIImage *scaleImage = [CIFilter filterWithName:@"CILanczosScaleTransform" keysAndValues:kCIInputImageKey, ciImage, @"inputScale", [NSNumber numberWithFloat:0.5], nil].outputImage; 

    CGImageRef cgImage = [imageContext createCGImage:scaleImage fromRect:scaleImage.extent]; 
    UIImage *image = [UIImage imageWithCGImage:cgImage]; 
    CGImageRelease(cgImage); 
    cgImage = NULL; // Always set to NULL after you release something 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    [self.pictureArray addObject:image]; 
    }); 
}); 

請注意,我盡力而爲,我可以在後臺線程。我只是將最後的addObject:移動到主線程。

線程安全addImage:

如果從後臺線程調用addObject:的時候,它可能是不錯的吊了這一點,爲自己的方法是這樣的:

- (void)addImageOnMainThread:(UIImage *)image { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    [self.pictureArray addObject:image]; 
    }); 
} 

線程安全pictureArray:

如果突變非常普遍並且鎖定是一個性能問題,這會更好。使用障礙導致快速訪問,代價是更復雜的代碼。

- (UIImage *)imageAtIndex:(NSUInteger)index { 
    UIImage *result = nil; 
    dispatch_sync(self.pictureArrayQueue, 
    ^{ result = self.pictureArray[index]; }); 
    return result; 
} 

- (void)addImage:(UIImage *)image { 
    dispatch_barrier_async(self.pictureArrayQueue, 
    ^{ [self.pictureArray addObject:image]; }); 
} 

注意,有一個新的調度隊列這裏訪問pictureArray。您可以建立更多讀者和作者(如removeImageAtIndex:等)。所有讀者使用dispatch_sync。所有作者使用dispatch_barrier_async。這需要更多的代碼,除了通過這些方法之外,您絕不能直接訪問pictureArray。優點是,如果突變非常普遍,速度會更快。

+0

我認爲ciImage不是線程安全的,因爲我認爲ciImage在過濾器創建scaleImage時發生改變。它必須,因爲結果是2圖像混合在一起.. –

+0

我試圖設置主線程上的addObject:代碼,並且結果是相同的,2圖像混合在一起.. :( –

+0

「imageContext」從多線程訪問它? –