teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

1

サンプルコードを追加

2020/10/01 13:52

投稿

TsukubaDepot
TsukubaDepot

スコア5086

answer CHANGED
@@ -19,4 +19,200 @@
19
19
  4. Info.plist を編集する
20
20
  5. 「実機で」実行する
21
21
 
22
- というステップで実行できると思います。
22
+ というステップで実行できると思います。
23
+
24
+ ##2020年10月1日追記
25
+ 参考にされたコードは iOS10 以降ではそのまま使えないため、使えるように一部変更を加えてみました。
26
+
27
+ また、オリジナルのコードはだと、録画終了後指定したフォルダに映像を保存するだけで、実はビデオライブラリには保存されないため、録画状態を確認することができません(要は、「写真」アプリで録画された映像を確認することができない)。
28
+
29
+ また、UIの一部が少し紛らわしいため、その修正も加えたコードを下記に提示しますので、コード中のコメントをよく読まれた上、試してみていただけますでしょうか。
30
+
31
+ ```Swift
32
+ // This code is originally based on http://faboplatform.github.io/SwiftDocs/5.avfoundation/003_avfoundation/
33
+ // Some lines of this program are modified to enable to run this code correctly after iOS 10.0 ,and added codes to save captured image to the Photo library.
34
+
35
+ import UIKit
36
+ import AVFoundation
37
+
38
+ // MARK: - フォトライブラリに保存するために必要
39
+ import Photos
40
+
41
+ class ViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {
42
+
43
+ // ビデオのアウトプット.
44
+ private var myVideoOutput: AVCaptureMovieFileOutput!
45
+
46
+ // スタートボタン.
47
+ private var myButtonStart: UIButton!
48
+
49
+ // ストップボタン.
50
+ private var myButtonStop: UIButton!
51
+
52
+ override func viewDidLoad() {
53
+ super.viewDidLoad()
54
+ print(#function)
55
+ // セッションの作成.
56
+ let mySession = AVCaptureSession()
57
+
58
+ // デバイス.
59
+ var myDevice = AVCaptureDevice.default(for: .video)
60
+
61
+ // 出力先を生成.
62
+ // let myImageOutput = AVCaptureStillImageOutput()
63
+ // MARK: - 'AVCaptureStillImageOutput' was deprecated in iOS 10.0: Use AVCapturePhotoOutput instead.
64
+ // 警告通り、AVCapturePhotoOutput() でインスタンスを生成するよういする
65
+ let myImageOutput = AVCapturePhotoOutput()
66
+
67
+ // デバイス一覧の取得.
68
+ // let devices = AVCaptureDevice.devices()
69
+ // MARK: - 'devices()' was deprecated in iOS 10.0: Use AVCaptureDeviceDiscoverySession instead.
70
+ // 警告に従うが、警告で出力されているメソッド名が微妙に異なる(AVCaptureDevice.DiscoverySessionが正解)なので注意する
71
+ // 詳しい使い方は公式ドキュメントを参照
72
+ // refer to: https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/choosing_a_capture_device
73
+ let devices = AVCaptureDevice.DiscoverySession(deviceTypes:
74
+ [.builtInTrueDepthCamera, .builtInDualCamera, .builtInWideAngleCamera],
75
+ mediaType: .video, position: .unspecified).devices
76
+ // マイクを取得.
77
+ let audioCaptureDevice = AVCaptureDevice.default(for: .audio)
78
+
79
+ // マイクをセッションのInputに追加.
80
+ let audioInput = try! AVCaptureDeviceInput.init(device: audioCaptureDevice!)
81
+
82
+ // バックライトをmyDeviceに格納.
83
+
84
+ // for device in devices {
85
+ // if(device.position == AVCaptureDevice.Position.back){
86
+ // myDevice = device
87
+ // }
88
+ // }
89
+ // MARK: - オリジナルのコードから一部変更。
90
+ guard !devices.isEmpty else { fatalError("選択されたデバイスは存在しません") }
91
+ myDevice = devices.first { $0.position == .back }
92
+
93
+ // バックカメラを取得.
94
+ let videoInput = try! AVCaptureDeviceInput.init(device: myDevice!)
95
+
96
+ // ビデオをセッションのInputに追加.
97
+ mySession.addInput(videoInput)
98
+
99
+ // オーディオをセッションに追加.
100
+ mySession.addInput(audioInput)
101
+
102
+ // セッションに追加.
103
+ mySession.addOutput(myImageOutput)
104
+
105
+ // 動画の保存.
106
+ myVideoOutput = AVCaptureMovieFileOutput()
107
+
108
+ // ビデオ出力をOutputに追加.
109
+ mySession.addOutput(myVideoOutput)
110
+
111
+ // 画像を表示するレイヤーを生成.
112
+ let myVideoLayer = AVCaptureVideoPreviewLayer.init(session: mySession)
113
+ myVideoLayer.frame = self.view.bounds
114
+ // myVideoLayer.session = myDevice
115
+ myVideoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
116
+
117
+ // Viewに追加.
118
+ self.view.layer.addSublayer(myVideoLayer)
119
+
120
+ // セッション開始.
121
+ mySession.startRunning()
122
+
123
+ // UIボタンを作成.
124
+ myButtonStart = UIButton(frame: CGRect(x: 0, y: 0, width: 120, height: 50))
125
+ myButtonStop = UIButton(frame: CGRect(x: 0, y: 0, width: 120, height: 50))
126
+
127
+ myButtonStart.backgroundColor = UIColor.red
128
+ myButtonStop.backgroundColor = UIColor.gray
129
+
130
+ myButtonStart.layer.masksToBounds = true
131
+ myButtonStop.layer.masksToBounds = true
132
+
133
+ myButtonStart.setTitle("撮影", for: .normal)
134
+ myButtonStop.setTitle("停止", for: .normal)
135
+
136
+ myButtonStart.layer.cornerRadius = 20.0
137
+ myButtonStop.layer.cornerRadius = 20.0
138
+
139
+ myButtonStart.layer.position = CGPoint(x: self.view.bounds.width/2 - 70, y:self.view.bounds.height-50)
140
+ myButtonStop.layer.position = CGPoint(x: self.view.bounds.width/2 + 70, y:self.view.bounds.height-50)
141
+
142
+ myButtonStart.addTarget(self, action: #selector(ViewController.onClickMyButton), for: .touchUpInside)
143
+ myButtonStop.addTarget(self, action: #selector(ViewController.onClickMyButton), for: .touchUpInside)
144
+
145
+ // UIボタンをViewに追加.
146
+ self.view.addSubview(myButtonStart)
147
+ self.view.addSubview(myButtonStop)
148
+
149
+ //
150
+ myButtonStop.isHidden = true
151
+ }
152
+
153
+ // MARK:
154
+ func toggleButtonStatus() {
155
+ //
156
+ myButtonStop.isHidden.toggle()
157
+ myButtonStart.isHidden.toggle()
158
+ }
159
+
160
+ /*
161
+ ボタンイベント.
162
+ */
163
+ @objc internal func onClickMyButton(sender: UIButton){
164
+ // 撮影開始.
165
+ if( sender == myButtonStart ){
166
+ // MARK:
167
+ toggleButtonStatus()
168
+
169
+ let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
170
+
171
+ // フォルダ.
172
+ let documentsDirectory = paths[0]
173
+
174
+ // ファイル名.
175
+ let filePath = "(documentsDirectory)/test.mp4"
176
+
177
+ // URL.
178
+ let fileURL = URL(fileURLWithPath: filePath)
179
+
180
+ // 録画開始.
181
+ myVideoOutput.startRecording(to: fileURL, recordingDelegate: self)
182
+
183
+ }
184
+ // 撮影停止.
185
+ else if ( sender == myButtonStop ){
186
+ //
187
+ toggleButtonStatus()
188
+
189
+ myVideoOutput.stopRecording()
190
+ }
191
+ }
192
+
193
+ // MARK: - AVCaptureFileOutputRecordingDelegate
194
+
195
+ /*
196
+ 動画がキャプチャーされた後に呼ばれるメソッド.
197
+ */
198
+ func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
199
+ print("didFinishRecordingTo outputFileURL")
200
+
201
+ // MARK: - フォトライブラリにビデオを保存するのであれば、以下のコードを追加した上、NSPhotoLibraryAddUsageDescription を Info.plist に追加する必要がある。
202
+ PHPhotoLibrary.shared().performChanges({
203
+ PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputFileURL)
204
+ }) { completed, error in
205
+ if completed {
206
+ print("Video is saved!")
207
+ }
208
+ }
209
+ }
210
+
211
+ /*
212
+ 動画のキャプチャーが開始された時に呼ばれるメソッド.
213
+ */
214
+ func fileOutput(_ output: AVCaptureFileOutput, didStartRecordingTo fileURL: URL, from connections: [AVCaptureConnection]) {
215
+ print("didStartRecordingTo fileURL")
216
+ }
217
+ }
218
+ ```