iOSアプリ開発勉強中の初学者大学生です。
開発環境
- Xcode 11
- Swift 5
- iOS 13
AVFoundationとPhotosを使用したビデオ撮影とスローモーション撮影の機能を実装しようとしています。
いくつかのサイトを参考に作成して制作しました。
実機ビルドでエラーは出ないのですが、端末の画面は真っ黒な状態になってしまいます。
※シミュレーターではカメラがなく動作しないので実機ビルドをしています。
ビルド結果で真っ黒になるという症状のis Initial View Controllerのチェックも確認しています。
Swift
1import UIKit 2import AVFoundation 3import Photos 4import Foundation 5 6class ViewController: UIViewController,AVCaptureFileOutputRecordingDelegate { 7 8 9 @IBOutlet weak var previewView: UIView! 10 11 //セッション 12 var session: AVCaptureSession! 13 //ビデオデバイス 14 var videoDevice: AVCaptureDevice! 15 //オーディオデバイス 16 var audioDevice: AVCaptureDevice! 17 //ファイル出力 18 var fileOutput: AVCaptureMovieFileOutput! 19 //プレビュー 20 var previewLayer: AVCaptureVideoPreviewLayer! 21 22 override func viewDidLoad() { 23 super.viewDidLoad() 24 //セッション生成 25 session = AVCaptureSession() 26 //入力:背面カメラ 27 videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) 28 let videoInput = try! AVCaptureDeviceInput.init(device: videoDevice) 29 session.addInput(videoInput) 30 31 //フォーマット指定 32 switchFormat(desired: 60.0) 33 34 //入力:マイク 35 audioDevice = AVCaptureDevice.default(for: .audio) 36 let audioInput = try! AVCaptureDeviceInput.init(device: audioDevice) 37 session.addInput(audioInput) 38 39 //出力 40 fileOutput = AVCaptureMovieFileOutput() 41 session.addOutput(fileOutput) 42 43 //プレビュー 44 previewLayer = AVCaptureVideoPreviewLayer() 45 previewLayer.frame = view.bounds 46 previewLayer.videoGravity = .resizeAspectFill 47 view.layer.addSublayer(previewLayer) 48 49 //セッション開始 50 session.startRunning() 51 } 52 53 func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) { 54 print("録画完了") 55 } 56 57 private func switchFormat(desired: Double) { 58 let isRunning = session.isRunning 59 if isRunning { session.stopRunning() } 60 61 //取得したフォーマットを格納する変数 62 var selectedFormat: AVCaptureDevice.Format! = nil 63 //そのフレームレートの中で一番大きい解像度を取得する 64 var currentMaxWidth: Int32 = 0 65 66 //フォーマット探索 67 for format in videoDevice.formats { 68 for range: AVFrameRateRange in format.videoSupportedFrameRateRanges { 69 let description = format.formatDescription as CMFormatDescription //フォーマットの説明 70 let dimensions = CMVideoFormatDescriptionGetDimensions(description) //幅・高さの情報 71 let width = dimensions.width //幅 72 73 //指定のフレームレートで一番大きな解像度を得る 74 if desired == range.maxFrameRate && currentMaxWidth <= width && width <= 1920 { 75 selectedFormat = format 76 currentMaxWidth = width 77 } 78 } 79 } 80 81 if selectedFormat != nil { 82 do { 83 try videoDevice.lockForConfiguration() 84 videoDevice.activeFormat = selectedFormat 85 videoDevice.activeVideoMinFrameDuration = CMTimeMake(value: 1, timescale: Int32(desired)) 86 videoDevice.activeVideoMaxFrameDuration = CMTimeMake(value: 1, timescale: Int32(desired)) 87 videoDevice.unlockForConfiguration() 88 89 if isRunning { session.startRunning() } 90 } 91 catch { 92 print("フォーマット・フレームレートが指定できませんでした : (desired)fps") 93 } 94 } 95 else { 96 print("フォーマットが取得できませんでした : (desired)fps") 97 } 98 } 99 100 //録画開始 101 private func startRecording() { 102 //Documents ディレクトリ直下にファイルを生成する 103 let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) 104 let documentsDirectory = paths[0] as String 105 106 //現在時刻をファイル名に付与する 107 let formatter = DateFormatter() 108 formatter.dateFormat = "yyyyMMddHHmmssSSS" 109 let filePath: String? = "(documentsDirectory)/myvideo-(formatter.string(from: Date())).mp4" 110 let fileURL = NSURL(fileURLWithPath: filePath!) 111 112 print("録画開始 : (filePath!)") 113 fileOutput?.startRecording(to: fileURL as URL, recordingDelegate: self) 114 115 116 } 117 118 //録画停止 119 private func stopRecording() { 120 print("録画停止") 121 fileOutput?.stopRecording() 122 123 } 124 125 //アプリ内に保存したmp4ファイルをカメラロールに書き出す 126 private func outputVideos() { 127 //Documentsディレクトリ 128 let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] 129 do { 130 //Documenrtsディレクトリ配下のファイル一覧を取得する 131 let contentUrls = try FileManager.default.contentsOfDirectory(at: documentDirectoryURL, includingPropertiesForKeys: nil) 132 for contentUrl in contentUrls { 133 //拡張しで判定する 134 if contentUrl.pathExtension == "mp4" { 135 //mp4ファイルならカメラロールに書き出す 136 PHPhotoLibrary.shared().performChanges({ 137 PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: contentUrl) 138 }) { (isCompleted, error) in 139 if isCompleted { 140 //カメラロールに書き出し成功 141 do { 142 try FileManager.default.removeItem(atPath: contentUrl.path) 143 print("カメラロール書き出し・ファイル削除成功 : (contentUrl.lastPathComponent)") 144 } 145 catch { 146 print("カメラロール書き出し後のファイル削除失敗 : (contentUrl.lastPathComponent)") 147 } 148 } 149 else { 150 print("カメラロール書き出し失敗 : (contentUrl.lastPathComponent)") 151 } 152 } 153 } 154 } 155 } 156 catch { 157 print("ファイル一覧取得エラー") 158 } 159 } 160 161}
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。