FrontPage
- iOS13より複数のカメラで同時撮影するAPIが追加された
- ズームレンズよりもメインレンズのほうが低照度環境でもノイズが乗りにくいが,ズームで取りたい場合もある→両方撮影して良い方を選べば良いのでは
- 結論: iPhone15ProMaxにおいて複数カメラのビデオ撮影では4Kをサポートしていない.1080pが最大である
コード†
import AVFoundation
import UIKit
import Photos
class ViewController: UIViewController {
@IBOutlet weak var previewView: UIView!
private var captureSession = AVCaptureMultiCamSession()
private var audioInput: AVCaptureDeviceInput!
private var audioPort: AVCaptureDeviceInput.Port!
// 広角カメラの設定
private var wideAngleInput: AVCaptureDeviceInput!
private var wideAnglePort: AVCaptureDeviceInput.Port!
private var wideAngleOutput: AVCaptureMovieFileOutput!
private var wideAngleVideoConnection: AVCaptureConnection!
// 望遠カメラの設定
private var telephotoInput: AVCaptureDeviceInput!
private var telephotoPort: AVCaptureDeviceInput.Port!
private var telephotoOutput: AVCaptureMovieFileOutput!
private var telephotoVideoConnection: AVCaptureConnection!
// プレビュー
private var videoPreviewLayer: AVCaptureVideoPreviewLayer!
override func viewDidLoad() {
super.viewDidLoad()
// マルチキャプチャをサポートしているかどうか
guard AVCaptureMultiCamSession.isMultiCamSupported else {
fatalError()
}
setupSession()
}
// MARK: - セッションの設定
private func setupSession() {
captureSession.beginConfiguration()
// マイクの準備
do {
let microphone = AVCaptureDevice.default(for: .audio)!
let input = try AVCaptureDeviceInput(device: microphone)
guard captureSession.canAddInput(input) else {
fatalError()
}
audioInput = input
captureSession.addInputWithNoConnections(input)
guard let audioPort = input.ports(for: .audio,
sourceDeviceType: microphone.deviceType,
sourceDevicePosition: .back).first else {
fatalError()
}
self.audioPort = audioPort
}
catch {
fatalError(error.localizedDescription)
}
// カメラの利用準備
do {
try setupWideCamera()
try setupTeleCamera()
previewView.layer.addSublayer(videoPreviewLayer)
videoPreviewLayer.frame = previewView.layer.frame
captureSession.commitConfiguration()
captureSession.startRunning()
if captureSession.canSetSessionPreset(.hd4K3840x2160) {
print("4k利用可能")
}
else {
print("4k利用不可能")
}
}
catch {
print("error")
}
}
// MARK: - 広角カメラの設定
private func setupWideCamera() throws {
guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera,
for: .video,
position: .back) else {
print("camera not founc")
throw NSError()
}
// sessinに追加
wideAngleInput = try AVCaptureDeviceInput(device: camera)
guard captureSession.canAddInput(wideAngleInput) else {
print("can not add camera input")
throw NSError()
}
captureSession.addInputWithNoConnections(wideAngleInput)
guard let wideAnglePort = wideAngleInput.ports(
for: .video, sourceDeviceType: camera.deviceType,
sourceDevicePosition: camera.position).first else {
print("can not find wide angle port")
throw NSError()
}
self.wideAnglePort = wideAnglePort
// outputをsessionに追加する
wideAngleOutput = AVCaptureMovieFileOutput()
guard captureSession.canAddOutput(wideAngleOutput) else {
print("can not add wide angle output")
throw NSError()
}
captureSession.addOutputWithNoConnections(wideAngleOutput)
// inputとoutputを接続する
wideAngleVideoConnection = AVCaptureConnection(
inputPorts: [wideAnglePort], output: wideAngleOutput)
wideAngleVideoConnection.videoOrientation = .portrait
if (wideAngleVideoConnection.isVideoStabilizationSupported) {
wideAngleVideoConnection.preferredVideoStabilizationMode = .cinematicExtended
}
guard captureSession.canAddConnection(wideAngleVideoConnection) else {
print("can not add wide angle video connetion")
throw NSError()
}
captureSession.addConnection(wideAngleVideoConnection)
// マイクとoutputを接続する
let audioConnection = AVCaptureConnection(
inputPorts: [audioPort], output: wideAngleOutput)
guard captureSession.canAddConnection(audioConnection) else {
print("can not add audio connection")
throw NSError()
}
}
// MARK: - 望遠カメラの設定
private func setupTeleCamera() throws {
guard let camera = AVCaptureDevice.default(
.builtInTelephotoCamera, for: .video, position: .back) else {
print("not found builtin telephoto camera")
throw NSError()
}
telephotoInput = try AVCaptureDeviceInput(device: camera)
guard captureSession.canAddInput(telephotoInput) else {
print("can not add telephoto camera")
throw NSError()
}
captureSession.addInputWithNoConnections(telephotoInput)
guard let telephotoPort = telephotoInput.ports(
for: .video,
sourceDeviceType: camera.deviceType,
sourceDevicePosition: camera.position).first else {
print("can not fine telephoto input port")
throw NSError()
}
self.telephotoPort = telephotoPort
// outputの設定
telephotoOutput = AVCaptureMovieFileOutput()
guard captureSession.canAddOutput(telephotoOutput) else {
print("can not add telephoto output")
throw NSError()
}
captureSession.addOutputWithNoConnections(telephotoOutput)
// inputとoutputを接続する
telephotoVideoConnection = AVCaptureConnection(
inputPorts: [telephotoPort], output: telephotoOutput)
telephotoVideoConnection.videoOrientation = .portrait
if telephotoVideoConnection.isVideoStabilizationSupported {
telephotoVideoConnection.preferredVideoStabilizationMode = .cinematicExtended
}
guard captureSession.canAddConnection(telephotoVideoConnection) else {
print("can not add telephoto video connection")
throw NSError()
}
captureSession.addConnection(telephotoVideoConnection)
// マイクとinputとoutputを接続する
let audioConnection = AVCaptureConnection(
inputPorts: [audioPort], output: telephotoOutput)
guard captureSession.canAddConnection(audioConnection) else {
print("can not add audio connection. telephoto")
throw NSError()
}
captureSession.addConnection(audioConnection)
// プレビューの設定
videoPreviewLayer = AVCaptureVideoPreviewLayer()
videoPreviewLayer.setSessionWithNoConnection(captureSession)
videoPreviewLayer.videoGravity = .resizeAspect
videoPreviewLayer.bounds = previewView.bounds
let layerConnection = AVCaptureConnection(
inputPort: telephotoPort, videoPreviewLayer: videoPreviewLayer)
layerConnection.videoOrientation = .portrait
guard captureSession.canAddConnection(layerConnection) else {
print("can not add layer connection")
throw NSError()
}
captureSession.addConnection(layerConnection)
}
}