iOS GPUImage研究五:短视频拍摄(滤镜、文件写入) - Go语言中文社区

iOS GPUImage研究五:短视频拍摄(滤镜、文件写入)


希望这个Demo,可以给大家在视频滤镜制作上带来一些灵感、避免重复造轮子。也希望大家转载的时候带上原文地址,算是对原创的鼓励。

最下方有Demo地址
运行环境Xcode7.3.1

这个Demo应该是对GPUImage的总结吧,包含了视频写入,滤镜信息读取。前面几篇文章也分别对GPUImage中常用的功能进行了分别介绍。虽说GPUImage是开源的,但对初学者来讲上手还是有一定难度的,希望可以帮助大家。

在GPUImage的探索的道路上依旧还未停止。

这里写图片描述

需求:

序号 描述
1. 实现画面获取:使用GPUImageMovieCamera
2. 实现画面呈现:使用GPUImageView
3. 实现美颜滤镜:包含读取图像颜色矩阵,以及GPUImage自带滤镜组合和网上流传的美颜滤镜
4. 实现实时滤镜视频处理:使用GPUImageMovieWriter
5. 实现保存到相册,并播放。
6. 简单地切换动画,让过程看起来更自然。

效果如图 :

这里写图片描述偏微黄滤镜![这里写图片描述]

Demo目录:

这里写图片描述

相关类 说明:
Frameworks 是使用GPUImage的必须依赖库。
GPUImageCustomLookupFilter 是将读取图片信息并将之转化为滤镜 的关键类。也包含一些我自己的滤镜组合,包含鱼眼滤镜、水晶球滤镜、放行滤镜、浮雕、反鱼眼等。
FSKVideoFilterVc 是主控制器,包含切换摄像头、视频滤镜写入、视频录制播放、保存相册、切换滤镜、以及组合滤镜的使用方法。
SkVideoFilterView 是滤镜的视图,继承collectionview,一共包含大概30种组合滤镜。
FilterModel 是滤镜Model,处理滤镜名称定义,以及滤镜列表的初始化。
SSGPUImageBeautyFilter 就是GPUImageBeautifulFilter,只是换了个名字而已。
MyLayout 是一个继承UICollectionViewFlowLayout的布局类,一个是拥有缩放效果的布局方式,后来我把缩放效果调成了0,因为综合效果的原因。
 CGFloat distance = offset - attribute.center.x;
        // 越往中心移动,值越小,那么缩放就越小,从而显示就越大
        // 同样,超过中心后,越往左、右走,缩放就越大,显示就越小
        CGFloat scaleForDistance = distance / self.itemSize.height;
        // 可调整,值越大,显示就越大
        CGFloat scaleForCell = 1 + 0 * (1 - fabs(scaleForDistance));

        // only scale y-axis
        attribute.transform3D = CATransform3DMakeScale(1, scaleForCell, 1);
        attribute.zIndex = 1;

可通过调节0 * (1 - fabs(scaleForDistance));来改变效果。

StoryBoard说明:

这里写图片描述

storyboard具备快速开发的优点,除了实时变化相对于代码差一点,其他的他已经很成熟、也是伟大的开发模式、在这里也希望那些老家伙们别固执与代码布局,紧随时代吧!
特别提示:注意Mylayout的位置 很重要

这里写图片描述

初始化相机和GPUImageview:

func setNewCameraAndGPUViewAndStart() {
        videoCamera = GPUImageVideoCamera.init(sessionPreset: AVCaptureSessionPreset640x480, cameraPosition: AVCaptureDevicePosition.Front)
        videoCamera.outputImageOrientation = UIInterfaceOrientation.Portrait
        videoCamera.horizontallyMirrorFrontFacingCamera = true
        videoCamera.horizontallyMirrorRearFacingCamera = true

        filter = SSGPUImageBeautyFilter.init()

        filterView = self.view as! GPUImageView
        filterView.fillMode = kGPUImageFillModePreserveAspectRatioAndFill
        videoCamera.addTarget(filter as GPUImageInput)
        filter.addTarget(filterView)

        videoCamera.startCameraCapture()

    }

初始化写入对象:

func getNewMovieWriter() {

        let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,
                                                        .UserDomainMask, true)
        let documentsDirectory = paths[0] as String
        let filePath : String? = "(documentsDirectory)/DBLiveTest(currentTimeStamp()).mp4"
        movieURL = NSURL(fileURLWithPath: filePath!)


        movieWriter = GPUImageMovieWriter.init(movieURL: movieURL, size: CGSizeMake(480.0, 640.0))
        movieWriter.encodingLiveVideo = true
        if groupFilter == nil {
            filter.addTarget(movieWriter)

        }else{
            self.groupFilter?.addTarget(movieWriter)

        }
        videoCamera.audioEncodingTarget = movieWriter

    }

切换滤镜

