我试图通过使用包含图像过滤器的单例对象来优化某些图像过滤,以供我在任何地方使用。我遇到了一个问题,我相信我一次多次调用过滤器(显示几个单元格,下载图像后,显示之前,我正在使用过滤器处理图像,这可能几乎同时发生)
我遇到了这个问题:
NSAssert(framebufferReferenceCount > 0, @"Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?");
https://github.com/BradLarson/GPUImage/blob/master/framework/Source/GPUImageFramebuffer.m#L269
这是我的代码:
接口:
#import <GPUImage/GPUImage.h>
@interface GPUImageFilterManager : NSObject
+ (GPUImageFilterManager*)sharedInstance;
@property (nonatomic, strong) GPUImageiOSBlurFilter *blurFilter;
@property (nonatomic, strong) GPUImageLuminanceThresholdFilter *luminanceFilter;
@end
实现:
#import "GPUImageFilterManager.h"
@implementation GPUImageFilterManager
+ (GPUImageFilterManager*)sharedInstance {
static GPUImageFilterManager *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [GPUImageFilterManager new];
});
return _sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
self.luminanceFilter = [[GPUImageLuminanceThresholdFilter alloc] init];
self.luminanceFilter.threshold = 0.5;
self.blurFilter = [[GPUImageiOSBlurFilter alloc] init];
[self.blurFilter setBlurRadiusInPixels:BLUR_RADIUS];
[self.blurFilter setSaturation:SATURATION];
[self.blurFilter setDownsampling:DOWNSAMPLING];
[self.blurFilter setRangeReductionFactor:RANGEREDUCTION];
}
return self;
}
-(GPUImageiOSBlurFilter*)blurFilter {
[_blurFilter useNextFrameForImageCapture];
return _blurFilter;
}
-(GPUImageLuminanceThresholdFilter*)luminanceFilter {
[_luminanceFilter useNextFrameForImageCapture];
return _luminanceFilter;
}
在我的代码中,我打电话给:
[[[GPUImageFilterManager sharedInstance] blurFilter] imageByFilteringImage:image];
以前,我在每个单元格中都有一个GPUImageLuminanceThresholdFilter属性,我想优化它只使用它的单个实例,但现在看来我不能一次处理多个图像。这里有什么想法或建议吗?
答案 0 :(得分:5)
我对这里出现的问题的猜测是-imageByFilteringImage:
并非真正的原子操作,如果你同时在多个线程上触发它,你就会#&# 39;重新变得奇怪的行为。看一下该方法中发生的事情(通过-newCGImageByFilteringCGImage:
方法):
- (CGImageRef)newCGImageByFilteringCGImage:(CGImageRef)imageToFilter;
{
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithCGImage:imageToFilter];
[self useNextFrameForImageCapture];
[stillImageSource addTarget:(id<GPUImageInput>)self];
[stillImageSource processImage];
CGImageRef processedImage = [self newCGImageFromCurrentlyProcessedOutput];
[stillImageSource removeTarget:(id<GPUImageInput>)self];
return processedImage;
}
创建GPUImagePicture,附加到过滤器,处理并提取输出。如果您在多个线程中使用相同的过滤器,并且您调用此方法,那么您可能会在各个点上中断此操作并创建奇怪的过滤路径。因此上面的错误(以及其他潜在的崩溃和图像损坏)。
如果你想在单例中使用这个过滤器,我的建议是设置一个串行调度队列,并在调度到该队列时将访问包装到该过滤器。特别是,我将同步调度包装在上面的-imageByFilteringImage:
周围的队列中,以保证它始终完全执行并返回图像,然后再由另一个图像和线程触发。
GPUImage OpenGL ES上下文一次只能执行一次渲染操作,因此一次只能将对过滤器的访问限制为一个线程,从而不会造成太大损失。它的实现也非常简单,我使用这种模式通过整个框架中的GCD队列限制对共享资源的访问。