Posted at

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

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