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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 12:13:17