You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GPUImage3导出视频至文档目录异常:导出文件损坏求错误排查

导出带滤镜的视频文件损坏问题排查与修复方案

我仔细看了你的代码,发现几个很可能导致导出视频损坏的问题,咱们一个个拆解:

  • 链路错误:Writer没有接收经过滤镜处理的帧
    你当前的设置是让原视频(movie)直接输出到writer,但滤镜后的帧只到了renderView。这种情况下,writer拿到的是未处理的原视频帧,同时你硬编码了writer的尺寸为100x100,和原视频尺寸大概率不匹配,编码时帧尺寸不一致直接会导致文件损坏。正确的做法是让滤镜的输出同时连接到渲染视图和writer,保证writer拿到的是经过滤镜处理且尺寸匹配的帧。

  • viewDidLayoutSubviews会重复执行
    这个方法在视图布局变化(比如屏幕旋转、视图调整大小)时会多次触发,你现在的代码每次触发都会重新创建movie、writer、filter,还会重复启动录制,这会导致文件写入混乱,直接损坏输出文件。应该把视频处理的初始化逻辑移到只执行一次的地方,比如viewDidLoad,或者加个判断确保只初始化一次。

  • LookupFilter的图片加载未做校验
    如果UIImage(named: "Image")加载失败(比如图片不存在、名称写错),lookupImage会是无效状态,滤镜处理会出问题,进而导致输出的视频帧异常,最终损坏文件。最好加个非空校验。

  • 硬编码输出尺寸不合理
    直接指定100x100的尺寸和原视频尺寸不匹配,编码时容易出现兼容性问题,建议使用原视频的尺寸movie.size来初始化writer。

修复后的代码示例

class ViewController: UIViewController {
    @IBOutlet weak var renderView: RenderView!
    var movie: MovieInput!
    var writer: MovieOutput!
    var filter: LookupFilter!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupVideoProcessing()
    }
    
    private func setupVideoProcessing() {
        guard let bundleURL = Bundle.main.resourceURL else {
            print("无法获取资源目录")
            return
        }
        let movieURL = URL(string:"sample_iPod.m4v", relativeTo: bundleURL)!
        
        do {
            let documentDirectory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
            let fileURL = documentDirectory.appendingPathComponent("TestVideo.mov")
            
            // 初始化视频输入,获取原视频尺寸
            movie = try MovieInput(url: movieURL, playAtActualSpeed: true)
            // 使用原视频尺寸初始化writer,避免尺寸不匹配
            writer = try MovieOutput(URL: fileURL, size: movie.size)
            
            // 校验lookup图片是否加载成功
            guard let lookupImage = UIImage(named: "Image") else {
                print("Lookup图片加载失败")
                return
            }
            filter = LookupFilter()
            filter.lookupImage = PictureInput(image: lookupImage)
            
            // 建立正确的链路:原视频→滤镜→渲染视图;滤镜→writer
            movie --> filter --> renderView
            filter --> writer
            
            movie.runBenchmark = true
            movie.start()
            writer.startRecording()
            
            writer.finishRecording {
                print("视频导出完成")
            }
        } catch {
            print("处理视频出错: \(error)")
        }
    }
}

内容的提问来源于stack exchange,提问作者Bhargav Soni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:29:45