WWDC Quick Look 💓 By SwiftGGTeam
Capture high-quality photos using video formats

Capture high-quality photos using video formats

观看原视频

Highlight

iOS 15 让常用视频格式在保持录制和预览响应的同时拍出更高质量照片,开发者可以用 AVCapturePhotoOutput.QualityPrioritizationAVCaptureDevice.Format.isHighPhotoQualitySupported 控制画质与速度的取舍。

核心内容

很多相机 App 都会在同一个画面里做两件事:持续显示视频预览,用户按下按钮时保存一张照片。

这类 App 往往会选择视频格式。视频格式适合录制、直播、实时滤镜和 AR 场景。它的开销低,帧率可以到 60 fps,开发者可以拿到更适合视频处理的分辨率。

问题出在拍照那一刻。过去,视频格式为了保证预览流畅,会使用较轻的照片处理。照片能很快交付,但弱光、噪声和动态范围的表现不如照片格式。

专业拍照 App 可以切到照片格式,拿到最高分辨率,还能使用 Live Photo、ProRAW 等照片能力。社交、直播、AR App 很难这么做。它们要继续处理视频帧,不能让预览掉帧。

Apple 在 iOS 15 改进了常用视频格式的照片处理算法。开发者继续使用视频格式,也能在 .balanced 下得到明显更好的照片,同时不打断视频录制和预览。需要最高质量时,可以选择 .quality,代价是部分设备上可能出现掉帧或预览中断。

这场演讲的关键是两个开关。一个是质量优先级,告诉 AVCapturePhotoOutput 这次拍摄更看重速度还是画质。另一个是格式能力查询,告诉开发者哪些视频格式支持新的高质量照片能力。

详细内容

搭建照片捕获管线

01:19)AVCapture(音视频采集)拍照的基本结构没有变化。应用创建 AVCaptureSession,把相机作为 AVCaptureDevice,再用 AVCaptureDeviceInput 把相机接入 session,最后添加 AVCapturePhotoOutput 接收照片。

import AVFoundation

final class PhotoCaptureController: NSObject, AVCapturePhotoCaptureDelegate {
    private let session = AVCaptureSession()
    private let photoOutput = AVCapturePhotoOutput()

    func configure() throws {
        session.beginConfiguration()
        session.sessionPreset = .photo

        guard let device = AVCaptureDevice.default(.builtInWideAngleCamera,
                                                   for: .video,
                                                   position: .back) else {
            session.commitConfiguration()
            return
        }

        let input = try AVCaptureDeviceInput(device: device)

        if session.canAddInput(input) {
            session.addInput(input)
        }

        if session.canAddOutput(photoOutput) {
            session.addOutput(photoOutput)
        }

        session.commitConfiguration()
    }

    func capture() {
        let settings = AVCapturePhotoSettings()
        photoOutput.capturePhoto(with: settings, delegate: self)
    }
}

关键点:

  • AVCaptureSession 是采集图的中心,输入和输出都接到它上面。
  • session.sessionPreset = .photo 表示这个配置优先服务于照片捕获。
  • AVCaptureDevice.default(..., for: .video, ...) 取到后置广角相机。
  • AVCaptureDeviceInput 把相机数据送入 session。
  • AVCapturePhotoOutput 是照片输出端。
  • AVCapturePhotoSettings() 保存单次拍照的设置。
  • capturePhoto(with:delegate:) 发起拍摄,结果会通过 AVCapturePhotoCaptureDelegate 回调交付。

用质量优先级表达取舍

03:07)过去,开发者常把 isAutoStillImageStabilizationEnabled 设为 true 来追求更高照片质量。这个名字只描述静态图像防抖。现在的照片质量还来自多图像融合技术,例如 Smart HDR 和 Deep Fusion。iOS 13 引入了 AVCapturePhotoOutput.QualityPrioritization,用三个级别表达取舍:.speed.balanced.quality

import AVFoundation

final class PrioritizedPhotoCapture: NSObject, AVCapturePhotoCaptureDelegate {
    private let photoOutput = AVCapturePhotoOutput()

    func configurePhotoOutput() {
        photoOutput.maxPhotoQualityPrioritization = .quality
    }

    func captureForFastSharing() {
        let settings = AVCapturePhotoSettings()
        settings.photoQualityPrioritization = .balanced
        photoOutput.capturePhoto(with: settings, delegate: self)
    }

