iOS 记GPUImage框架使用问题
1、第一次打开GPUImage的相机很慢很慢,启动就是很慢......
不出意外的话,这里项目是报了一个紫色感叹号的内存泄露问题。解决方法也很简单:
1、在GPUImageView.m里,定义一个属性viewBounds,来记录做中转。
///解决首次启动很慢的问题
@property (nonatomic, assign) CGRect viewBounds;
2、在初始方法里做记录。
- (id)initWithFrame:(CGRect)frame
{
if (!(self = [super initWithFrame:frame]))
{
return nil;
}
//第一次启动很慢
self.viewBounds = self.bounds;
[self commonInit];
return self;
}
3、修改 recalculateViewGeometry 方法,将self.bounds.size替换为我们定义的self.viewBounds.size
- (void)recalculateViewGeometry;
{
runSynchronouslyOnVideoProcessingQueue(^{
CGFloat heightScaling, widthScaling;
CGSize currentViewSize = self.viewBounds.size;//self.bounds.size;
// CGFloat imageAspectRatio = inputImageSize.width / inputImageSize.height;
// CGFloat viewAspectRatio = currentViewSize.width / currentViewSize.height;
CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, self.viewBounds);//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,
// };
}
4、如果你有切换比例,进行拍照等操作,需要在GPUImageView.m 的 layoutSubviews里更新我们自定义的属性,否则你切换画幅比例之后,页面还是以前的预览视图大小。
- (void)layoutSubviews {
[super layoutSubviews];
//第一次启动很慢
self.viewBounds = 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、录制视频时崩溃
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?'
是因为 framebufferReferenceCount的值小于0,这里是GPUImage对buffer的缓存处理,简单的解决办法是在源文件GPUImageFramebuffer.m 中 unlock方法添加一个判断:
- (void)unlock;
{
if (referenceCountingDisabled)
{
return;
}
//此处为手动添加 修改
if (framebufferReferenceCount <1) {
return;
}
NSAssert(framebufferReferenceCount > 0, @"Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?");
framebufferReferenceCount--;
if (framebufferReferenceCount < 1)
{
[[GPUImageContext sharedFramebufferCache] returnFramebufferToCache:self];
}
}
3、录制视频出现首帧黑屏、卡帧、丢帧的情况
这是因为自己在结束视频录制时,释放时机不对,导致的问题。解决方法很简单,不要直接调用finishRecordingWithCompletionHandler,
而是在finishRecordingWithCompletionHandler的回调里去写结束的逻辑
//MARK: - 结束录制视频
/// 结束录制视频
- (void)endRecording {
WEAK_SELF;
[self.movieWriter finishRecordingWithCompletionHandler:^{
STRONG_SELF;
dispatch_async(dispatch_get_main_queue(), ^{
strongSelf.isRecording = NO;
[strongSelf.cameraFilter setFrameProcessingCompletionBlock:nil];
[strongSelf.blendFilter removeTarget:strongSelf.movieWriter];
[strongSelf.imageElement removeTarget:strongSelf.blendFilter];
[strongSelf.cameraFilter removeTarget:strongSelf.blendFilter];
strongSelf.blendFilter = nil;
strongSelf.imageElement = nil;
strongSelf.movieWriter = nil;
});
}];
}
4、打开手机旋转锁定后,横屏拍照处理失效
这个bug很隐秘,因为我自己手机一直是锁定的,做完横屏的处理之后,测试机还是有问题,但我的没有问题,苦苦找寻,才发现是屏幕锁定被打开了。这里我采用的方式是将输出都做统一的输出矫正,解决方法:
1、找到GPUImageOutput.h,定义一个暴露给外界的方法imageFromCurrentFramebuffer2
/// 手动增加的方法,防止打开手机屏幕旋转锁定后,拍照出现错乱的bug
- (UIImage *)imageFromCurrentFramebuffer2;
2、在GPUImageOutput.m里进行方法实现
/// 手动增加的方法,防止打开手机屏幕旋转锁定后,拍照出现错乱的bug
- (UIImage *)imageFromCurrentFramebuffer2
{
return [self imageFromCurrentFramebufferWithOrientation:UIImageOrientationUp];
}
3、我是使用的GPUImageStillCamera来定义的相机,在GPUImageStillCamera.m里,找到我调用的拍照方法- (void)capturePhotoAsImageProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withCompletionHandler:(void (^)(UIImage *processedImage, NSError *error))block
,进行修改
- (void)capturePhotoAsImageProcessedUpToFilter:(GPUImageOutput<GPUImageInput> *)finalFilterInChain withCompletionHandler:(void (^)(UIImage *processedImage, NSError *error))block;
{
[self capturePhotoProcessedUpToFilter:finalFilterInChain withImageOnGPUHandler:^(NSError *error) {
UIImage *filteredPhoto = nil;
if(!error){
filteredPhoto = [finalFilterInChain imageFromCurrentFramebuffer2];
//[finalFilterInChain imageFromCurrentFramebuffer];
}
dispatch_semaphore_signal(frameRenderingSemaphore);
block(filteredPhoto, error);
}];
}