前语
最近想做个简单的带滤镜功用的录制器,于是乎就想到GPUImage
这个远古且强大的滤镜库,其间GPUImage
的GPUImageMovieWriter
能够完结录制功用,用起来比较简单,关于我这种OpenGL小白非常友爱。
可是,开发过程中,发现这个录制器的暂停功用是有问题的。
这种情况,最好是换一个库,毕竟GPUImage
现已好久没有更新了,今后问题估计会越来越多,可是此刻录制相关的逻辑都写得差不多了,这沉没本钱有点大。。。
终究决议,专门针对这个录制器进行修复吧。
终究效果
Demo地址:JPMovieWriter_Demo,可暂停、续录、守时、带滤镜美颜的录制器,另附GIF制造。
暂停问题
GPUImageMovieWriter
目前存在的问题是:暂停又重录会黑屏或者有画面没声响。
经过调试发现:
-
屡次暂停恢复后,GPUImageVideoCamera的
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
这个方法会收集不了音频。 -
经百度谷歌发现这篇文章也是发现这个问题,可是注释了文章说到的那段代码后,虽然音频能持续收集,可是屡次暂停恢复,误差会越来越大,终究导致音画不同步(有时候声响卡了,有时候是画面卡了,终究连声响也没了)。
// 文中提及注释的当地
if (offsetTime.value > 0) {
CFRelease(audioBuffer);
audioBuffer = [self adjustTime:audioBuffer by:offsetTime];
CFRetain(audioBuffer);
}
解决方案
GPUImageMovieWriter
内部是经过AVAssetWriter
完结的录制功用,但AVAssetWriter
本来就没有暂停的功用,而GPUImageMovieWriter
是经过一些延时算法来完结,可是并不靠谱,屡次暂停后误差会越来越离谱。
持续百度谷歌还有ChatGPT的问询后,最好办法便是每次暂停后,换一个新的AVAssetWriter
从头录制,这是最稳妥的解决方案。
由于GPUImageMovieWriter
除了能录制,内部还有对视频帧进行滤镜烘托,为了不影响这部分的逻辑,我的做法便是彻底复制一个新的GPUImageMovieWriter
文件,然后只针对AVAssetWriter
的部分进行改造:移除【暂停】这个功用,只能【完结】录制,不同的是,【完结】录制后,能够【再次】录制。
这便是JPMovieWriter的由来,一个能够重复录制,而且带滤镜烘托功用的录制器。
新的特性
- 可重复、从头录制:每次录制都是一个全新的AVAssetWriter,因此每次”暂停“都是新的一个视频,也能够清空已录制部分从头开始录制,且在内部完结,无需从头设置滤镜烘托链(从头设置页面会明显卡顿)。
- 可设置最大录制时长:录制过程中会不断监听录制的时间,到达最大值会主动停止录制。
JPMovieWriter
能够彻底替代GPUImageMovieWriter
,由于除了AVAssetWriter
的部分,其余当地几乎没有改动,而且也做了大量的代码结构性优化,愈加面向对象化,便利阅读和调试。
留意点
虽然说能重录,但每次录制都是新的一个视频,所以终究完毕录制时,会回来一个存放在Temp文件夹的视频URL数组,鉴于以便应付不同的需求,内部并没有将多段视频组成一个视频的完结,数据将原汁原味保留(组成的逻辑Demo中有完结)。
遵守JPMovieWriterDelegate
协议,监听录制过程,录制完毕后组成并导出:
// MARK: - <JPMovieWriterDelegate>
extension RecordViewController: JPMovieWriterDelegate {
// AVAssetWriter重置过错的回调(例如目标途径已存在文件)
func movieWriter(_ writer: JPMovieWriter, resetFailed recordedURLs: [URL], error: Error) {
JPProgressHUD.showError(withStatus: (error as NSError).localizedDescription, userInteractionEnabled: true)
}
// 录制进度的回调
func movieWriter(_ writer: JPMovieWriter, recording recordDuration: TimeInterval, totalDuration: TimeInterval) {
let progress = recordDuration / totalDuration
controlBtn.setProgress(progress, animated: false)
}
// 录制行将完毕的回调
func movieWriter(_ writer: JPMovieWriter, recordWillDone error: Error?) {
JPProgressHUD.show(withStatus: error == nil ? "正在完毕录制" : "录制发生过错")
controlBar.isEnabled = false
}
// 录制现已完毕的回调
func movieWriter(_ writer: JPMovieWriter, recordDone recordedURLs: [URL], error: Error?) {
if let error = error as? NSError {
// 录制发送过错
return
}
// 录制完结,将视频碎片组成并导出
VideoTool.mergeVideos(recordedURLs, videoSize: UIConfig.videoSize, contentMode: .scaleAspectFit, maxDuration: CMTime(value: Int64(RecordConfig.videoMaxDuration), timescale: 1)) { mergedFilePath in
// mergedFilePath:组成好的途径 -> 缓存
} faild: { kError in
// 组成或导出失利
}
}
}
Demo介绍
JPMovieWriter_Demo:可暂停、续录、守时、带滤镜美颜的录制器,另附GIF制造。没什么技术含量,不过能够玩一下。
Feature:
✅ 可暂停、守时、续录;
✅ 多种滤镜选择;
✅ 基础美颜功用;
✅ 支持相册视频的导入和拼接;
✅ GIF制造;
TODO:
更多的滤镜和特效;
愈加定制化的GIF制造;
视频编辑。
美颜滤镜
GIF制造
生成图:
其他
- 首页的瀑布流布局:WaterfallLayoutDemo
- 封面编辑裁剪:JPCrop
- 视频GIF制造:JPImageresizerView
终究
本来想做一个GIF制造(用于微信斗图)、同时也能随时随地记录心境的App,可是最近有更重要的工作要先去做,还有很多页面和功用都没写完,这个项目只能放置了。