swift4で動画を撮影し、保存する手順を説明します。
手順
- frameworkの追加
- AVCaptureSession, AVCaptureDeviceの設定
- プレビューの生成
- 録画開始、停止ボタンを追加
- 動画を保存
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!")
}
}
}
}