GPUImageFilter Singleton断言失败(useNextFrameForImageCapture)

run*_*mad 0 singleton ios gpuimage

我正在尝试通过使用包含图像过滤器的单例对象来优化一些图像过滤,以供我在任何地方使用.我遇到了一个问题,我相信我一次多次调用过滤器(显示几个单元格,下载图像后,显示之前,我正在使用过滤器处理图像,这可能几乎同时发生) .

我遇到了这个问题:

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
Run Code Online (Sandbox Code Playgroud)

执行:

#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;
}
Run Code Online (Sandbox Code Playgroud)

在我的代码中,我打电话给:

[[[GPUImageFilterManager sharedInstance] blurFilter] imageByFilteringImage:image];

以前,我在每个单元格中都有一个GPUImageLuminanceThresholdFilter属性,我想优化它只是使用它的单个实例,但现在看来我将无法一次处理多个图像.这里有什么想法或建议吗?

Bra*_*son 5

我对这里出现问题的猜测是,这-imageByFilteringImage:不是一个真正的原子操作,如果你同时在多个线程上触发它,你将会得到奇怪的行为.看一下该方法中发生的事情(通过该-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;
}
Run Code Online (Sandbox Code Playgroud)

创建GPUImagePicture,附加到过滤器,处理并提取输出.如果你在多个线程中使用相同的过滤器,并且你调用了这个方法,那么你可能会在不同的点上中断它并创建奇怪的过滤途径.因此上面的错误(以及其他潜在的崩溃和图像损坏).

如果你想在单例中使用这个过滤器,我的建议是设置一个串行调度队列,并在调度到该队列时将访问包装到该过滤器.特别是,我将同步调度包装到-imageByFilteringImage:上面的这个队列中,以保证在完全被另一个图像和线程触发之前,它总是完全执行并返回一个图像.

GPUImage OpenGL ES上下文一次只能执行一次渲染操作,因此您不会因为一次只能将对过滤器的访问限制为一个线程而损失太多.它的实现也非常简单,我使用这种模式通过整个框架中的GCD队列限制对共享资源的访问.