    func captureForBurstLikeSpeed() {
        let settings = AVCapturePhotoSettings()
        settings.photoQualityPrioritization = .speed
        photoOutput.capturePhoto(with: settings, delegate: self)
    }
}

关键点:

  • maxPhotoQualityPrioritization 设置这个 AVCapturePhotoOutput 允许的最高质量级别。
  • 这个值在配置输出时设置一次即可。
  • settings.photoQualityPrioritization = .balanced 表示单次拍摄在速度和画质之间取平衡。
  • settings.photoQualityPrioritization = .speed 表示这次拍摄优先快速交付。
  • 单次拍摄的优先级不能高于 photoOutput.maxPhotoQualityPrioritization,否则会抛出异常。
  • 如果不设置,默认值是 .balanced

根据处理时间决定 UI 反馈

04:29)质量优先级只是提示。AVCapturePhotoOutput 会结合设备、场景和光照选择算法。开发者不能直接指定底层算法,但可以读取 AVCaptureResolvedPhotoSettings.photoProcessingTimeRange,判断照片交付大概要多久。

import AVFoundation

func shouldShowProcessingIndicator(
    for resolvedSettings: AVCaptureResolvedPhotoSettings
) -> Bool {
    let processingRange = resolvedSettings.photoProcessingTimeRange
    return processingRange.end.seconds > 0.5
}

关键点:

  • AVCaptureResolvedPhotoSettings 是系统解析后的拍照设置。
  • photoProcessingTimeRange 表示照片处理时间范围。
  • processingRange.end.seconds 取最慢可能时间。
  • 超过阈值时,应用可以显示等待指示器。
  • 这个判断适合 .quality 拍摄,因为高质量处理可能需要更久。

分清照片格式和视频格式

06:56)照片格式表示应用把静态照片放在第一位。它有最高照片分辨率,支持 Live Photo、ProRAW 等照片能力,帧率限制为 30 fps。视频格式表示应用围绕视频体验设计,适合录制、直播、实时处理和 60 fps。

import AVFoundation

func configureSessionForPhotoFirst(_ session: AVCaptureSession) {
    session.beginConfiguration()
    session.sessionPreset = .photo
    session.commitConfiguration()
}

func selectPhotoFormat(from device: AVCaptureDevice) -> AVCaptureDevice.Format? {
    return device.formats.first { format in
        format.isHighestPhotoQualitySupported
    }
}

func selectVideoFormat(from device: AVCaptureDevice) -> AVCaptureDevice.Format? {
    return device.formats.first { format in
        !format.isHighestPhotoQualitySupported
    }
}

关键点:

  • .photo preset 会选择照片优先的 session 配置。
  • isHighestPhotoQualitySupported == true 表示该格式是照片格式。
  • isHighestPhotoQualitySupported == false 的格式属于视频格式。
  • 照片格式适合追求最高照片质量的 App。
  • 视频格式适合需要稳定预览、录制或自定义帧处理的 App。

选择支持高质量照片的视频格式

11:37)iOS 15 在 AVCaptureDevice.Format 上新增 isHighPhotoQualitySupported。这个属性为 true 的格式支持视频格式下的高质量照片能力,并且一定是视频格式。

import AVFoundation

func selectHighPhotoQualityVideoFormat(
    from device: AVCaptureDevice
) -> AVCaptureDevice.Format? {
    return device.formats.first { format in
        format.isHighPhotoQualitySupported
    }
}

func applyHighPhotoQualityVideoFormat(to device: AVCaptureDevice) throws {
    guard let format = selectHighPhotoQualityVideoFormat(from: device) else {
        return
    }

    try device.lockForConfiguration()
    device.activeFormat = format
    device.unlockForConfiguration()
}

关键点:

  • isHighPhotoQualitySupported 是 iOS 15 新增的格式能力查询。
  • 这个属性表示视频格式是否支持新的高质量照片处理。
  • device.formats.first { ... } 从相机可用格式中选择一个匹配格式。
  • 修改 activeFormat 前必须调用 lockForConfiguration()
  • 设置完成后调用 unlockForConfiguration() 释放配置锁。
  • 演讲中列出的支持范围包括 1280×720 30/60 fps、1920×1080 30/60 fps、1920×1440 30 fps、4K 30 fps,设备支持回溯到 iPhone XS。

在视频格式下选择 .balanced.quality

