美文网首页收藏ios
iOS-GPUImage实现透明视频

iOS-GPUImage实现透明视频

作者: 笑破天 | 来源:发表于2021-01-08 10:18 被阅读0次

    一、尝试思路

    1、使用了GPUImageChromaKeyFilter,效果不太理想。

    2、换用GPUImageChromaKeyBlendFilter,它通过将第一个源中setColorToReplaceRed中指定颜色的像素替换为第二个源中的像素来混合两个源。报错Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?,暂无法解决,pass

    3、使用GPUImageCropFilter和GPUImageMaskFilter组合,思路是剪切成两个视频,再mask混合。效果不太理想。

    let filter1 = GPUImageCropFilter(cropRegion: CGRect(x: 0.5, y: 0, width: 0.5, height: 1))
    let filter2 = GPUImageCropFilter(cropRegion: CGRect(x: 0, y: 0, width: 0.5, height: 1))
    let filter = GPUImageMaskFilter()
    

    4、使用自定义filter,系统内置的filter无法满足需求。打开GPUImageColorInvertFilter.m可以查看怎么实现GPUImage 自定义滤镜,自己实现一个AlphaFilter

    #ifndef AlphaFilter_h
    #define AlphaFilter_h
    
    #import <GPUImage/GPUImageFilter.h>
    
    @interface AlphaFilter : GPUImageFilter
    
    @end
    
    #endif /* AlphaFilter_h */
    
    #import "AlphaFilter.h"
    
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
    
    NSString *const kGPUImageVideoAlphaShaderString = SHADER_STRING
    (
     varying highp vec2 textureCoordinate;//这个对应下面的ST坐标,即右边视频的坐标
     uniform sampler2D inputImageTexture;//这个是完整视频的纹理
     
     const lowp vec2 leftW = vec2(-0.5,0.0);
     
     void main()
     {
         //从右边的视频中拿RGB值,从左边的视频中拿Alpha值,然后返回一个新的RGBA.
         lowp vec4 rightTextureColor = texture2D(inputImageTexture, textureCoordinate);
         lowp vec2 leftTextureCoordinate = leftW + textureCoordinate;
         lowp vec4 leftTextureColor = texture2D(inputImageTexture, leftW + textureCoordinate);
         gl_FragColor = vec4(rightTextureColor.rgb, leftTextureColor.r);//leftTextureColor.r
     }
     );
    #else
    
    
    #endif
    
    @implementation AlphaFilter
    
    - (id)init {
        if (!(self = [super initWithFragmentShaderFromString: kGPUImageVideoAlphaShaderString]))
        {
            return nil;
        }
        return self;
    }
    
    - (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates {
        static const GLfloat posVertices[] = {
            // x , y
            -1, 1,
            1, 1,
            -1, -1,
            1, -1,
        };
    /*
         [0.0,0.0]----[0.5,0.0]----[1.0,0.0]
              |                   |                 |
              |                   |                 |
              |                   |                 |
         [0.0,0.5]----[0.5,0.5]----[1.0,0.5]
              |                   |                 |
              |                   |                 |
              |                   |                 |
         [0.0,1.0]----[0.5,1.0]----[1.0,1.0]
         */
        static const GLfloat textVertices[] = {
            // s , t
            0.5, 1.0,
            1.0, 1.0,
            0.5, 0.0,
            1.0, 0.0
        };
    //    static const GLfloat textVertices[] = {
    //        // s , t
    //        0.5, 1.0,
    //        1.0, 1.0,
    //        0.5, 0.5,
    //        1.0, 0.5
    //    };
        // 向缓冲区对象写入刚定义的顶点数据
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //    glBlendFunc(GL_ONE, GL_ZERO);
    
        [super renderToTextureWithVertices:posVertices textureCoordinates:textVertices];
    
        glDisable(GL_BLEND);
    }
    
    @end
    

    至此,GPUImage透明视频实现完毕。遗留个问题:没有声音,稍后解决。
    参考:
    自定义GPUImageFilter滤镜(类似抖音效果)
    iOS基于GPUImage带Alpha的mp4播放方案

    二、收获

    1、百度不到的资料,去谷歌,真的太不一样。,可搜索“礼物特效透明MP4”对比下效果。
    2、少写了相关的看不懂的代码,肯定是不能正常工作的,少写了init方法,死活出不来效果。

    三、遇到的一些问题:

    GPUImage github主页的说明中,自定义滤镜的方法.fsh好像不太好使,或者自己不会用。

    GPUImage的GPUImageMovie调用本地视频,为什么没有声音
    用url是没有声音的,用item就可以了,预览时不支持播放声音,需要自行添加声音播放功能,用AVPlayer吧

    GPUImageVideoCamera: 从Camera获取的实时视频。
    GPUImageStillCamera: 从Camera获取到的图片。
    GPUImagePicture: 静态图片。
    GPUImageMovie: 电影

    fileType: AVFileType.mp4.rawValue
    outputSettings: [AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : 1080, AVVideoHeightKey : 1080]

    [AVAssetWriter initWithURL:fileType:error:] invalid parameter not satisfying: [outputURL isFileURL]’
    原因:看一下初始化的GPUImageMovieWriter的MovieURL,是它:fileURLWithPath 不是:URLWithString

    [AVAssetWriterInput appendSampleBuffer:] Cannot append sample buffer: Input buffer must be in an uncompressed format when outputSettings is not nil'

    [AVAssetWriter startWriting] Cannot call method when status is 3'

    滤镜使用:

    let imgView = UIImageView(frame: view.bounds)
            imgView.image = UIImage(named: "bg")
            view.addSubview(imgView)
            
            let inputUrl1 = URL(fileURLWithPath: Bundle.main.path(forResource: "two4", ofType: "mp4") ?? "")
            let imageMovie1 = GPUImageMovie(url: inputUrl1)
            imageMovie1?.shouldRepeat = true
            
            let filter = AlphaFilter()
            imageMovie1?.addTarget(filter)
            
            let videoView = GPUImageView(frame: view.bounds)
            videoView.backgroundColor = UIColor.clear
            videoView.fillMode = .stretch
            view.addSubview(videoView)
            
            filter.addTarget(videoView)
            
            imageMovie1?.startProcessing()
    

    四、新问题

    1、播放太快-设置成真实速率即可
    2、后台重新进入,卡住了-前后台切换需要关闭和打开movie,否则会崩溃卡住
    3、没声音
    自己用AVPlayer播放无画面的mp4里的声音即可,注意AVPlayer播放MP4里的声音,必须有playerlayer,否则无法播放。
    4、延迟了7秒才开始播放???
    连接Xcode的话,首次加载会超长时间,测试机拔掉线单独运行没事

    5、前后台切换,重新播放问题
    6、子线程调UI问题

    相关文章

      网友评论

        本文标题:iOS-GPUImage实现透明视频

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