swift 视频录制保存

swift 视频录制  

1 添加访问的权限

Privacy - Camera Usage Description

Privacy - Microphone Usage Description

Privacy - Photo Library Usage Description 

2  视频录制  

//  视频录制 

//  IWVideoRecordingController.swift

//  VideoRecording

//

//  Created by goWhere on 16/7/4.

//  Copyright © 2016年 iwhere. All rights reserved.

//

importUIKit

importAVFoundation

importPhotos

class IWVideoRecordingController: UIViewController {


    //  最常视频录制时间,单位 秒

    let MaxVideoRecordTime = 6000

    //  MARK: - Properties

    //  视频捕获会话,他是 input 和 output 之间的桥梁,它协调着 input 和 output 之间的数据传输

    let captureSession = AVCaptureSession()

    //  视频输入设备,前后摄像头

    var camera: AVCaptureDevice?

    //  展示界面

    var previewLayer: AVCaptureVideoPreviewLayer!

    //  HeaderView 

    var headerView: UIView!

    //  音频输入设备

    let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)

    //  将捕获到的视频输出到文件

    let fileOut = AVCaptureMovieFileOutput()


    //  开始、停止按钮

    var startButton, stopButton: UIButton!

    //  前后摄像头转换、闪光灯 按钮

    var cameraSideButton, flashLightButton: UIButton!

    //  录制时间 Label

    var totolTimeLabel: UILabel!

    //  录制时间Timer

    vartimer:Timer?

    var secondCount = 0

    //  视频操作View

    var operatorView: IWVideoOperatorView!

    //  表示当时是否在录像中

    var isRecording = false



    //  MARK: - LifeCycle

    override func viewDidLoad() {

        super.viewDidLoad()


        //  录制视频基本设置

        setupAVFoundationSettings()

        //  UI 布局

        setupButton()

        setupHeaderView()

    }


    overridefuncviewWillAppear(_animated:Bool) {

        super.viewWillAppear(animated)

        navigationController?.isNavigationBarHidden = true

    }

    overridefuncviewWillDisappear(_animated:Bool) {

        super.viewWillDisappear(animated)

        navigationController?.isNavigationBarHidden = false

    }


    //  MARK: - Private Methods

    /// 对视频进行基本设置

    private func setupAVFoundationSettings() {

        // 相机

        camera = cameraWithPosition(position: AVCaptureDevice.Position.back)

        //  设置视频清晰度

        captureSession.sessionPreset = AVCaptureSession.Preset.vga640x480

        //  添加视频、音频输入设备

        ifletvideoInput =try?AVCaptureDeviceInput(device:camera!) {

            captureSession.addInput(videoInput)

        }

        ifaudioDevice!=nil,

           letaudioInput =try?AVCaptureDeviceInput(device:audioDevice!) {

            captureSession.addInput(audioInput)

        }

        //  添加视频捕获输出

        self.captureSession.addOutput(fileOut)


        //  使用 AVCaptureVideoPreviewLayer 可以将摄像头拍到的实时画面显示在 ViewController 上

        letvideoLayer =AVCaptureVideoPreviewLayer(session:self.captureSession)

        videoLayer.frame=view.bounds

        videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill

        view.layer.addSublayer(videoLayer)

        previewLayer= videoLayer

        //  启动 Session 回话

        self.captureSession.startRunning()

    }


    ///选择摄像头

    private func cameraWithPosition(position: AVCaptureDevice.Position) -> AVCaptureDevice? {

        let devices = AVCaptureDevice.devices(for: AVMediaType.video)

        foritemindevices {

            ifitem.position== position {

                returnitem

            }

        }

        returnnil

    }



    //  MARK: - UI Settings

    /**

     创建按钮

     */

    private func setupButton() {

        //  开始按钮

        startButton=prepareButtons(btnTitle:"开始",btnSize:CGSize(width:120,height:50),btnCenter:CGPoint(x:view.bounds.width/2-70,y:view.bounds.height-50))

        startButton.backgroundColor = UIColor.red

        startButton.addTarget(self, action: #selector(onClickedStartButton(startButton:)), for: .touchUpInside)


        //  结束按钮

        stopButton=prepareButtons(btnTitle:"结束",btnSize:CGSize(width:120,height:50),btnCenter:CGPoint(x:view.bounds.width/2+70,y:view.bounds.height-50))

        stopButton.backgroundColor = UIColor.lightGray

        stopButton.isUserInteractionEnabled = false

        stopButton.addTarget(self, action: #selector(onClickedEndButton(endButton:)), for: .touchUpInside)

    }


    //  开始、结束按钮风格统一

    privatefuncprepareButtons(btnTitletitle:String,btnSizesize:CGSize,btnCentercenter:CGPoint) ->UIButton{

        letbutton =UIButton(frame:CGRect(x:0,y:0,width: size.width,height: size.height))

        button.center= center

        button.clipsToBounds=true

        button.layer.cornerRadius=20

        button.setTitle(title,for: .normal)

        button.setTitleColor(UIColor.white, for: .normal)

        view.addSubview(button)

        returnbutton

    }


    //  headerView

    private func setupHeaderView() {

        headerView=UIView(frame:CGRect(x:0,y:0,width:view.bounds.width,height:64))

        headerView.backgroundColor = UIColor.black.withAlphaComponent(0.3)

        view.addSubview(headerView)


        letcenterY =headerView.center.y+5

        letdefaultWidth:CGFloat=40


        //  返回、摄像头调整、时间、闪光灯四个按钮

        letbackButton =UIButton(frame:CGRect(x:0,y:0,width:20,height:20))

        backButton.setBackgroundImage(UIImage(named: "iw_back"), for: .normal)

        backButton.addTarget(self,action:#selector(backAction),for: .touchUpInside)

        backButton.center=CGPoint(x:25,y: centerY)

        headerView.addSubview(backButton)


        cameraSideButton=UIButton(frame:CGRect(x:0,y:0,width: defaultWidth,height: defaultWidth *68/99.0))

        cameraSideButton.setBackgroundImage(UIImage(named: "iw_cameraSide"), for: .normal)

        cameraSideButton.center=CGPoint(x:100,y: centerY)

        cameraSideButton.addTarget(self, action: #selector(changeCamera(cameraSideButton:)), for: .touchUpInside)

        headerView.addSubview(cameraSideButton)


        totolTimeLabel=UILabel(frame:CGRect(x:0,y:0,width:100,height:20))

        totolTimeLabel.center=CGPoint(x:headerView.center.x,y: centerY)

        totolTimeLabel.textColor = UIColor.white

        totolTimeLabel.textAlignment = .center

        totolTimeLabel.font = UIFont.systemFont(ofSize: 19)

       // 时间的设置  

        totolTimeLabel.text = "00:00:00"

        view.addSubview(totolTimeLabel)


        flashLightButton=UIButton(frame:CGRect(x:0,y:0,width: defaultWidth,height: defaultWidth *68/99.0))

        flashLightButton.setBackgroundImage(UIImage(named: "iw_flashOn"), for: .selected)

        flashLightButton.setBackgroundImage(UIImage(named: "iw_flashOff"), for: .normal)

        flashLightButton.center=CGPoint(x:headerView.bounds.width-100,y: centerY)

        flashLightButton.addTarget(self, action: #selector(switchFlashLight(flashButton:)), for: .touchUpInside)

        headerView.addSubview(flashLightButton)


    }


    //  MARK: - UIButton Actions

    //  按钮点击事件

    //  点击开始录制视频

    @objc private func onClickedStartButton(startButton: UIButton) {

        hiddenHeaderView(isHidden: true)

        //  开启计时器

        timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(videoRecordingTotolTime), userInfo: nil, repeats: true)



        if!isRecording{

            //  记录状态: 录像中 ...

            isRecording=true

            captureSession.startRunning()


            //  设置录像保存地址,在 Documents 目录下,名为 当前时间.mp4

            let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)

            letdocumentDirectory = path[0]asString

            letfilePath:String? ="\(documentDirectory)/\(Date()).mp4"

            letfileUrl:URL? =URL(fileURLWithPath: filePath!)

            //  启动视频编码输出

            fileOut.startRecording(to: fileUrl!, recordingDelegate: self)


            //  开始、结束按钮改变颜色

            startButton.backgroundColor=UIColor.lightGray

            stopButton.backgroundColor = UIColor.red

            startButton.isUserInteractionEnabled=false

            stopButton.isUserInteractionEnabled = true

        }


    }


    //  点击停止按钮,停止了录像

    @objc private func onClickedEndButton(endButton: UIButton) {

        hiddenHeaderView(isHidden: false)


        //  关闭计时器

        timer?.invalidate()

        timer=nil

        secondCount=0


        ifisRecording{

            //  停止视频编码输出

            captureSession.stopRunning()


            //  记录状态: 录像结束 ...

            isRecording=false


            //  开始结束按钮颜色改变

            startButton.backgroundColor = UIColor.red

            stopButton.backgroundColor = UIColor.lightGray

            startButton.isUserInteractionEnabled = true

            stopButton.isUserInteractionEnabled = false

        }


        //  弹出View

        operatorView = (Bundle.main.loadNibNamed("IWVideoOperatorView", owner: self, options: nil)?.first as! IWVideoOperatorView)

        operatorView.getSuperViewController(superController: self)


        operatorView.frame = CGRect(x: 0, y: view.bounds.height, width: view.bounds.width, height: view.bounds.height)

        view.addSubview(operatorView)


        UIView.animate(withDuration: 0.3) {

            self.operatorView.frame.origin.y=0

        }

    }


    //  录制时间

    @objc private func videoRecordingTotolTime() {

        secondCount+=1


        //  判断是否录制超时

        if secondCount == MaxVideoRecordTime {

            timer?.invalidate()

            HsuAlert(title: "最常只能录制十分钟呢", message: nil, ensureTitle: "确定", cancleTitle: nil, ensureAction: nil, cancleAction: nil)

        }


        lethours =secondCount/3600

        letmintues = (secondCount%3600) /60

        letseconds =secondCount%60 


        totolTimeLabel.text=String(format:"%02d", hours) +":"+String(format:"%02d", mintues) +":"+String(format:"%02d", seconds)

    }


    //  是否隐藏 HeaderView

    func hiddenHeaderView(isHidden: Bool) {

        ifisHidden {

            UIView.animate(withDuration:0.2) {

               self.headerView.frame.origin.y-=64

            }

        }else{

            UIView.animate(withDuration:0.2) {

                self.headerView.frame.origin.y+=64

            }

        }

    }


    //  返回上一页

    @objc private func backAction() {

        self.navigationController?.popViewController(animated: true)

    }


    //  调整摄像头

    @objc private func changeCamera(cameraSideButton: UIButton) {

        cameraSideButton.isSelected= !cameraSideButton.isSelected

        captureSession.stopRunning()

        //  首先移除所有的 input

        iflet  allInputs =captureSession.inputsas? [AVCaptureDeviceInput] {

            forinputinallInputs {

                captureSession.removeInput(input)

            }

        }


        changeCameraAnimate()


        //  添加音频输出

        ifaudioDevice!=nil,

            letaudioInput =try?AVCaptureDeviceInput(device:audioDevice!) {

            self.captureSession.addInput(audioInput)

        }

        ifcameraSideButton.isSelected{

            camera = cameraWithPosition(position: .front)

            ifletinput =try?AVCaptureDeviceInput(device:camera!) {

                captureSession.addInput(input)

            }


            ifflashLightButton.isSelected{

                flashLightButton.isSelected=false

            }

        }else{

            camera = cameraWithPosition(position: .back)

            ifletinput =try?AVCaptureDeviceInput(device:camera!) {

                captureSession.addInput(input)

            }

        }

    }


    //  切换动画

    private func changeCameraAnimate() {

        letchangeAnimate =CATransition()

        changeAnimate.delegate=self

        changeAnimate.duration=0.4

        changeAnimate.type=CATransitionType(rawValue:"oglFlip")

        changeAnimate.subtype=CATransitionSubtype.fromRight

        previewLayer.add(changeAnimate,forKey:"changeAnimate")

    }


    //  开启闪光灯

    @objc private func switchFlashLight(flashButton: UIButton) {

        if self.camera?.position == AVCaptureDevice.Position.front {

            return

        }

        let camera = cameraWithPosition(position: .back)

        ifcamera?.torchMode==AVCaptureDevice.TorchMode.off{

            do{

                trycamera?.lockForConfiguration()

            }catchleterrorasNSError{

                print("开启闪光灯失败 : \(error)")

            }


            camera?.torchMode=AVCaptureDevice.TorchMode.on

            camera?.flashMode=AVCaptureDevice.FlashMode.on

            camera?.unlockForConfiguration()


            flashButton.isSelected=true

        }else{

            do{

                trycamera?.lockForConfiguration()

            }catchleterrorasNSError{

                print("关闭闪光灯失败: \(error)")

            }


            camera?.torchMode=AVCaptureDevice.TorchMode.off

            camera?.flashMode=AVCaptureDevice.FlashMode.off

            camera?.unlockForConfiguration()


            flashButton.isSelected=false

        }

    }


    override var shouldAutorotate: Bool {

        return false

    }


    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {

        return.portrait

    }

}

// MARK: - CAAnimationDelegate

extension IWVideoRecordingController: CAAnimationDelegate {

    ///动画开始

    func animationDidStart(_ anim: CAAnimation) {

        captureSession.startRunning()

    }


    ///动画结束

    funcanimationDidStop(_anim:CAAnimation,finishedflag:Bool) {

    }

}

// MARK: - AVCaptureFileOutputRecordingDelegate

extension IWVideoRecordingController: AVCaptureFileOutputRecordingDelegate {

    ///开始录制

    funcfileOutput(_output:AVCaptureFileOutput,didStartRecordingTofileURL:URL,fromconnections: [AVCaptureConnection]) {


    }


    ///结束录制

    funcfileOutput(_output:AVCaptureFileOutput,didFinishRecordingTooutputFileURL:URL,fromconnections: [AVCaptureConnection],error:Error?) {

        operatorView.getVideoUrl(videoUrl: outputFileURL)

    }

}


3 .  // 将视频保存 在本地  

private func saveVideoToAlbum(videoUrl: URL) {

        var info =""

        // 保存的方法 

        PHPhotoLibrary.shared().performChanges({

            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoUrl)

        }) { (success, error)in

            if success {

                info ="保存成功"

            }else{

                info ="保存失败,err = \(error.debugDescription)"

            }


            DispatchQueue.main.async{

                letalertVC =UIAlertController(title: info,message:nil,preferredStyle: .alert)

                alertVC.addAction(UIAlertAction(title:"OK",style: .default,handler:nil))

                self.controller.present(alertVC,animated:true,completion:nil)

            }

        }

    }

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容