使用AVAssetWriter为视频录制添加GPS位置EXIF标签
解决AVAssetWriter写入GPS位置标签的崩溃问题
错误原因分析
崩溃提示核心问题:写入的元数据项的标识符、数据类型、KeySpace组合与初始化时创建的格式描述不匹配:
- 手动配置格式描述时指定了
kCMMetadataDataType_QuickTimeMetadataLocation_ISO6709,但实际生成的元数据项被识别为UTF-8类型 - 元数据项使用了
AVMetadataKeySpace.common,但格式描述对应的是QuickTime元数据标准
修正后的代码实现
1. 初始化元数据写入器(自动匹配格式描述)
func initMetadataWriter() throws { // 用 dummy 元数据项生成格式描述,避免手动配置的不匹配问题 let dummyLocation = CLLocation(latitude: 0, longitude: 0) let dummyMetadataItem = createLocationMetadataItem(location: dummyLocation) let dummyGroup = AVTimedMetadataGroup(items: [dummyMetadataItem], timeRange: .zero) guard let metadataFormatDescription = dummyGroup.copyFormatDescription() else { throw CameraError.location(.cannotWriteLocationToVideo) } let metadataInput = AVAssetWriterInput(mediaType: .metadata, outputSettings: nil, sourceFormatHint: metadataFormatDescription) metadataInput.expectsMediaDataInRealTime = true // 实时录制场景必须开启 guard assetWriter.canAdd(metadataInput) else { throw CameraError.location(.cannotWriteLocationToVideo) } assetWriter.add(metadataInput) metadataWriter = AVAssetWriterInputMetadataAdaptor(assetWriterInput: metadataInput) }
2. 创建符合规范的GPS元数据项
private func createLocationMetadataItem(location: CLLocation) -> AVMetadataItem { let metadataItem = AVMutableMetadataItem() // 匹配QuickTime元数据标准的KeySpace metadataItem.keySpace = AVMetadataKeySpace.quickTimeMetadata // 直接用标识符作为key,避免类型转换问题 metadataItem.key = AVMetadataIdentifier.quickTimeMetadataLocationISO6709.rawValue as (NSCopying & NSObjectProtocol)? // 严格遵循ISO 6709格式,无需末尾斜杠 metadataItem.value = String(format: "%+.6f%+.6f", location.coordinate.latitude, location.coordinate.longitude) as (NSCopying & NSObjectProtocol)? metadataItem.identifier = AVMetadataIdentifier.quickTimeMetadataLocationISO6709 // 指定对应的数据类型,与格式描述完全匹配 metadataItem.dataType = kCMMetadataDataType_QuickTimeMetadataLocation_ISO6709 as String return metadataItem.copy() as! AVMetadataItem }
3. 写入位置标签逻辑
func writeLocationTag(location: CLLocation) throws { guard let metadataWriter else { throw CameraError.location(.cannotWriteLocationToVideo) } let metadataItem = createLocationMetadataItem(location: location) // 时间范围设为整个视频时长,确保元数据全局生效 let metadataGroup = AVTimedMetadataGroup(items: [metadataItem], timeRange: CMTimeRange(start: CMTime.zero, end: assetWriter.duration)) metadataWriter.append(metadataGroup) }
关键注意事项
- 调用时机:必须在
assetWriter.startWriting()之后、第一帧视频/音频写入之前调用writeLocationTag,保证元数据写入文件头部 - 格式兼容性:上述代码同时支持MOV和MP4(H.264/H.265)格式,QuickTime元数据会被正确封装到MP4的moov原子中
- 权限校验:确保已获取
NSLocationWhenInUseUsageDescription权限,能拿到有效的CLLocation实例
内容的提问来源于stack exchange,提问作者mrousavy
相关产品推荐
相关产品推荐

