カテゴリー: iOS

[Swift]動画撮影にて好きなサイズでプレビュー表示する

はじめに

こんにちは、nukkyです。
今回はメインのビューの右上とかに小窓の様なプレビューにカメラの映像を出して、動画撮影するという機能を作成したのですが、思ったより苦戦したので備忘録がてら記事にしたいと思います。

前提条件

Xcode 9.1
iOS 11 Simulator
Swift 4.0

 

実装

まずは以下の二つをインポートします。
「AVFoundation」は動画撮影に、「Photos」動画を保存する際に必要になってきます。

import AVFoundation
import Photos

動画保存の為に「AVCaptureFileOutputRecordingDelegate」を設定します。

class RecordViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {

以下のグローバル変数を宣言しておきます。

// カメラやマイクへのセッション管理用
var captureSession:AVCaptureSession!
// 動画ファイルの出力管理用
var fileOutput:AVCaptureMovieFileOutput!
// View上にカメラの映像を表示用
var videoLayer:AVCaptureVideoPreviewLayer!
// 動画撮影状態管理用フラグ
var isRecoding = false

AVCaptureSessionとAVCaptureMovieFileOutputの初期化を行います。
今回はフロントカメラを使用します。

// セッションのインスタンス生成
captureSession = AVCaptureSession()

// 入力(前面カメラ)
var videoDevice: AVCaptureDevice?
// OSバージョンでカメラの指定が異なる
if #available(iOS 10.0, *) {
    let discoverySession = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInDuoCamera],
                                                           mediaType: AVMediaTypeVideo,
                                                           position: .front)
    for device in (discoverySession?.devices)! {
        videoDevice = device
    }
}
else {
    let videoDevices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)
    for device in videoDevices!{
        let device = device as! AVCaptureDevice
        if device.position == AVCaptureDevicePosition.front {
            videoDevice = device
            break
        }
    }
}
let videoInput = try! AVCaptureDeviceInput.init(device: videoDevice)
captureSession.addInput(videoInput)
// 入力(マイク)動画の音声いらない?もしくは動画保存中に録音もするから無いほうがいい?
let audioDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
let audioInput = try! AVCaptureDeviceInput.init(device: audioDevice)
captureSession.addInput(audioInput);
// 出力(動画ファイル)
fileOutput = AVCaptureMovieFileOutput()
captureSession.addOutput(fileOutput)

ここが今回の肝ですが、カメラの映像を小窓の様にして表示させます。
今回はViewの左上に240の正方形で表示させます。

// プレビュー表示
func previewInitialization(view:UIView, frame: CGRect = CGRect(x: 0, y: 60, width: 240, height: 240)) {
    if let videoLayer = AVCaptureVideoPreviewLayer.init(session: captureSession) {
        videoLayer.frame = frame
        videoLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        self.videoLayer = videoLayer
        view.layer.addSublayer(self.videoLayer)
    }
}

録画の開始と終了は以下になります。

// 録画開始
func startRecord(fileURL:NSURL) {
    // toOutputFileURLにファイルのパスをファイル名と拡張子込みで渡す
    fileOutput?.startRecording(toOutputFileURL: fileURL as URL!, recordingDelegate: self)
}

// 録画終了
func stopRecord() {
    fileOutput.stopRecording()
}

stopRecordingメソッドを呼ぶと以下のDelegateが呼ばれるので、ここでファイルを保存します。

// 録画終了時に動画を保存
public func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) {
    if error != nil {
        // エラー処理
        return
    }
    // ライブラリへの保存
    PHPhotoLibrary.shared().performChanges({
        PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputFileURL)
    }) { completed, error in
        if completed {
            print("Video is saved!")
        }
    }
}

 

 

さいごに

駆け足になってしまいましたが、これで自由にカメラの映像をViewに重ねて動画の保存ができると思います。
個人的に、カメラの映像のframe自由に設定して画面表示する箇所がソースにすると大した事ないのですが調査も含めて苦戦したので、これが誰かのお役に立てれば報われます。

nukky

シェア
執筆者:
nukky
タグ: Swift

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前