收藏ios

iOS-GPUImage实现透明视频

2021-01-08  本文已影响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问题

上一篇下一篇

猜你喜欢

热点阅读