先总结:相机启动过慢主要是因为几个线程警告引起的,所以解决线程警告至关重要
警告截图
第一步:修改GPUImageVideoCamera.m文件中的警告
警告位置
解决方法
第1步:在.m文件中声明一个线程
//防止线程阻塞
@property(nonatomic) dispatch_queue_t sessionQueue;
第2步:实现sessionQueue
/**
* 创建一个队列,防止阻塞主线程
*/
- (dispatch_queue_t)sessionQueue{
if (!_sessionQueue) {
_sessionQueue = dispatch_queue_create("wjx_GPUImage_sessionQueue", DISPATCH_QUEUE_SERIAL);
}
return _sessionQueue;
}
第3步:把方法添加进子线程
- (void)startCameraCapture;
{
if (![_captureSession isRunning])
{
startingCaptureTime = [NSDate date];
// [_captureSession startRunning];
//自己添加一个子线程 操作
__weak __typeof(self)weakSelf = self;
dispatch_async(self.sessionQueue, ^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf.captureSession.isRunning) {
[strongSelf.captureSession startRunning];
}
});
};
}
第二步:修改GPUImageView.m文件中的警告2处
警告位置
//位置1
[[[GPUImageContext sharedImageProcessingContext] context] renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
//位置2
CGSize currentViewSize = self.bounds.size;
解决方案
第1步:在.h文件声明两个参数并在.m文件自动编辑
//.h
@property(nonatomic)CAEAGLLayer *currentlayer;
@property(nonatomic)CGRect currentFrame;
//.m
@synthesize currentlayer;//wjx添加防止主线程卡顿
@synthesize currentFrame;//wjx添加防止主线程卡顿
第2步 修改“警告位置”1的报错
- (void)commonInit方法中更改
//原文
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
//改成
currentlayer = (CAEAGLLayer *)self.layer;
currentlayer.opaque = YES;
currentlayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
- (void)createDisplayFramebuffer方法中更改
//原文
[[[GPUImageContext sharedImageProcessingContext] context] renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
//改成
[[[GPUImageContext sharedImageProcessingContext] context] renderbufferStorage:GL_RENDERBUFFER fromDrawable:currentlayer];
第2步 修改“警告位置”2的报错--这有两种修改
方法1--修改会用到前面声明的currentFrame
//1.0
- (void)layoutSubviews {
[super layoutSubviews];
self.currentFrame = self.bounds;//添加这句代码
// The frame buffer needs to be trashed and re-created when the view size changes.
if (!CGSizeEqualToSize(self.bounds.size, boundsSizeAtFrameBufferEpoch) &&
!CGSizeEqualToSize(self.bounds.size, CGSizeZero)) {
runSynchronouslyOnVideoProcessingQueue(^{
[self destroyDisplayFramebuffer];
[self createDisplayFramebuffer];
[self recalculateViewGeometry];
});
}
}
//2.
- (void)recalculateViewGeometry;
{
runSynchronouslyOnVideoProcessingQueue(^{
CGFloat heightScaling, widthScaling;
// CGSize currentViewSize = self.bounds.size;//原文是注释掉这句
CGSize currentViewSize = currentFrame.size;//改成这样
// CGFloat imageAspectRatio = inputImageSize.width / inputImageSize.height;
// CGFloat viewAspectRatio = currentViewSize.width / currentViewSize.height;
// CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, self.bounds);
CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, self.viewBounds);//原文是注释掉这句
CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, currentFrame);//改成这样
/*
...省略
**/
});
}
//3.0
- (void)createDisplayFramebuffer;
{
/*
...省略
**/
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, displayRenderbuffer);
GLuint framebufferCreationStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
NSAssert(framebufferCreationStatus == GL_FRAMEBUFFER_COMPLETE, @"Failure with display framebuffer generation for display of size: %f, %f", self.bounds.size.width, self.bounds.size.height);
//boundsSizeAtFrameBufferEpoch = self.bounds.size;//原文是注释掉这句
boundsSizeAtFrameBufferEpoch = currentFrame.size;//改成这样
}
方法2--修改会不会用到前面声明的currentFrame--只需要--判断是否为主线程
//1.先把recalculateViewGeometry方法中的代码提出来-重写一个函数
- (void)wjx_recalculateViewGeometryWithSize:(CGSize)size{
runSynchronouslyOnVideoProcessingQueue(^{
CGFloat heightScaling, widthScaling;
CGSize currentViewSize = size;
// CGFloat imageAspectRatio = inputImageSize.width / inputImageSize.height;
// CGFloat viewAspectRatio = currentViewSize.width / currentViewSize.height;
CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, self.bounds);
switch(_fillMode)
{
case kGPUImageFillModeStretch:
{
widthScaling = 1.0;
heightScaling = 1.0;
}; break;
case kGPUImageFillModePreserveAspectRatio:
{
widthScaling = insetRect.size.width / currentViewSize.width;
heightScaling = insetRect.size.height / currentViewSize.height;
}; break;
case kGPUImageFillModePreserveAspectRatioAndFill:
{
// CGFloat widthHolder = insetRect.size.width / currentViewSize.width;
widthScaling = currentViewSize.height / insetRect.size.height;
heightScaling = currentViewSize.width / insetRect.size.width;
}; break;
}
imageVertices[0] = -widthScaling;
imageVertices[1] = -heightScaling;
imageVertices[2] = widthScaling;
imageVertices[3] = -heightScaling;
imageVertices[4] = -widthScaling;
imageVertices[5] = heightScaling;
imageVertices[6] = widthScaling;
imageVertices[7] = heightScaling;
});
// static const GLfloat imageVertices[] = {
// -1.0f, -1.0f,
// 1.0f, -1.0f,
// -1.0f, 1.0f,
// 1.0f, 1.0f,
// };
}
//2.修改recalculateViewGeometry
- (void)recalculateViewGeometry;
{
NSLog(@"Is main thread: %@", [NSThread isMainThread] ? @"YES" : @"NO");
if ([NSThread isMainThread] == NO) {
dispatch_async(dispatch_get_main_queue(), ^{
[self wjx_recalculateViewGeometryWithSize:self.bounds.size];
});
} else {
[self wjx_recalculateViewGeometryWithSize:self.bounds.size];
}
}
本文主要引用两篇文章做了汇总感谢
【iOS紫色警告】GPUImage启动摄像头耗时
GPUImage 子线程访问 UI 的输出警告处理