You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 12中AVCaptureMovieFileOutput录制时拍照的实现问题

在iOS 12.1.2的iPhone 6s Plus上实现录屏同时拍照的问题

我在iPhone 6s Plus(iOS 12.1.2)设备上尝试用AVCaptureMovieFileOutput录制视频的同时拍照,但所有尝试的方法要么导致录制停止,要么无法获取画面帧。我知道可以使用AVAssetWriter+AVCaptureVideoDataOutput方案,但该方案极不稳定,希望尽可能避免。

以下是我尝试过的方法:

  • 两个独立Session搭配AVCaptureMovieFileOutput+AVCapturePhotoOutput:录制停止
  • 两个独立Session搭配AVCaptureMovieFileOutput+AVCaptureStillImageOutput:录制停止
  • 同一Session搭配AVCaptureMovieFileOutput+AVCaptureVideoDataOutput:数据输出代理回调未触发(该方法在iOS17的iPhone13上可正常工作)
  • 两个独立Session搭配AVCaptureMovieFileOutput+AVCaptureVideoDataOutput:录制停止

以下是测试应用的代码:

class ViewController: UIViewController {
    var device1:AVCaptureDevice!
    var device2:AVCaptureDevice!
    let session1:AVCaptureSession = AVCaptureSession()
    let session2:AVCaptureSession = AVCaptureSession()
    let fileOutput:AVCaptureMovieFileOutput = AVCaptureMovieFileOutput()
    let dataOutput:AVCaptureVideoDataOutput = AVCaptureVideoDataOutput()
//    let stillImageOutput:AVCaptureStillImageOutput = AVCaptureStillImageOutput()
//    let photoOutput:AVCapturePhotoOutput = AVCapturePhotoOutput()
    
    @IBOutlet weak var debugImageView:UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        checkPermissions()
        session1.startRunning()
        session2.startRunning()
        sleep(1)
        print("start recording")
        let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        fileOutput.startRecording(to: documentsURL.appendingPathComponent("test.mp4"), recordingDelegate: self)
//        sleep(1)
//        print("take photo")
//        photoOutput.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
    }
    
    func setupCamera(){
        device1 = AVCaptureDevice.default(for: .video)
        device2 = AVCaptureDevice.default(for: .video)
        
        do {
            session1.beginConfiguration()
            let input1 = try AVCaptureDeviceInput(device: device1)
            session1.addInput(input1)
            session1.addOutput(fileOutput)
            session1.commitConfiguration()
            
            session2.beginConfiguration()
            let input2 = try AVCaptureDeviceInput(device: device1)
            session2.addInput(input2)
            dataOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))
            session2.addOutput(dataOutput)
            
//            session2.addOutput(photoOutput)
//            session2.addOutput(stillImageOutput)
            session2.commitConfiguration()
        } catch {
            print(error)
        }
    }
    
    func checkPermissions(){
        switch AVCaptureDevice.authorizationStatus(for: .video) {
        case .authorized:
            self.setupCamera()
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
                guard granted else { return }
                self?.setupCamera()
            }
        case .denied:
            return
        case .restricted:
            return
        @unknown default:
            return
        }
    }
    var once = true
}

extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate{
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        if once {
            once = false
        } else {
            return
        }
        let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
        let ciImage = CIImage(cvPixelBuffer: imageBuffer!)
        let context = CIContext()
        let myUIImage = UIImage(cgImage: context.createCGImage(ciImage, from: ciImage.extent)!)
        DispatchQueue.main.async {
            self.debugImageView.image = myUIImage
        }
    }
}

extension ViewController: AVCapturePhotoCaptureDelegate{
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        debugImageView.image = UIImage(data: photo.fileDataRepresentation()!)
    }
}

extension ViewController: AVCaptureFileOutputRecordingDelegate{
    func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
        print("finish recording")
    }
}

内容的提问来源于stack exchange,提问作者TheJavaNoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 17:33:20