Foundation — AVFoundation

AVFoundation 是 Apple 提供的一个功能丰富的 多媒体框架,用于处理音频、视频、音频视频的捕获与播放,还可以编辑和处理多媒体内容。它是苹果生态系统中开发多媒体相关应用(如媒体播放器、音频视频录制、编辑工具)的关键核心框架。不论是初学者还是高级用户,AVFoundation 都是实现复杂多媒体功能的强大工具。


1. AVFoundation 的体系结构 #

AVFoundation 的体系结构包含多个模块,根据功能被划分为以下几个主要部分:

1.1 播放音频与视频 (Playback) #

类/协议描述
AVPlayer用于播放音频或视频的核心类,支持网络流媒体和本地文件。
AVPlayerItemAVPlayer 的媒体资源描述对象,包含当前播放媒体的属性和状态。
AVPlayerLayer用于显示视频内容的图层,通常嵌入 CALayer 层级实现视频画面渲染。

1.2 媒体捕获与录制 (Capture) #

类/协议描述
AVCaptureSession负责管理输入设备(如摄像头、麦克风)和输出目标(如文件、图像预览)的会话。
AVCaptureDevice代表具体的硬件输入设备,如摄像头、麦克风等。
AVCaptureDeviceInput表示输入源(摄像头或麦克风)的配置。
AVCaptureOutput输出捕获的音视频数据,例如存储为文件或提供实时音视频数据流。
AVCapturePhotoOutput专门处理拍照输出(静态图像)的类。
AVCaptureVideoDataOutput视频数据流输出,可以处理实时捕获的视频帧。
AVCaptureAudioDataOutput音频数据流输出,可捕获实时音频流。

1.3 媒体编辑与导出 (Editing) #

类/协议描述
AVAsset媒体文件的抽象表示,包括音频、视频、字幕等。
AVAssetExportSessionAVAsset 导出为指定的格式和分辨率视频或音频文件。
AVMutableComposition用于创建或编辑音频和视频的可变复合媒体。
AVMutableVideoComposition修改或创建视频特效(如滤镜)和过渡效果。
AVMutableAudioMix用于实现音频的淡入/淡出或多轨音频混音。

1.4 媒体资源管理 (Reading & Metadata) #

类/协议描述
AVURLAsset管理基于 URL 的媒体资源(如本地文件或网络流媒体文件)。
AVMetadataItem包含媒体文件元数据信息(如视频标题、描述、艺术家信息等)。
AVMediaSelection用于管理音轨选择、多语言字幕和视频轨道。

1.5 低层次音频管理 (Audio) #

类/协议描述
AVAudioPlayer简单播放音频文件的类,用于播放本地音频(如 .mp3.wav)。
AVAudioRecorder音频录制类,可通过麦克风录制音频并存储为音频文件(如 .m4a)。
AVAudioSession配置并管理应用的音频行为(如录音和播放的模式)。
AVAudioEngine提供低级音频操作支持,适用于需要音频实时处理的场景(如音效增强或者多轨混音)。

2. 如何使用 AVFoundation? #

2.1 视频和音频播放(AVPlayer) #

示例:播放本地视频或音频文件 #

import AVFoundation
import UIKit

class PlayerViewController: UIViewController {
    var player: AVPlayer?
    var playerLayer: AVPlayerLayer?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let filePath = Bundle.main.path(forResource: "sample", ofType: "mp4") {
            let fileURL = URL(fileURLWithPath: filePath)
            // 初始化播放器
            player = AVPlayer(url: fileURL)
            
            // 创建视频显示的 Layer
            playerLayer = AVPlayerLayer(player: player)
            playerLayer?.videoGravity = .resizeAspect
            playerLayer?.frame = self.view.bounds
            
            // 添加播放器 Layer 到视图
            if let playerLayer = playerLayer {
                self.view.layer.addSublayer(playerLayer)
            }
        }
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        player?.play() // 开始播放
    }
}

2.2 媒体捕获与录制(AVCaptureSession) #

示例:拍摄照片 #

import UIKit
import AVFoundation

class CapturePhotoViewController: UIViewController, AVCapturePhotoCaptureDelegate {
    var captureSession: AVCaptureSession?
    var photoOutput: AVCapturePhotoOutput?

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 1. 创建捕获会话
        captureSession = AVCaptureSession()
        
