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

iOS开发:编程实现MP4视频章节导航时接口返回空数组问题

问题原因

QuickTime Player对MP4章节的解析覆盖了所有行业常见存储规范,但AVFoundation提供的chapterMetadataGroups(bestMatchingPreferredLanguages:)接口识别范围有限,返回空数组基本是以下两个原因:

  • 语言匹配规则过严:该接口会严格按照传入的语言列表匹配章节的语言标记,大量压制工具导出的MP4章节不会设置语言标签,默认标记为und(未定义语言),直接传入Locale.preferredLanguages无法命中这类无标记章节,直接返回空。
  • 章节存储格式不兼容:MP4章节有两种主流存储方式,一种是苹果生态常用的独立章节文本轨道(带chap轨道引用的text轨),另一种是MP4标准规范里定义的、存储在moov原子udta分区下的chpl章节列表。上述接口仅能识别第一种格式的章节,而后者是很多跨平台压制工具默认使用的章节存储格式,QuickTime可以正常解析,但AVFoundation的这个接口不会读取。
正确实现方式

按照从易到难的顺序兼容所有场景即可:

第一步:兜底匹配无语言标记的章节

不要只传入系统首选语言,额外加入und作为兜底匹配项,覆盖绝大多数无语言标签的章节轨场景,代码如下:

let asset = AVAsset(url: targetVideoURL)
// 提前加载需要用到的属性key
let loadKeys = ["availableChapterLocales", "tracks"]
asset.loadValuesAsynchronously(forKeys: loadKeys) {
    var loadError: NSError?
    // 校验所有属性的加载状态
    for key in loadKeys {
        let status = asset.statusOfValue(forKey: key, error: &loadError)
        guard status == .loaded else {
            print("属性\(key)加载失败: \(loadError?.localizedDescription ?? "未知错误")")
            return
        }
    }
    
    DispatchQueue.main.async {
        var allChapterGroups: [AVTimedMetadataGroup] = []
        // 先匹配系统首选语言的章节
        allChapterGroups.append(contentsOf: asset.chapterMetadataGroups(bestMatchingPreferredLanguages: Locale.preferredLanguages))
        // 兜底匹配无语言标记的章节
        allChapterGroups.append(contentsOf: asset.chapterMetadataGroups(bestMatchingPreferredLanguages: ["und"]))
        
        // 按章节起始时间排序,解析成可用的章节模型
        let sortedChapters = allChapterGroups
            .sorted { $0.timeRange.start.seconds < $1.timeRange.start.seconds }
            .map { group -> (title: String, startTime: TimeInterval) in
                // 优先读取通用标题元数据
                let titleMeta = group.items.first(where: { $0.commonKey == .commonIdentifierTitle })
                let chapterTitle = titleMeta?.stringValue ?? "未命名章节"
                return (chapterTitle, group.timeRange.start.seconds)
            }
        
        // 到这一步sortedChapters就是解析完成的章节列表,如果非空直接用即可
    }
}

第二步:解析chpl格式存储的章节

如果第一步执行完还是拿不到章节,说明章节是存在MP4标准的chpl结构里,AVFoundation没有暴露直接解析的接口,可以按以下方式处理:

  • 先遍历asset.metadata的所有元数据项,查找标识符对应章节列表的项,部分封装工具会把chpl章节映射到com.apple.quicktime.chapter_list元数据项中,可以直接读取解析。
  • 如果元数据里没有对应项,用AVAssetReader读取MP4文件的moov原子二进制数据,手动解析chpl结构即可:
    • chpl结构固定头为:1字节版本号 + 3字节标志位 + 2字节保留位
    • 头之后是4字节无符号整数,表示章节总数量
    • 每个章节条目结构为:8字节无符号整数(章节起始时间,单位毫秒)+ 1字节无符号整数(标题UTF-8编码的字节长度)+ 对应长度的UTF-8编码标题文本

注:如果目标视频存放在iCloud等云端位置,先确认视频已经完整下载到本地,按需加载的云端资源会出现元数据读取不全的问题,你提到QuickTime可以正常显示章节,这个场景可以直接排除。

内容的提问来源于stack exchange,提问作者1058u4

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 14:06:22