如何让AVFoundation在处理前解码低分辨率视频帧?
问题:让AVFoundation在传入AVMutableVideoComposition处理块前解码更小尺寸的视频帧
我们在应用中使用AVMutableVideoComposition结合Core Image滤镜处理视频(用于播放/预览和导出)。出于性能和内存考虑,希望在旧设备上限制视频帧的处理分辨率——理想状态是让AVFoundation直接向合成器提供指定最大尺寸的视频帧。
原本以为设置合成器的renderSize属性就能实现,但实际发现这只会改变输出帧的尺寸,并不会影响进入合成器处理块的源帧尺寸。示例代码如下:
let composition = AVMutableVideoComposition(asset: asset, applyingCIFiltersWithHandler: { request in let input = request.sourceImage // <- 此图像仍为视频原始尺寸 // ... }) composition.renderSize = CGSize(width: 1280, height: 720) // 示例
如果用户选择4K视频,滤镜链会收到4K输入帧。虽然可以在处理流程内手动缩小帧尺寸,但这会额外消耗资源,尤其是占用大量内存。我们希望AVFoundation能在将帧传入合成器处理块前就按所需尺寸解码,请问是否有办法实现?
解决方案
要让AVFoundation在解码阶段就输出指定尺寸的帧,不能直接依赖AVMutableVideoComposition的便捷初始化方法,需要手动通过AVAssetReader控制解码流程:
1. 用AVAssetReaderTrackOutput指定解码尺寸
创建AVAssetReaderTrackOutput时,通过outputSettings配置目标分辨率和像素格式,AVFoundation会直接解码出对应尺寸的帧,无需后续缩小操作:
guard let videoTrack = asset.tracks(withMediaType: .video).first else { // 处理无视频轨道的情况 return } // 配置目标解码尺寸 let targetSize = CGSize(width: 1280, height: 720) let outputSettings: [String: Any] = [ kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA, kCVPixelBufferWidthKey as String: Int(targetSize.width), kCVPixelBufferHeightKey as String: Int(targetSize.height) ] let readerOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: outputSettings) let assetReader = try! AVAssetReader(asset: asset) assetReader.add(readerOutput) assetReader.startReading()
2. 将解码后的帧传入滤镜处理流程
- 预览场景:结合
AVPlayerItemVideoOutput获取解码后的帧,转换为CIImage后应用Core Image滤镜,再渲染到自定义图层上。 - 导出场景:将处理后的帧通过
AVAssetWriterInputPixelBufferAdaptor写入AVAssetWriter,完成视频导出。
3. 动态适配设备性能
可以根据设备型号或硬件能力动态调整目标分辨率,比如旧设备限制为720p,新设备允许使用原分辨率,平衡性能和画质:
func getTargetResolution() -> CGSize { let deviceModel = UIDevice.current.model // 根据设备型号判断,比如iPhone 8及以下用720p,以上用1080p或原尺寸 if ["iPhone 8", "iPhone 8 Plus", "iPhone 7", "iPhone 7 Plus"].contains(deviceModel) { return CGSize(width: 1280, height: 720) } else { return CGSize(width: 1920, height: 1080) } }
内容的提问来源于stack exchange,提问作者Frank Rupprecht
相关产品推荐
相关产品推荐

