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
相关产品推荐
相关产品推荐

