AVFoundation结合Firebase的视频应用播放及上传延迟优化咨询
视频播放与上传优化方案
一、AVPlayer 预加载实现秒开
你当前的实现是触发播放时才创建AVAsset、AVPlayerItem,所有加载逻辑都在播放请求后才执行,自然会有延迟。可按以下方案实现预加载:
实现思路
- 提前初始化AV相关资源:拿到视频URL列表时就预先创建
AVAsset和AVPlayerItem,主动触发元数据加载和前端缓冲 - 配置缓冲参数:设置
preferredForwardBufferDuration提前缓存指定时长的视频数据 - 预preroll准备:提前调用
preroll方法让播放器进入待播放状态,触发播放时直接执行play()即可秒开
优化代码示例
// 提前预加载视频的方法,可在拿到视频URL列表时调用 func preloadVideo(url: URL) -> AVPlayerItem { let asset = AVAsset(url: url) // 异步加载必要的元数据,避免阻塞主线程 asset.loadValuesAsynchronously(forKeys: ["duration", "tracks", "playable"]) { var error: NSError? let status = asset.statusOfValue(forKey: "duration", error: &error) guard status == .loaded else { return } let item = AVPlayerItem(asset: asset) // 预缓冲3秒内容,可根据业务调整 item.preferredForwardBufferDuration = 3 // 提前挂载到播放器,可全局维护一个AVPlayer实例复用 self.avPlayer.replaceCurrentItem(with: item) // 预准备到可播放状态 self.avPlayer.preroll(atRate: 1.0) { _ in // 预加载完成标记,可存在本地字典里记录对应URL的加载状态 self.preloadedItemMap[url.absoluteString] = item } } } // 优化后的播放方法 func playVideo(with outputFileURL: URL) { DispatchQueue.main.async { self.setView(view: self.progressBar, hidden: true) self.progressBar.progress = 0 // 优先取预加载好的item,没有的话再临时创建兜底 let item: AVPlayerItem if let preloadedItem = self.preloadedItemMap[outputFileURL.absoluteString] { item = preloadedItem } else { let asset = AVAsset(url: outputFileURL) item = AVPlayerItem(asset: asset) self.avPlayer.replaceCurrentItem(with: item) } // 避免重复添加layer,可提前创建好AVPlayerLayer复用 if self.previewPlayerLayer == nil { let previewLayer = AVPlayerLayer(player: self.avPlayer) previewLayer.frame = self.view.bounds previewLayer.videoGravity = .resizeAspectFill self.previewView.layer.addSublayer(previewLayer) self.previewPlayerLayer = previewLayer } self.view.layoutIfNeeded() self.avPlayer.play() } }
提示:全局复用AVPlayer和AVPlayerLayer实例,避免每次播放都重新创建,可进一步降低启动延迟。
二、上传优化方案
1. 录制同时同步上传实现
可以实现边录边传,核心思路是获取录制过程中的实时缓冲分片,无需等待整个视频写入完成再上传:
- 用
AVCaptureVideoDataOutput和AVCaptureAudioDataOutput代替AVCaptureMovieFileOutput,在代理方法captureOutput(_:didOutputSampleBuffer:from:)中实时拿到音视频帧 - 本地用
AVAssetWriter写入文件的同时,按固定大小(比如1MB/片)生成分片数据,直接调用Firebase Storage的分片上传接口上传 - 录制完成后补传最后一个分片,再合并成完整的视频文件,这样录制完成时基本已经完成90%以上的上传,几乎无等待
2. Firebase 后台上传支持
Firebase Storage 本身支持后台上传,需要做两处配置:
- 在Xcode项目的「Signing & Capabilities」中添加「Background Modes」能力,勾选「Background fetch」和「Background processing」
- 最新版Firebase SDK会自动管理后台上传任务,只要用户不主动杀掉应用,切后台后上传任务会继续执行,超过系统默认后台时间的话SDK会自动申请延长后台执行时长
上传额外优化建议
- 先压缩再上传:1分钟的视频可压缩到720P 30fps、码率2Mbps左右,体积可缩小70%以上,上传速度提升明显
- 开启断点续传:Firebase上传失败时可获取
resumeData存储到本地,下次启动时用ref.putFile(from: url, metadata: nil, resume: resumeData)继续上传,无需从头传输
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

