使用GPUImage实现视频滤镜

简介: GPUImage是一个著名的图像处理开源库,可以实现图像的输入、处理、输出等。这篇文章先总结了一下GPUImage的工作原理,然后将接入app时的一些注意事项分享给大家。

关于GPUImage

这里直接引用官方描述:
The GPUImage framework is a BSD-licensed iOS library that lets you apply GPU-accelerated filters and other effects to images, live camera video, and movies. In comparison to Core Image (part of iOS 5.0), GPUImage allows you to write your own custom filters, supports deployment to iOS 4.0, and has a simpler interface. However, it currently lacks some of the more advanced features of Core Image, such as facial detection.
项目地址:https://github.com/BradLarson/GPUImage

滤镜基本原理

滤镜处理的原理就是把静态图片或者视频的每一帧进行图形变换再显示出来。它的本质就是像素点的坐标和颜色变化,这点从GPUImage项目中滤镜的源代码就可以了解到。
例如下面就是一个名为DarkenBlend的滤镜代码:

NSString *const kGPUImageDarkenBlendFragmentShaderString = SHADER_STRING( varying highp vec2 textureCoordinate; varying highp vec2 textureCoordinate2;
AI 代码解读

uniform sampler2D inputImageTexture;
uniform sampler2D inputImageTexture2;

void main()
{

lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);
lowp vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);

gl_FragColor = vec4(min(overlayer.rgb * base.a, base.rgb * overlayer.a) + overlayer.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlayer.a), 1.0);
AI 代码解读

}
);


GPUImage的最新版本已经内置了125个滤镜。也支持编写自定义滤镜(custom filter)。

图像处理流程

数据源需要实现GPUImageOutput接口,而后续各个环节(包括最后处理输出结果)的对象都要实现GPUImageInput接口。每个处理环节都是从上一个环节获取图像数据,进行处理后再将结果传递给下一个。下游的处理对象称为上一步的target。使用addTarget:方法为处理链路添加每个环节的对象。一个常见的链条如下:
数据源(例如GPUImageVideoCamera或者GPUImageMovie)->各类filter->GPUImageView
如果需要将结果输出到文件,只要把上述流程中最末的GPUImageView改为一个GPUImageMovieWriter即可。所以滤镜的添加和替换,以及输出结果都十分简单方便。

附一张GPUImage的结构图
Snip20160222_3

接入app

将滤镜接入app非常简单,只要创建一个GPUImageMovie,一个具体的GPUImageFilter和一个用来显示的GPUImageView,然后按处理链条的上下游关系把它们用addTarget串起来。
下面附上我的app里面的调用代码(预览视频):

AI 代码解读
_movie = [[GPUImageMovie alloc] initWithURL:url];
_movie.shouldRepeat = YES;
_movie.playAtActualSpeed = YES;
_movie.playSound = YES;
_movie.delegate = self;

GPUImageMissEtikateFilter *filter = [[GPUImageMissEtikateFilter alloc] init];//胶片效果
[_movie addTarget:filter];
[filter addTarget:self.gpuImageView];

[_movie startProcessing];
AI 代码解读

然后就是一些重要的参数设置:
playAtActualSpeed
控制GPUImageView预览视频时的速度是否要保持真实的速度。如果设为NO,则会将视频的所有帧无间隔渲染,导致速度非常快。设为YES,则会根据视频本身时长计算出每帧的时间间隔,然后每渲染一帧,就sleep一个时间间隔,从而达到正常的播放速度。

shouldRepeat
控制视频是否循环播放。

当你不想预览,而是想将处理过的结果输出到文件时,步骤也类似,只是不再需要创建GPUImageView,而是需要一个GPUImageMovieWriter:

AI 代码解读
_writer = [[GPUImageMovieWriter alloc] initWithMovieURL:filtedMovieURL size:CGSizeMake(480, 640) fileType:(NSString *)kUTTypeMPEG4 outputSettings:outputSettings];
_writer.encodingLiveVideo = NO;
_writer.shouldPassthroughAudio = NO;
_movie.audioEncodingTarget = _writer;
_movie.playAtActualSpeed = NO;
[_movie addTarget:_curFilter];
[_curFilter addTarget:_writer];
[_movie enableSynchronizedEncodingUsingMovieWriter:_writer];
[_writer startRecording];
[_movie startProcessing];
AI 代码解读

一些局限和踩过的坑

1.预览时不支持播放声音
视频结果输出到GPUImageView预览时不支持播放声音,所以要自行添加声音播放:
自行创建了一个播放器对象

AI 代码解读

(void) setupSound
{
if (theAudioPlayer != nil)
{

[theAudioPlayer pause];
[theAudioPlayer seekToTime:kCMTimeZero];
theAudioPlayer = nil;
AI 代码解读

}
theAudioPlayer = [[AVPlayer alloc] initWithURL:self.url];
}

跟GPUImageView的图像同步播放

AI 代码解读
if (self.playSound && hasAudioTrack)
{
    [theAudioPlayer seekToTime:kCMTimeZero];
    [theAudioPlayer play];
}
AI 代码解读

由于GPUImageMovie里面没有在这几个重要位置提供回调,所以只能在源代码中直接添加,这也导致了对源码的侵入,不利于以后版本升级。

2.GPUImageView预览视频并循环播放时,当播放重新开始时,有大约50%的概率会有红屏闪一下,目前还未定位到原因

3.GPUImageView预览视频时,app切到后台会crash,所以要特别处理下,在willDisappear和handleApplicationWillEnterBackgroundNotify这两个时机都要暂停滤镜处理:

AI 代码解读
if (_movie) {
    [_movie endProcessing];
    [_movie removeAllTargets];
    _movie = nil;
}
AI 代码解读


对应的,在willAppear和handleApplicationWillEnterForegroundNotify这两个时机要重启处理:
AI 代码解读
if (!_movie) {
    _movie = [[GPUImageMovie alloc] initWithURL:url];
}

_movie.shouldRepeat = YES;
_movie.playAtActualSpeed = YES;
_movie.playSound = YES;
_movie.delegate = self;

[_movie addTarget:_curFilter];
[_curFilter addTarget:self.gpuImageView];

[_movie startProcessing];
AI 代码解读

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
ruobin
+关注
目录
打赏
0
0
0
1
4
分享
相关文章
FFmpeg中overlay滤镜用法-水印及画中画
overlay 技术又称视频叠加技术。overlay 视频技术使用非常广泛,常见的例子有,电视屏幕右上角显示的电视台台标,以及画中画功能。画中画是指在一个大的视频播放窗口中还存在一个小播放窗口,两个窗口不同的视频内容同时播放。
2122 0
FFmpeg中overlay滤镜用法-水印及画中画
Photoshop利用滤镜给照片加上四射的光芒
Photoshop利用滤镜给照片加上四射的光芒
129 0
OpenGL 实现视频编辑中的转场效果
转场效果是什么? 转场效果,简单来说就是两段视频之间的衔接过渡效果。
500 0