        // 2. 设置视频输入设备
        guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),
              let videoInput = try? AVCaptureDeviceInput(device: camera) else {
            print("Failed to get camera input.")
            return
        }
        captureSession?.addInput(videoInput)
        
        // 3. 设置照片输出
        photoOutput = AVCapturePhotoOutput()
        if let photoOutput = photoOutput {
            captureSession?.addOutput(photoOutput)
        }
        
        // 4. 添加预览图层
        let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
        previewLayer.frame = view.bounds
        previewLayer.videoGravity = .resizeAspectFill
        view.layer.addSublayer(previewLayer)
        
        // 5. 开始捕获会话
        captureSession?.startRunning()
    }

    // 捕获按钮点击事件
    @IBAction func capturePhoto(_ sender: UIButton) {
        let settings = AVCapturePhotoSettings()
        photoOutput?.capturePhoto(with: settings, delegate: self)
    }
    
    // 处理照片捕获结果
    func photoOutput(_ output: AVCapturePhotoOutput,
                     didFinishProcessingPhoto photo: AVCapturePhoto,
                     error: Error?) {
        if let photoData = photo.fileDataRepresentation() {
            let image = UIImage(data: photoData)
            // 保存照片到相册或者使用照片
            UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)
            print("Photo captured.")
        }
    }
}

2.3 视频编辑与导出(AVAssetExportSession) #

示例:裁剪视频并导出 #

import AVFoundation

func trimVideo(inputURL: URL, outputURL: URL, startTime: Double, duration: Double, completion: @escaping (Bool) -> Void) {
    let asset = AVAsset(url: inputURL)
    let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality)!
    
    let start = CMTime(seconds: startTime, preferredTimescale: 600)
    let duration = CMTime(seconds: duration, preferredTimescale: 600)
    let range = CMTimeRange(start: start, duration: duration)
    
    exportSession.outputURL = outputURL
    exportSession.outputFileType = .mp4
    exportSession.timeRange = range
    
    exportSession.exportAsynchronously {
        switch exportSession.status {
        case .completed:
            completion(true)
        case .failed, .cancelled:
            print("Failed: \(String(describing: exportSession.error))")
            completion(false)
        default:
            break
        }
    }
}

2.4 实现音频播放与录制(AVAudioPlayer 和 AVAudioRecorder) #

示例:播放音频 #

import AVFoundation

func playAudio() {
    guard let fileURL = Bundle.main.url(forResource: "audio", withExtension: "mp3") else { return }
    
    do {
        let player = try AVAudioPlayer(contentsOf: fileURL)
        player.play()
    } catch {
        print("Failed to play audio: \(error.localizedDescription)")
    }
}

示例:录制音频 #

import AVFoundation

func recordAudio() {
    guard let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
    let audioPath = documentsPath.appendingPathComponent("record.m4a")
    
    let settings: [String: Any] = [
        AVFormatIDKey: kAudioFormatMPEG4AAC,
        AVSampleRateKey: 44100.0,
        AVNumberOfChannelsKey: 2,
        AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
    ]
    
    do {
        let recorder = try AVAudioRecorder(url: audioPath, settings: settings)
        recorder.record() // 开始录音
    } catch {
        print("Failed to record audio: \(error.localizedDescription)")
    }
}

3. 注意事项 #

  1. 权限管理

    • 如果需要访问用户的摄像头、麦克风或相册,需要在 Info.plist 中声明权限:
      <key>NSCameraUsageDescription</key>
      <string>We need camera access to record videos.</string>
      
      <key>NSMicrophoneUsageDescription</key>
      <string>We need microphone access to record audio.</string>
      
  2. 高耗性能

    • 媒体捕获和编辑的操作会消耗较多内存和 CPU,建议优化。
  3. 文件格式和编码

    • 确保输出文件格式与设备兼容,例如 .mp4.m4a

4. 总结 #

AVFoundation 是一个功能强大且灵活的多媒体框架,主要包含:

  • 播放音视频 AVPlayer
  • 捕获多媒体内容 AVCaptureSession
  • 编辑和导出 AVAssetExportSession
  • 音频管理和处理 AVAudioEngine

适用于创建视频播放器、音视频编辑工具、实时捕获应用等多媒体相关应用。

本文共 1693 字,上次修改于 Jan 1, 2025