1. 程式人生 > >iOS 音視訊採集以及寫入檔案(swift)

iOS 音視訊採集以及寫入檔案(swift)

iOS音視訊採集以及寫入檔案(swift)


注意:配置允許訪問相機與麥克風參考這裡
1.初始化檔案屬性
class ViewController: UIViewController {
    
    fileprivate lazy var session: AVCaptureSession = AVCaptureSession()
    //視訊輸出
    fileprivate var videoOutPut: AVCaptureVideoDataOutput?
    //預覽層
    fileprivate var previewLayer: AVCaptureVideoPreviewLayer?
    //視訊輸入
    fileprivate var videoInput: AVCaptureDeviceInput?
    //檔案輸出
    fileprivate var fileOutPut: AVCaptureMovieFileOutput?

    override func viewDidLoad() {
        super.viewDidLoad()
        //MARK: 視訊採集
        initVideoInputOutput()
        //MARK: 音訊採集
        initAudioInputOutput()
        //MARK: 建立預覽層
        initPreViewLayer()
    }
    
}


2.音視訊進行採集
extension ViewController {
    //視訊採集
    fileprivate func initVideoInputOutput(){
        //視訊輸入
        guard let devices = AVCaptureDevice.devices() as? [AVCaptureDevice] else{return}
        guard let device = devices.filter({ $0.position == .front }).first else {return}
        guard let input = try? AVCaptureDeviceInput(device: device) else {return}
        self.videoInput = input
        //視訊輸出
        let output = AVCaptureVideoDataOutput()
        output.setSampleBufferDelegate(self, queue: DispatchQueue.global())
        self.videoOutPut = output
        //新增輸入輸出
        addInputOutPut(input, output)
    }
    
    //音訊採集
    fileprivate func initAudioInputOutput(){
        //音訊輸入
        guard let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) else {return}
        guard let input = try? AVCaptureDeviceInput(device: device) else {return}
        //音訊輸出
        let output = AVCaptureAudioDataOutput()
        output.setSampleBufferDelegate(self, queue: DispatchQueue.global())
        //新增輸入輸出
        addInputOutPut(input, output)
    }
    
    //新增輸入和輸出
    private func addInputOutPut(_ input: AVCaptureInput, _ output: AVCaptureOutput) {
        //新增輸入輸出
        session.beginConfiguration()
        if session.canAddInput(input) {
            session.addInput(input)
        }
        if session.canAddOutput(output){
            session.addOutput(output)
        }
        session.commitConfiguration()
    }
    //建立預覽層
    fileprivate func initPreViewLayer(){
        guard let preLayer = AVCaptureVideoPreviewLayer(session: session) else {return}
        self.previewLayer = preLayer
        preLayer.frame = view.bounds
        view.layer.insertSublayer(preLayer, at: 0)
    }
}


3.採集的代理方法
//MARK: AVCapture delegate
extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate {
    func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
        if videoOutPut?.connection(withMediaType: AVMediaTypeVideo) == connection {
            print("採集到視訊資料")
        }else{
            print("採集到音訊資料")
        }
    }
}


4.開始採集、結束採集、切換攝像頭方法呼叫
extension ViewController{

    //開始採集
    @IBAction func startCapture(_ sender: Any) {
        print("startCapture")
        session.startRunning()
        movieOutPutFile()
    }
    
    //結束採集
    @IBAction func endCapture(_ sender: Any) {
        print("endCapture")
        self.fileOutPut?.stopRecording()
        session.stopRunning()
        previewLayer?.removeFromSuperlayer()
    }
    
    //切換鏡頭
    @IBAction func changeDirection(_ sender: Any) {
        print("changeDirection")
        guard let videoInput = videoInput else {
            return
        }
        let position: AVCaptureDevicePosition = videoInput.device.position == .front ? .back : .front
        guard let devices = AVCaptureDevice.devices() as? [AVCaptureDevice] else{return}
        guard let device = devices.filter({ $0.position == position }).first else {return}
        guard let newInput = try? AVCaptureDeviceInput(device: device) else {return}
        self.videoInput = newInput
        session.beginConfiguration()
        session.removeInput(videoInput)
        if session.canAddInput(newInput) {
            session.addInput(newInput)
        }
        session.commitConfiguration()
    }
    
    //寫入檔案
    fileprivate func movieOutPutFile() {
        let fileOutPut = AVCaptureMovieFileOutput()
        let connection = fileOutPut.connection(withMediaType: AVMediaTypeVideo)
        connection?.automaticallyAdjustsVideoMirroring = true
        print(session)
        session.beginConfiguration()
        session.removeOutput(self.fileOutPut)
        if session.canAddOutput(fileOutPut) {
            session.addOutput(fileOutPut)
        }
        session.commitConfiguration()
        self.fileOutPut = fileOutPut
        let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/glt.mp4"
        fileOutPut.startRecording(toOutputFileURL: URL(fileURLWithPath: path), recordingDelegate: self)
    }
    
}

5.寫入檔案代理
//MARK: 寫入檔案代理
extension ViewController: AVCaptureFileOutputRecordingDelegate {

    func capture(_ captureOutput: AVCaptureFileOutput!, didStartRecordingToOutputFileAt fileURL: URL!, fromConnections connections: [Any]!) {
        print("開始錄製")
    }
    
    func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) {
        print("結束錄製")
    }
    
}