Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Swift4で動画を撮影・保存する

More than 1 year has passed since last update.

swift4で動画を撮影し、保存する手順を説明します。

手順

  1. frameworkの追加
  2. AVCaptureSession, AVCaptureDeviceの設定
  3. プレビューの生成
  4. 録画開始、停止ボタンを追加
  5. 動画を保存

frameworkの追加

AVFoundationとPhotosをimportします。

AVCaptureSession, AVCaptureDeviceの設定

はじめに入力と出力を設定し、その情報をAVCaptureSessionに渡します。

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

do {
    if videoDevice == nil || audioDevice == nil {
        throw NSError(domain: "device error", code: -1, userInfo: nil)
    }
    let captureSession = AVCaptureSession()

    // video inputを capture sessionに追加
    let videoInput = try AVCaptureDeviceInput(device: videoDevice!)
    captureSession.addInput(videoInput)

    // audio inputを capture sessionに追加
    let audioInput = try AVCaptureDeviceInput(device: audioDevice!)
    captureSession.addInput(audioInput)

    // 録画時間の上限を設けたい時は maxRecordedDurationを設定する
    fileOutput.maxRecordedDuration = CMTimeMake(30, 1)

    // 出力をsessionに追加
    captureSession.addOutput(fileOutput)

} catch {
    // エラー処理
}

プレビューの生成

AVCaptureVideoPreviewLayerを使い、画面全体にプレビューを表示します。

// プレビュー
let videoLayer : AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoLayer.frame = self.view.bounds
videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.view.layer.addSublayer(videoLayer)

captureSession.startRunning()

録画ボタンを追加

func setUpButton() {
    recordButton = UIButton(frame: CGRect(x: 0,y: 0,width: 120,height: 50))
    recordButton.backgroundColor = UIColor.gray
    recordButton.layer.masksToBounds = true
    recordButton.setTitle("録画開始", for: UIControlState.normal)
    recordButton.layer.cornerRadius = 20.0
    recordButton.layer.position = CGPoint(x: self.view.bounds.width/2, y:self.view.bounds.height-50)
    recordButton.addTarget(self, action: #selector(RecordViewController.onClickRecordButton(sender:)), for: .touchUpInside)

    self.view.addSubview(recordButton)
}

@objc func onClickRecordButton(sender: UIButton) {
    if !isRecording {
        // 録画開始
        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        let documentsDirectory = paths[0] as String
        let filePath : String? = "\(documentsDirectory)/temp.mp4"
        let fileURL : NSURL = NSURL(fileURLWithPath: filePath!)
        fileOutput.startRecording(to: fileURL as URL, recordingDelegate: self)

        isRecording = true
        changeButtonColor(target: recordButton, color: UIColor.red)
        recordButton.setTitle("録画中", for: .normal)
    } else {
        // 録画終了
        fileOutput.stopRecording()

        isRecording = false
        changeButtonColor(target: recordButton, color: UIColor.gray)
        recordButton.setTitle("録画開始", for: .normal)
    }
}

func changeButtonColor(target: UIButton, color: UIColor) {
    target.backgroundColor = color
}

動画を保存

録画が停止されるとこのメソッドが呼び出されるので、この中で動画を保存する処理を行います。

func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
    // ライブラリへ保存
    PHPhotoLibrary.shared().performChanges({
        PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputFileURL)
    }) { completed, error in
        if completed {
            print("Video is saved!")
        }
    }
}

ソースコード

import UIKit
import AVFoundation
import Photos

class RecordViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {
    let fileOutput = AVCaptureMovieFileOutput()

    var recordButton: UIButton!
    var isRecording = false

    override func viewDidLoad() {
        super.viewDidLoad()

        setUpPreview()
    }

    func setUpPreview() {
        let videoDevice = AVCaptureDevice.default(for: AVMediaType.video)
        let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)

        do {
            if self.videoDevice == nil || self.audioDevice == nil {
                throw NSError(domain: "device error", code: -1, userInfo: nil)
            }
            let captureSession = AVCaptureSession()

            // video inputを capture sessionに追加
            let videoInput = try AVCaptureDeviceInput(device: self.videoDevice!)
            captureSession.addInput(videoInput)

            // audio inputを capture sessionに追加
            let audioInput = try AVCaptureDeviceInput(device: self.audioDevice!)
            captureSession.addInput(audioInput)

            // max 30sec
            self.fileOutput.maxRecordedDuration = CMTimeMake(30, 1)
            captureSession.addOutput(fileOutput)

            // プレビュー
            let videoLayer : AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
            videoLayer.frame = self.view.bounds
            videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
            self.view.layer.addSublayer(videoLayer)

            captureSession.startRunning()

            setUpButton()
        } catch {
            // エラー処理
        }
    }

    func setUpButton() {
        recordButton = UIButton(frame: CGRect(x: 0,y: 0,width: 120,height: 50))
        recordButton.backgroundColor = UIColor.gray
        recordButton.layer.masksToBounds = true
        recordButton.setTitle("録画開始", for: UIControlState.normal)
        recordButton.layer.cornerRadius = 20.0
        recordButton.layer.position = CGPoint(x: self.view.bounds.width/2, y:self.view.bounds.height-50)
        recordButton.addTarget(self, action: #selector(RecordViewController.onClickRecordButton(sender:)), for: .touchUpInside)

        self.view.addSubview(recordButton)
    }

    @objc func onClickRecordButton(sender: UIButton) {
        if !isRecording {
            // 録画開始
            let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
            let documentsDirectory = paths[0] as String
            let filePath : String? = "\(documentsDirectory)/temp.mp4"
            let fileURL : NSURL = NSURL(fileURLWithPath: filePath!)
            fileOutput.startRecording(to: fileURL as URL, recordingDelegate: self)

            isRecording = true
            changeButtonColor(target: recordButton, color: UIColor.red)
            recordButton.setTitle("録画中", for: .normal)
        } else {
            // 録画終了
            fileOutput.stopRecording()

            isRecording = false
            changeButtonColor(target: recordButton, color: UIColor.gray)
            recordButton.setTitle("録画開始", for: .normal)
        }
    }

    func changeButtonColor(target: UIButton, color: UIColor) {
        target.backgroundColor = color
    }

    func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
        // ライブラリへ保存
        PHPhotoLibrary.shared().performChanges({
            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputFileURL)
        }) { completed, error in
            if completed {
                print("Video is saved!")
            }
        }
    }
}

daigou26
主にモバイルアプリ開発をしてます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away