1. 程式人生 > >iOS GPUImage音視訊採集以及美顏功能

iOS GPUImage音視訊採集以及美顏功能

iOS GPUImage音視訊採集以及美顏功能


GPUImageStillCamera:用於拍攝當前手機的畫面, 並且儲存圖片

GPUImageVideoCamera:通常用於實時視訊的錄製

使用方法:GPUImageStillCamera \ GPUImageVideoCamera>GPUImageFilter->GPUImageView 攝像機轉到濾鏡再轉到view上

本篇部落格Demo:iOS GPUImage音視訊採集以及美顏功能


初始化需要用到的屬性
    
    fileprivate lazy var camera: GPUImageVideoCamera? = GPUImageVideoCamera(sessionPreset: AVCaptureSessionPresetHigh, cameraPosition: .front)
    
    fileprivate lazy var preView: GPUImageView  = {
        let preView = GPUImageView(frame: self.view.bounds)
        return preView
    }()
    
    let saturationFilter = GPUImageSaturationFilter() // 飽和
    let bilateralFilter = GPUImageBilateralFilter() // 磨皮
    let brightnessFilter = GPUImageBrightnessFilter() // 美白
    let exposureFilter = GPUImageExposureFilter() // 曝光
    
    fileprivate var player: AVPlayer?
    fileprivate var isEndRecording = false
    
    // 視訊存放路徑Url
    var fileURL : URL {
        return URL(fileURLWithPath: pathString)
    }
    
    //視訊存放路徑
    var pathString: String {
        return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/test.mp4"
    }
    
    // 建立寫入物件
    fileprivate lazy var movieWriter : GPUImageMovieWriter = { [weak self] in
        if FileManager.default.fileExists(atPath: (self?.pathString)!) {
            try? FileManager.default.removeItem(atPath: (self?.pathString)!)
        }
        let movieWriter = GPUImageMovieWriter(movieURL: self?.fileURL, size: (self?.view.bounds.size)!)
        movieWriter?.encodingLiveVideo = true
        
        return movieWriter!
    }()
    

建立camera以及濾鏡組
    
    fileprivate func conifgCamera() {
        //建立預覽的View
        view.insertSubview(preView, at: 0)
        //設定camera方向
        camera?.outputImageOrientation = .portrait
        camera?.horizontallyMirrorFrontFacingCamera = true
        
        ///防止允許聲音通過的情況下,避免錄製第一幀黑屏閃屏
        camera?.addAudioInputsAndOutputs()
        
        //獲取濾鏡組
        let filterGroup = getGroupFilters()
        //設定預設值
        bilateralFilter.distanceNormalizationFactor = 5.5
        exposureFilter.exposure = 0
        brightnessFilter.brightness = 0
        saturationFilter.saturation = 1.0
        //設定GPUImage的響應鏈
        camera?.addTarget(filterGroup)
        filterGroup.addTarget(preView)
        //開始採集視訊
        camera?.startCapture()
        // 將writer設定成濾鏡的target
        filterGroup.addTarget(movieWriter)
        camera?.delegate = self
        camera?.audioEncodingTarget = movieWriter
        movieWriter.startRecording()
    }
    
    fileprivate func getGroupFilters() -> GPUImageFilterGroup {
        //建立濾鏡組
        let filterGroup = GPUImageFilterGroup()
        //建立濾鏡(設定濾鏡的引來關係)
        bilateralFilter.addTarget(brightnessFilter)
        brightnessFilter.addTarget(exposureFilter)
        exposureFilter.addTarget(saturationFilter)
        //設定濾鏡起點 終點的filter
        filterGroup.initialFilters = [bilateralFilter]
        filterGroup.terminalFilter = saturationFilter
        return filterGroup
    }

功能以及方法的呼叫
    //翻轉
    @objc fileprivate func pickUpCameraSelected() {
        camera?.rotateCamera()
    }
    
    //濾鏡
    @objc fileprivate func filterCameraSelected() {
        filterView.show()
    }
    
    //結束錄製
    @objc fileprivate func endRecordSelected() {
        isEndRecording = true
        preView.removeFromSuperview()
        movieWriter.finishRecording()
        let filterGroup = getGroupFilters()
        filterGroup.removeTarget(movieWriter)
        camera?.stopCapture()
    }
    
    //播放
    @objc fileprivate func playRecordSelected() {
        print(fileURL)
        if !FileManager.default.fileExists(atPath: pathString) {
            showAlert("播放路徑不存在")
            return
        }
        let playerItem = AVPlayerItem(url: fileURL)
        player = AVPlayer(playerItem: playerItem)
        let layer = AVPlayerLayer(player: player)
        layer.frame = CGRect(x: (kWidth - 220)/2.0, y: 210, width: 220, height: 220)
        view.layer.addSublayer(layer)
        player?.play()
    }
    
    
    
    //拍照
    @objc fileprivate func takePhotoSelected() {
        
        guard let camera = camera else {
            fatalError("請退出程式重新錄製!")
        }
        
        if camera.isMember(of: GPUImageVideoCamera.self)  {
            showAlert("請檢視takePhotoSelected方法的說明")
            return
        }
        
        /*說明:
        GPUImageVideoCamera:通常用於實時視訊的錄製
         GPUImageStillCamera:用於拍攝當前手機的畫面, 並且儲存圖片
        1. 將
        fileprivate lazy var camera: GPUImageVideoCamera? = GPUImageVideoCamera(sessionPreset: AVCaptureSessionPresetHigh, cameraPosition: .front)
        改為
        fileprivate lazy var camera: GPUImageStillCamera? = GPUImageStillCamera(sessionPreset: AVCaptureSessionPresetHigh, cameraPosition: .front)
         
        2. 取消以下注釋
         
        */
        
        /*
        camera.capturePhotoAsImageProcessedUp(toFilter: getGroupFilters(), withCompletionHandler: {[weak self] (image, error) in
            if error == nil {
                UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)
                self?.showAlert("圖片儲存成功,請退出程式重新錄製!")
            }else{
                self?.showAlert("圖片儲存失敗,請退出程式重新錄製!")
            }
            self?.endRecordSelected()
        })
        */
 
    }
    

美顏效果的切換處理,可以參考 iOS GPUImage影象處理
    
    //根據滑動改變美顏效果
    fileprivate func configSliderChange() {
        
        filterView.sliderDidValueChanged = {[weak self] (_, slider, type) in
            print(slider.value)
            switch type {
                
            case .bilateralFilter:
                self?.bilateralFilter.distanceNormalizationFactor = 10.0 - CGFloat(slider.value)
                break
                
            case .exposureFilter:
                self?.exposureFilter.exposure = CGFloat(slider.value) * 20.0 - 10.0
                break
                
            case .brightnessFilter:
                self?.brightnessFilter.brightness = CGFloat(slider.value) * 2.0 - 1.0
                break
                
            case .saturationFilter:
                self?.saturationFilter.saturation = CGFloat(slider.value) * 2.0
                break
        
            }
        }
        
    }
    
    //開關美顏功能
    fileprivate func configSwitchChange() {
        
        filterView.switchDidValueChanged = {[weak self] (_, filterSwitch, isOpen) in
            if isOpen {
                self?.camera?.removeAllTargets()
                let group = self?.getGroupFilters()
                self?.camera?.addTarget(group)
                group?.addTarget(self?.preView)
            }else{
                self?.camera?.removeAllTargets()
                self?.camera?.addTarget(self?.preView)
            }
        }
        
    }

效果圖如下: