【Swift】AVFoundationを使用して動画撮影機能を実装

#AVFoundationとは

AVFoundationとは、静止画・音声・動画などのメディアの作成・再生・編集を行うことの出来るフレームワークです。

https://developer.apple.com/documentation/avfoundation

AVFoundationは、大まかに下記の３つの構成になっています。

・デバイス(AVCaptureDevice)
・セッション(AVCaptureSession)
・出力(AVCaptureOutput)

AVCaptureDeviceクラスで取得した入力テータを、AVCaptureDeviceInputクラスを用いてAVCaptureSessionに渡します。AVCaptureSessionクラスから出力されるデータは、AVCaptureOutputクラスによって、静止画、音声ファイル、動画ファイル、動画フレームデータ、メタデータなど様々な形式で出力されます。

#サンプルの挙動

ボタンタッチで録画開始→もう一度ボタンタッチで録画終了→シェア

#コード

```swift
import UIKit
import AVFoundation

final class ViewController: UIViewController {

    private let captureSession = AVCaptureSession()
    private let fileOutput = AVCaptureMovieFileOutput()
    private var recordButton: UIButton!
    
    override func viewDidLoad() {
        
        super.viewDidLoad()
        self.view.backgroundColor = .black
        self.setUpCamera()
    }
    
    // デバイスの設定
    private func setUpCamera() {
        
        // デバイスの初期化
        let videoDevice: AVCaptureDevice? = AVCaptureDevice.default(for: AVMediaType.video)
        let audioDevice: AVCaptureDevice? = AVCaptureDevice.default(for: AVMediaType.audio)
       
        //ビデオの画質
        captureSession.sessionPreset = AVCaptureSession.Preset.high
        
        // ビデオのインプット設定
        let videoInput: AVCaptureDeviceInput = try! AVCaptureDeviceInput(device: videoDevice!)
        captureSession.addInput(videoInput)
        
        // 音声のインプット設定
        let audioInput = try! AVCaptureDeviceInput(device: audioDevice!)
        captureSession.addInput(audioInput)
        captureSession.addOutput(fileOutput)
        captureSession.startRunning()
        
        // ビデオ表示
        let videoLayer : AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        videoLayer.frame = self.view.bounds
        videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
        self.view.layer.addSublayer(videoLayer)
        
        // 録画ボタン
        self.recordButton = UIButton(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
        self.recordButton.backgroundColor = .white
        self.recordButton.layer.masksToBounds = true
        self.recordButton.layer.cornerRadius = 80 / 2
        self.recordButton.layer.position = CGPoint(x: self.view.bounds.width / 2, y:self.view.bounds.height - 120)
        self.recordButton.addTarget(self, action: #selector(self.tappedRecordButton(sender:)), for: .touchUpInside)
        self.view.addSubview(recordButton)
    }
    
    @objc private func tappedRecordButton(sender: UIButton) {

        if self.fileOutput.isRecording {
            // 録画終了
            fileOutput.stopRecording()
            
            self.recordButton.backgroundColor = .white
        } else {
            // 録画開始
            let tempDirectory: URL = URL(fileURLWithPath: NSTemporaryDirectory())
            let fileURL: URL = tempDirectory.appendingPathComponent("sampletemp")
            fileOutput.startRecording(to: fileURL, recordingDelegate: self)
            
            self.recordButton.backgroundColor = .red
        }
    }
}

extension ViewController: AVCaptureFileOutputRecordingDelegate {
    
    func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
        
        //動画をシェア
        let activityItems = [outputFileURL as Any, "#SampleVideo"] as [Any]
        let activityController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
        
        activityController.popoverPresentationController?.sourceView = self.view
        activityController.popoverPresentationController?.sourceRect = self.view.frame
        self.present(activityController, animated: true, completion: nil)
    }
}
```

##参考記事

https://qiita.com/t_okkan/items/f2ba9b7009b49fc2e30a
https://dev.classmethod.jp/articles/ios-avfoundation/
https://superhahnah.com/swift-avcapture-settings/