如何将视频PHAsset导出为包含GPS元数据的NSData?
保留视频PHAsset位置元数据的解决方案
你遇到的问题核心在于:直接复制AVURLAsset的临时文件或使用AVAssetExportSession时未正确处理元数据传递,导致GPS信息丢失。以下是两种可靠的解决方法:
方法一:使用PHAssetResourceManager直接导出原始数据(推荐)
PHAssetResourceManager可以直接获取PHAsset的原始媒体数据,完整保留所有元数据(包括GPS信息),无需经过AVAsset的转换,是最稳妥的方式。
代码示例:
// 获取PHAsset对应的原始资源 PHAssetResource *resource = [[PHAssetResource assetResourcesForAsset:asset] firstObject]; NSURL *tempFileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:resource.originalFilename]]; // 导出原始数据到临时文件 [[PHAssetResourceManager defaultManager] writeDataForAssetResource:resource toFile:tempFileURL options:nil completionHandler:^(NSError * _Nullable error) { if (!error) { // 读取文件为NSData用于上传 NSData *videoData = [NSData dataWithContentsOfURL:tempFileURL]; // 此处执行上传逻辑 } else { // 处理导出错误 } }];
方法二:修复AVAssetExportSession的元数据传递
如果必须使用AVAssetExportSession,需要确保正确提取并传递完整的元数据,尤其是GPS相关的元数据项。注意AVAsset的metadata可能不包含全部原始元数据,建议直接从PHAsset获取完整元数据集:
步骤1:从PHAsset提取完整元数据
[asset requestContentEditingInputWithOptions:nil completionHandler:^(PHContentEditingInput * _Nullable contentEditingInput, NSDictionary * _Nonnull info) { if (contentEditingInput) { AVURLAsset *urlAsset = (AVURLAsset *)contentEditingInput.audiovisualAsset; // 筛选出GPS相关的元数据项 NSArray *gpsMetadata = [urlAsset.metadata filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) { AVMetadataItem *item = (AVMetadataItem *)evaluatedObject; return [item.commonKey isEqualToString:AVMetadataCommonKeyLocation]; }]]; // 合并通用元数据与GPS元数据 NSMutableArray *finalMetadata = [NSMutableArray arrayWithArray:urlAsset.commonMetadata]; [finalMetadata addObjectsFromArray:gpsMetadata]; // 执行导出逻辑 [self exportAssetWithMetadata:finalMetadata asset:urlAsset outputURL:yourTempOutputURL]; } }];
步骤2:正确配置AVAssetExportSession
- (void)exportAssetWithMetadata:(NSArray *)metadata asset:(AVAsset *)asset outputURL:(NSURL *)outputURL { // 使用Passthrough预设避免重新编码,减少元数据丢失风险 AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetPassthrough]; exporter.outputURL = outputURL; exporter.outputFileType = AVFileTypeQuickTimeMovie; // 设置完整元数据 exporter.metadata = metadata; // 禁止网络优化,防止系统精简元数据 exporter.shouldOptimizeForNetworkUse = NO; [exporter exportAsynchronouslyWithCompletionHandler:^{ if (exporter.status == AVAssetExportSessionStatusCompleted) { NSData *videoData = [NSData dataWithContentsOfURL:outputURL]; // 此处执行上传逻辑 } else { // 处理导出错误 } }]; }
关键注意点:
- 使用
AVAssetExportPresetPassthrough替代AVAssetExportPresetHighestQuality,避免视频重新编码导致元数据丢失; - 设置
shouldOptimizeForNetworkUse = NO,防止系统为网络传输自动精简元数据; - 确保元数据项的格式与输出文件类型匹配(MOV格式需使用QuickTime规范的元数据键)。
内容的提问来源于stack exchange,提问作者haplo1384
相关产品推荐
相关产品推荐

