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

iOS Swift环境下使用sunlubo/SwiftFFmpeg库的方法及报错解决求助

SwiftFFmpeg iOS端接入适配方案(适配M1 MacBook + Xcode 13 + 1.0.5版本)

前置环境校验

  • 确认Xcode 13的命令行工具已正确绑定:执行xcode-select -p检查输出是否为/Applications/Xcode.app/Contents/Developer,若路径错误执行sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer修正
  • 确认项目iOS部署目标≥11.0,该版本SwiftFFmpeg最低支持iOS 11.0
  • M1设备必须开启Xcode Rosetta转译:右键Xcode->显示简介->勾选使用Rosetta打开,这是解决1.0.5版本CFFmpeg静态库架构兼容问题的核心步骤

SPM接入步骤(推荐,可解决原始SPM报错问题)

  • 打开Xcode项目,进入Project配置页的Package Dependencies栏,点击+号添加依赖
  • 版本选择栏精确指定版本为1.0.5,不要选择更高版本避免兼容性问题
  • 添加依赖时仅勾选SwiftFFmpeg库绑定到主项目Target即可,无需勾选CFFmpeg
  • 进入Target->Build Settings,搜索Architectures,确认Excluded Architectures中没有添加arm64配置
  • 搜索Search Paths,在Framework Search Paths中添加$(inherited),确保SPM引入的库路径被正确识别
  • 清理Xcode缓存:按Command+Shift+K清理项目,关闭Xcode后删除~/Library/Developer/Xcode/DerivedData下对应项目的缓存文件夹,重新打开Xcode编译即可

手动导入适配步骤(可解决No such module 'CFFmpeg'报错)

如果你坚持使用手动导入方式,按以下步骤调整配置即可解决模块找不到的问题:

  • 拖拽SwiftFFmpeg整个源码文件夹到项目中,勾选Copy items if needed并绑定到主Target
  • 进入Target->Build Settings,搜索Swift Compiler - Search Paths,在Import Paths中添加CFFmpeg源码所在的文件夹路径,路径根据你实际存放的位置调整
  • 搜索Header Search Paths,添加FFmpeg头文件所在路径,权限设置为recursive
  • 进入Target->Build Phases->Compile Sources,确认所有SwiftFFmpeg的.swift文件都已添加到列表中,CFFmpeg的静态库文件已添加到Link Binary With Libraries列表
  • 开启Xcode Rosetta转译,清理缓存后重新编译即可

MP4转MPEGTS示例代码

使用前需要先在需要调用的文件中引入库:import SwiftFFmpeg
转换功能实现代码如下:

func convertMP4ToMPEGTS(inputPath: String, outputPath: String) throws {
    // 注册所有可用格式与编解码器
    AVRegister.all()
    
    // 打开输入MP4文件,读取流信息
    let inputFormatCtx = try AVInputFormat.open(path: inputPath)
    try inputFormatCtx.findStreamInfo()
    
    // 初始化MPEGTS输出上下文
    guard let outputFormat = AVOutputFormat(formatName: "mpegts") else {
        throw NSError(domain: "FFmpegConvert", code: -1, userInfo: [NSLocalizedDescriptionKey: "不支持mpegts格式"])
    }
    let outputCtx = try AVFormatContext(format: outputFormat)
    
    // 音视频流映射
    var streamMap: [Int: Int] = [:]
    var outputStreamIndex = 0
    for inputStreamIndex in 0..<inputFormatCtx.streams.count {
        let inStream = inputFormatCtx.streams[inputStreamIndex]
        let codecType = inStream.codecpar.codecType
        guard codecType == .video || codecType == .audio else {
            continue
        }
        streamMap[inputStreamIndex] = outputStreamIndex
        outputStreamIndex += 1
        
        // 配置输出流参数
        let outStream = outputCtx.addStream()
        try outStream.codecpar.copy(from: inStream.codecpar)
        outStream.codecpar.codecTag = 0
    }
    
    // 打开输出文件写入流
    try outputCtx.openOutput(path: outputPath)
    try outputCtx.writeHeader()
    
    // 循环读写数据包(转封装无需重新编解码,速度极快)
    let packet = AVPacket()
    while try inputFormatCtx.readFrame(into: packet) {
        guard let mappedIndex = streamMap[Int(packet.streamIndex)] else {
            packet.unref()
            continue
        }
        packet.streamIndex = Int32(mappedIndex)
        // 时间基转换
        let inTimebase = inputFormatCtx.streams[Int(packet.streamIndex)].timebase
        let outTimebase = outputCtx.streams[mappedIndex].timebase
        packet.rescaleTs(from: inTimebase, to: outTimebase)
        try outputCtx.writeFrame(packet: packet)
        packet.unref()
    }
    
    // 写入文件尾,关闭输出流
    try outputCtx.writeTrailer()
    outputCtx.closeOutput()
}

注意:转换操作属于IO密集型任务,建议放在子线程执行避免阻塞主线程,调用前请确认输入路径可读、输出路径有写入权限

内容的提问来源于stack exchange,提问作者Ankur Pachauri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 06:15:03