Capture high-quality photos using video formats
Photos & Camera 进阶 20m

用视频格式拍摄高质量照片

Capture high-quality photos using video formats

2021年6月10日

在 Apple 官方观看视频

一句话判断

AVFoundation 的新 API 让你可以从视频流中提取高质量静态帧——这意味着拍照不再需要切换到照片模式,“边录像边拍照”的体验可以做到零延迟。

这场 Session 讲了什么

Session 介绍了 iOS 15 中 AVFoundation 的新能力:从视频流中提取高质量静态图片。传统的拍照流程需要切换到照片捕获模式,完成对焦和曝光后拍摄一张照片。新 API 允许你在视频录制过程中随时提取一帧作为高质量照片,不需要停止录制或切换模式。

关键技术是 AVCapturePhotoOutputisFastCaptureEnabled 和从 AVCaptureVideoDataOutput 的样本缓冲区(Sample Buffer)中提取照片质量图像。后者结合了视频流的实时性和照片的分辨率和动态范围。

还介绍了 Apple 的计算摄影(Computational Photography)技术如何在提取帧时发挥作用——Smart HDR、Deep Fusion 和夜间模式都可以应用到从视频帧提取的照片上。

值得深挖的点

视频帧到照片质量的差距

普通视频帧的分辨率是 1920x1080(Full HD)或 3840x2160(4K),而照片模式可以输出 12MP(4032x3024)或更高。但通过多帧合成技术,从视频流中提取的照片质量可以接近专用照片模式——系统会在你按下快门的前后各取几帧,用多帧降噪和超分辨率算法合成一张高质量照片。这意味着”在 4K 视频中截图”和”在照片模式中拍照”的质量差距在缩小。

零快门延迟的实现

传统照片捕获从按下快门到实际拍摄有约 200-300ms 延迟。从视频流提取帧则不同——视频一直在录,你按下快门的那一刻对应的帧就是你要的帧,延迟接近零。对于抓拍场景(体育、儿童、宠物),这个差异意味着能不能拍到决定性瞬间。

代码片段

从视频流中提取高质量照片帧

import AVFoundation

class VideoPhotoCapture: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
    let session = AVCaptureSession()
    let videoOutput = AVCaptureVideoDataOutput()
    
    func setup() {
        session.sessionPreset = .photo  // 使用照片质量预设
        
        let videoDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)!
        let videoInput = try! AVCaptureDeviceInput(device: videoDevice)
        session.addInput(videoInput)
        
        videoOutput.setSampleBufferDelegate(self, queue: captureQueue)
        session.addOutput(videoOutput)
        session.startRunning()
    }
    
    // 视频帧回调
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        // 保存最近几帧用于后续提取
        recentBuffers.append(sampleBuffer)
        if recentBuffers.count > 10 {
            recentBuffers.removeFirst()
        }
    }
    
    // 从缓冲区提取高质量照片
    func capturePhoto() {
        guard let buffer = recentBuffers.last else { return }
        
        // 将视频帧转换为照片质量图像
        let pixelBuffer = CMSampleBufferGetImageBuffer(buffer)!
        let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
        let context = CIContext()
        let cgImage = context.createCGImage(ciImage, from: ciImage.extent)!
        let image = UIImage(cgImage: cgImage)
        
        // 保存照片
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
    }
}

使用 AVCapturePhotoOutput 的快速捕获

// 配置快速照片捕获
let photoOutput = AVCapturePhotoOutput()
photoOutput.isFastCaptureEnabled = true
photoOutput.isHighResolutionCaptureEnabled = true

// 拍照
let settings = AVCapturePhotoSettings()
settings.isHighResolutionPhotoEnabled = true
settings.photoQualityPrioritization = .balanced  // 速度和质量的折中

photoOutput.capturePhoto(with: settings, delegate: self)

// 在 delegate 中获取照片
func photoOutput(_ output: AVCapturePhotoOutput, 
                 didFinishProcessingPhoto photo: AVCapturePhoto, 
                 error: Error?) {
    guard let data = photo.fileDataRepresentation() else { return }
    let image = UIImage(data: data)
    // 这张照片经过 Smart HDR 和 Deep Fusion 处理
}

同时录制视频和拍照

// 同时添加视频和照片输出
let session = AVCaptureSession()
session.addOutput(videoDataOutput)
session.addOutput(photoOutput)

// 录制视频的同时可以随时拍照
// 不需要停止录制
func startRecording() {
    movieFileOutput.startRecording(to: outputURL, recordingDelegate: self)
}

// 在录制过程中随时调用
func takePhotoWhileRecording() {
    let settings = AVCapturePhotoSettings()
    photoOutput.capturePhoto(with: settings, delegate: self)
    // 视频继续录制,不受影响
}

最佳实践

拍照 App: 如果你做的是拍照 App,考虑用视频流提取帧的方式替代传统拍照流程。零快门延迟 + 计算摄影的组合让用户体验大幅提升。注意处理高分辨率帧的内存压力——不要在内存中保存太多帧缓冲区。

视频 App: 在视频录制界面提供”拍照”按钮,让用户在录视频时随时截图。提取的帧质量比传统截图好得多(经过了降噪和 HDR 处理)。

还有什么值得关注

  • ProRes 视频格式在 iPhone 13 Pro 上支持,可以用于专业视频拍摄。
  • Cinematic 视频模式支持拍摄后的焦点调整。
  • 从视频帧提取的照片会保留 EXIF 元数据,包括时间戳和相机参数。
WWDC 2021