30
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

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!")
            }
        }
    }
}

30
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?