// // PlayContoller9.swift // tdvideo // // Created by mac on 2024/2/21. // /* 拍摄空间视频 */ import UIKit import AVFoundation import Photos import AVKit import VideoToolbox class PlayContoller9: UIViewController, AVCaptureFileOutputRecordingDelegate { //AVCaptureSession --- 单摄像头 var session = AVCaptureMultiCamSession()//多摄像头 var wideAngleCameraDeviceInput: AVCaptureDeviceInput?//广角摄像头 .builtInWideAngleCamera var ultraWideCameraDeviceInput: AVCaptureDeviceInput?//超广角 .builtInUltraWideCamera var wideAngleCameraVideoPreviewLayer: AVCaptureVideoPreviewLayer?//广角摄像头 var ultraWideCameraVideoPreviewLayer: AVCaptureVideoPreviewLayer?//超广角 var wideAngleCameraMovieOutput: AVCaptureMovieFileOutput? var ultraWideCameraMovieOutput: AVCaptureMovieFileOutput? var isRecording = false var startRecordingButton: UIButton? var leftEyeVideoURL:URL? var rightEyeVideoURL:URL? var outputVideoURL: URL? override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white outputVideoURL = URL.documentsDirectory.appendingPathComponent("output.MOV") configureSession() setupUI() } private func configureSession() { session.beginConfiguration() defer { session.commitConfiguration() } // 配置后置摄像头 .builtInWideAngleCamera 广角摄像头(默认设备 --- 主摄,28mm左右焦段) .back 后置摄像头 guard let backCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else { print("Could not find the back camera") return } do { wideAngleCameraDeviceInput = try AVCaptureDeviceInput(device: backCamera) guard let wideAngleCameraDeviceInput = wideAngleCameraDeviceInput, session.canAddInput(wideAngleCameraDeviceInput) else { print("Could not add back camera input") return } session.addInput(wideAngleCameraDeviceInput) } catch { print("Could not create back camera device input: \(error)") return } // .builtInUltraWideCamera 超广角(默认设备的0.5x,只能使用AVCaptureDeviceDiscoverySession获取) .back 后置摄像头 guard let frontCamera = AVCaptureDevice.default(.builtInUltraWideCamera, for: .video, position: .back) else { print("Could not find the front camera") return } do { ultraWideCameraDeviceInput = try AVCaptureDeviceInput(device: frontCamera) guard let ultraWideCameraDeviceInput = ultraWideCameraDeviceInput, session.canAddInput(ultraWideCameraDeviceInput) else { print("Could not add front camera input") return } session.addInput(ultraWideCameraDeviceInput) } catch { print("Could not create front camera device input: \(error)") return } // 配置音频输入设备 guard let audioDevice = AVCaptureDevice.default(for: .audio) else { print("Could not find audio device") return } do { let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice) guard session.canAddInput(audioDeviceInput) else { print("Could not add audio input") return } session.addInput(audioDeviceInput) } catch { print("Could not create audio device input: \(error)") return } // 配置后置摄像头输出 wideAngleCameraMovieOutput = AVCaptureMovieFileOutput() guard let wideAngleCameraMovieOutput = wideAngleCameraMovieOutput, session.canAddOutput(wideAngleCameraMovieOutput) else { print("Could not add the back camera movie output") return } session.addOutput(wideAngleCameraMovieOutput) // 配置前置摄像头输出 ultraWideCameraMovieOutput = AVCaptureMovieFileOutput() guard let ultraWideCameraMovieOutput = ultraWideCameraMovieOutput, session.canAddOutput(ultraWideCameraMovieOutput) else { print("Could not add the front camera movie output") return } session.addOutput(ultraWideCameraMovieOutput) // 配置预览图层 wideAngleCameraVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: session) wideAngleCameraVideoPreviewLayer?.frame = CGRect(x: 0, y: 0, width: view.frame.size.width / 2, height: view.frame.size.height / 2) if let wideAngleCameraVideoPreviewLayer = wideAngleCameraVideoPreviewLayer { view.layer.addSublayer(wideAngleCameraVideoPreviewLayer) } ultraWideCameraVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: session) ultraWideCameraVideoPreviewLayer?.frame = CGRect(x: view.frame.size.width / 2, y: 0, width: view.frame.size.width / 2, height: view.frame.size.height / 2) if let ultraWideCameraVideoPreviewLayer = ultraWideCameraVideoPreviewLayer { view.layer.addSublayer(ultraWideCameraVideoPreviewLayer) } DispatchQueue.global().async { self.session.startRunning() } } private func setupUI() { startRecordingButton = UIButton(type: .system) startRecordingButton?.setTitle("Start Recording", for: .normal) startRecordingButton?.setTitleColor(UIColor.brown, for: UIControl.State.normal) startRecordingButton?.addTarget(self, action: #selector(toggleRecording(_:)), for: .touchUpInside) startRecordingButton?.frame = CGRect(x: 0, y: view.frame.size.height - 250, width: view.frame.size.width, height: 50) view.addSubview(startRecordingButton!) } @objc private func toggleRecording(_ sender: UIButton) { if isRecording { stopRecording() } else { startRecording() } } private func startRecording() { guard let wideAngleCameraMovieOutput = wideAngleCameraMovieOutput, let ultraWideCameraMovieOutput = ultraWideCameraMovieOutput else { print("Movie output not configured") return } let time = Date().timeIntervalSince1970 let name1 = "back" + String(time) + ".mov" let name2 = "front" + String(time) + ".mov" let backCameraOutputURL = URL.documentsDirectory.appending(path:name1) let frontCameraOutputURL = URL.documentsDirectory.appending(path:name2) wideAngleCameraMovieOutput.startRecording(to: backCameraOutputURL, recordingDelegate: self) ultraWideCameraMovieOutput.startRecording(to: frontCameraOutputURL, recordingDelegate: self) isRecording = true startRecordingButton?.setTitle("Stop Recording", for: .normal) } private func stopRecording() { guard let wideAngleCameraMovieOutput = wideAngleCameraMovieOutput, let ultraWideCameraMovieOutput = ultraWideCameraMovieOutput else { print("Movie output not configured") return } wideAngleCameraMovieOutput.stopRecording() ultraWideCameraMovieOutput.stopRecording() isRecording = false startRecordingButton?.setTitle("Start Recording", for: .normal) } func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) { if let error = error { print("Video recording finished with error: \(error.localizedDescription)") } else { if output == wideAngleCameraMovieOutput { print("Back camera video recorded: \(outputFileURL)") leftEyeVideoURL = outputFileURL } else if output == ultraWideCameraMovieOutput { print("Front camera video recorded: \(outputFileURL)") rightEyeVideoURL = outputFileURL } createSpVideo() } } func createSpVideo(){ if(rightEyeVideoURL != nil && leftEyeVideoURL != nil){ let spatialVideoWriter = SpatialVideoWriter() Task { spatialVideoWriter.writeSpatialVideo(leftEyeVideoURL: leftEyeVideoURL!, rightEyeVideoURL: rightEyeVideoURL!, outputVideoURL: outputVideoURL!) { success, error in if success { print("空间视频生成成功") } else if let error = error { print("生成空间视频失败:\(error.localizedDescription)") } } } } } }