美文网首页
iOS 记GPUImage框架使用问题

iOS 记GPUImage框架使用问题

作者: iOS_July | 来源:发表于2022-01-15 15:34 被阅读0次

    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);
        }];
    }
    

    相关文章

      网友评论

          本文标题:iOS 记GPUImage框架使用问题

          本文链接:https://www.haomeiwen.com/subject/yfithrtx.html