//换滤镜
    func switchFilter(index: Int) {
        self.filter?.removeAllTargets()
        self.groupFilter?.removeAllTargets()
        self.currentFilterIndex = index
        let lookupImageName = self.filterModel.filterList[index].lookupImageName

        self.lookupFilter = GPUImageCustomLookupFilter.init(lookupImageName: lookupImageName)
        self.setUpGroupFilters(self.lookupFilter!)
        self.groupFilter?.addTarget(filterView)



        self.groupFilter?.addTarget(movieWriter)

    }

    func setUpGroupFilters(lookupFilter: GPUImageCustomLookupFilter) {
        self.groupFilter = GPUImageFilterGroup.init()
        self.groupFilter?.addTarget(filter)
        self.filter?.addTarget(lookupFilter)
        self.groupFilter?.initialFilters = [self.filter!]
        self.groupFilter?.terminalFilter = lookupFilter
    }

播放视频

func playVideoAndAddPreView() {
        dispatch_async(dispatch_get_main_queue()) {

            let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask, true)
            let documentsDirectory = paths[0] as String
            let filePath1 : String? = "(documentsDirectory)/DBLiveTest(currentTimeStamp()).jpg";

            UIImagePNGRepresentation(getFirstImageFromVideo(self.movieURL))?.writeToFile(filePath1!, atomically: true);

            self.thumbURL = NSURL(fileURLWithPath: filePath1!)

            animationFlipFromRight(self.filterView)
            self.videoCamera.stopCameraCapture()

            self.playerItem = AVPlayerItem(URL: self.movieURL)
            // 创建 AVPlayer 播放器
            self.player = AVPlayer(playerItem: self.playerItem)
            // 将 AVPlayer 添加到 AVPlayerLayer 上
            self.playerLayer = AVPlayerLayer(player: self.player)
            // 设置播放页面大小
            self.playerLayer.frame = self.view.frame
            // 设置画面缩放模式
            self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
            // 在视图上添加播放器
            self.view.layer.addSublayer(self.playerLayer)
            // 开始播放
            self.player.play()
            self.addPreViewToSufureView()
        }
    }

保存到相册:

func doYouWantSaveItToAlbum(bool:Bool) {
        if bool == true {
            let library = ALAssetsLibrary()

            if library.videoAtPathIsCompatibleWithSavedPhotosAlbum(movieURL) {
                library.writeVideoAtPathToSavedPhotosAlbum(movieURL, completionBlock: { (assetURL, error) in
                    dispatch_async(dispatch_get_main_queue(), {
                        if error == nil{
                            let alert = UIAlertView.init(title: "提示消息", message: "保存成功", delegate: nil, cancelButtonTitle: "确定")
                            alert.show()
                        }else{
                            let alert = UIAlertView.init(title: "提示消息", message: "保存失败", delegate: nil, cancelButtonTitle: "确定")
                            alert.show()
                        }
                    })
                })
            }

        }
    }

用到的全局方法:

//翻转动画
func animationFlipFromLeft(view:UIView) {
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationCurve(UIViewAnimationCurve.EaseInOut)
    UIView.setAnimationDuration(0.5)
    UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromLeft, forView: view, cache: false)
    UIView.commitAnimations()
}

//翻转动画
func animationFlipFromRight(view:UIView) {
    UIView.beginAnimations(nil, context: nil)
    UIView.setAnimationCurve(UIViewAnimationCurve.EaseInOut)
    UIView.setAnimationDuration(0.5)
    UIView.setAnimationTransition(UIViewAnimationTransition.FlipFromRight, forView: view, cache: false)
    UIView.commitAnimations()
}

//时间戳
func currentTimeStamp()->String {
    let now = NSDate()
    let dformatter = NSDateFormatter()
    dformatter.dateFormat = "yyyy年MM月dd日 HH:mm:ss"
    print("当前日期时间:(dformatter.stringFromDate(now))")



    //当前时间的时间戳
    let timeInterval:NSTimeInterval = now.timeIntervalSince1970
    let timeStamp = Int(timeInterval)

    return String(timeStamp)

}
//获取视频第一帧
func getFirstImageFromVideo(videoUrl:NSURL)->(UIImage){


    let asset = AVURLAsset(URL:videoUrl)

    let generator = AVAssetImageGenerator(asset: asset)

    generator.appliesPreferredTrackTransform=true

    let time = CMTimeMakeWithSeconds(0.0,600)

    var actualTime:CMTime = CMTimeMake(0,0)

    var image:CGImageRef!

    do{
        image = try generator.copyCGImageAtTime(time, actualTime: &actualTime)
    }catch let error as NSError{
        print(error)
    }

    return UIImage(CGImage: image)


}

模糊效果:

//添加模糊效果
    func addVisualEffectView() {
        self.effectView = UIVisualEffectView.init(effect: UIBlurEffect.init(style: UIBlurEffectStyle.Light));
        self.view.addSubview(self.effectView)
        self.effectView.frame = self.view.bounds
    }

Demo 地址:http://download.csdn.net/my

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/xoxo_x/article/details/70198469
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-08 14:40:27
  • 阅读 ( 1063 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