10:19)在支持的 video formats(视频格式)下,.speed 仍然交付轻处理的 WYSIWYG(所见即所得)照片。.balanced 会带来明显画质提升,只增加少量处理时间,并且不会造成视频录制掉帧或预览中断。.quality 会运行成本更高的算法,可能在部分设备上导致掉帧或预览中断。

import AVFoundation

final class VideoFormatPhotoCapture: NSObject, AVCapturePhotoCaptureDelegate {
    private let photoOutput = AVCapturePhotoOutput()

    func configureOutputForVideoFormat() {
        photoOutput.maxPhotoQualityPrioritization = .quality
    }

    func captureSnapshotDuringRecording(needsExactVideoMatch: Bool) {
        let settings = AVCapturePhotoSettings()

        if needsExactVideoMatch {
            settings.photoQualityPrioritization = .speed
        } else {
            settings.photoQualityPrioritization = .balanced
        }

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

关键点:

  • maxPhotoQualityPrioritization = .quality 允许后续拍摄选择最高级别。
  • needsExactVideoMatch 表示照片是否必须和同时录制的视频画面完全一致。
  • .speed 适合照片需要和视频画面一致的场景。
  • .balanced 适合大多数视频格式下的拍照场景,画质提升且不打断录制和预览。
  • 想使用 .quality 获取更高画质时,需要接受部分设备上的掉帧或预览中断风险。

处理兼容性和限制

12:32)如果应用已经使用 AVCapturePhotoOutput.balanced,在 iOS 15 上会自动得到更好的视频格式照片。使用 .speed 的应用可以改为 .balanced。仍在使用已废弃的 AVCaptureStillImageOutput 的应用需要迁移。

import AVFoundation

func preferredPhotoQualityPrioritization(
    prioritizesExactVideoAppearance: Bool,
    acceptsPreviewInterruptions: Bool
) -> AVCapturePhotoOutput.QualityPrioritization {
    if prioritizesExactVideoAppearance {
        return .speed
    }

    if acceptsPreviewInterruptions {
        return .quality
    }

    return .balanced
}

关键点:

  • 照片必须和视频外观一致时,选择 .speed
  • 能接受预览中断或掉帧时,可以选择 .quality
  • 常规视频格式拍照建议从 .balanced 开始。
  • 新能力只适用于 AVCaptureSession,不适用于 AVCaptureMultiCamSession
  • AVCaptureStillImageOutput 已废弃,也不支持这个新能力。
  • .balanced.quality 可能融合不同曝光的多张图像,照片外观可能和同时录制的视频不同。

核心启发

  • 做什么:给短视频 App 加一个“高质量截图”按钮。 为什么值得做:iOS 15 的视频格式可以在 .balanced 下提升照片质量,同时不打断录制和预览。 怎么开始:继续使用视频格式,选择 isHighPhotoQualitySupportedtrueAVCaptureDevice.Format,拍摄时设置 settings.photoQualityPrioritization = .balanced

  • 做什么:给直播 App 加一个主播封面快照功能。 为什么值得做:直播链路需要低延迟和稳定预览,视频格式比照片格式更适合实时处理。 怎么开始:用 AVCapturePhotoOutput 在直播 session 中捕获照片,默认使用 .balanced,在弱网或设备压力大时切到 .speed

  • 做什么:给 AR App 加一个保存当前 3D 场景照片的入口。 为什么值得做:AR 场景依赖稳定相机 feed。演讲指出,重算法可能影响核心体验,.balanced 能在画质和流畅度之间取得可控结果。 怎么开始:在现有 AVCaptureSession 中添加 AVCapturePhotoOutput,拍照前读取 photoProcessingTimeRange,需要等待时显示轻量提示。

  • 做什么:给相机 App 做一个“速度 / 平衡 / 质量”拍摄偏好。 为什么值得做AVCapturePhotoOutput.QualityPrioritization 本身就是面向质量和速度取舍的 API。 怎么开始:把用户选择映射到 .speed.balanced.quality,并确保 maxPhotoQualityPrioritization 不低于单次拍摄设置。

  • 做什么:给审核或巡检 App 加一个快速连拍模式和精细留档模式。 为什么值得做:同一个业务里既有快速记录,也有需要更高画质的证据照片。 怎么开始:快速连拍用 .speed,单张留档用 .balanced.quality,用 photoProcessingTimeRange 决定是否显示处理状态。

关联 Session

评论

GitHub Issues · utterances