如何让Apple AVKit的AVAsset tracks识别GoPro MP4全部轨道(含GPMF)
如何让AVAsset识别GoPro MP4中的GPMF等自定义数据轨道
AVAsset默认的tracks方法仅返回系统预设的标准媒体轨道(视频、音频、时间码等),而GoPro MP4中的GPMF(GPS数据轨道,gpmd)、SOS(fdsc)属于自定义数据轨道,需要通过异步加载资产+指定媒体类型筛选的方式才能获取。
解决步骤
1. 确保AVAsset完全加载
直接调用asset.tracks可能因资产未加载完成返回不完整轨道列表,必须先异步加载轨道数据:
AVURLAsset *asset = [AVURLAsset assetWithURL:yourGoProVideoURL]; [asset loadValuesAsynchronouslyForKeys:@[@"tracks"] completionHandler:^{ NSError *error = nil; AVKeyValueStatus status = [asset statusOfValueForKey:@"tracks" error:&error]; if (status == AVKeyValueStatusLoaded) { // 资产加载完成,后续处理轨道 [self processAllTracksOfAsset:asset]; } else { NSLog(@"轨道加载失败:%@", error.localizedDescription); } }];
2. 筛选并获取GPMF轨道
通过AVMediaTypeData类型筛选所有数据轨道,再根据媒体子类型(gpmd)定位GPS轨道:
- (void)processAllTracksOfAsset:(AVAsset *)asset { // 获取所有数据类型轨道 NSArray *dataTracks = [asset tracksWithMediaType:AVMediaTypeData]; for (AVAssetTrack *track in dataTracks) { if (track.formatDescriptions.count == 0) continue; // 获取轨道的媒体子类型(对应ffmpeg中的轨道标识) FourCharCode subType = CMFormatDescriptionGetMediaSubType(track.formatDescriptions.firstObject); NSString *subTypeStr = [NSString stringWithFormat:@"%c%c%c%c", (subType >> 24) & 0xFF, (subType >> 16) & 0xFF, (subType >> 8) & 0xFF, subType & 0xFF]; if ([subTypeStr isEqualToString:@"gpmd"]) { NSLog(@"找到GPMF GPS轨道,trackID: %d", track.trackID); // 读取并解析轨道中的GPS数据 [self parseGPMFGPSDataFromTrack:track]; } else if ([subTypeStr isEqualToString:@"fdsc"]) { NSLog(@"找到GoPro SOS轨道,trackID: %d", track.trackID); } } }
3. 读取并解析GPMF轨道数据
使用AVAssetReader读取GPMF轨道的原始数据,再解析其中的GPS信息(GPMF是GoPro自定义的二进制格式,需按格式规范解析):
- (void)parseGPMFGPSDataFromTrack:(AVAssetTrack *)track { NSError *error = nil; AVAssetReader *reader = [AVAssetReader assetReaderWithAsset:track.asset error:&error]; if (!reader) { NSLog(@"创建AssetReader失败:%@", error.localizedDescription); return; } AVAssetReaderTrackOutput *trackOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track outputSettings:nil]; if (![reader canAddOutput:trackOutput]) { NSLog(@"无法添加TrackOutput"); return; } [reader addOutput:trackOutput]; [reader startReading]; NSMutableData *gpmfRawData = [NSMutableData data]; while (reader.status == AVAssetReaderStatusReading) { CMSampleBufferRef sampleBuffer = [trackOutput copyNextSampleBuffer]; if (sampleBuffer) { CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer); size_t dataLength = CMBlockBufferGetDataLength(blockBuffer); uint8_t *buffer = malloc(dataLength); CMBlockBufferCopyDataBytes(blockBuffer, 0, dataLength, buffer); [gpmfRawData appendBytes:buffer length:dataLength]; free(buffer); CMSampleBufferInvalidate(sampleBuffer); CFRelease(sampleBuffer); } } if (reader.status == AVAssetReaderStatusCompleted) { NSLog(@"GPMF数据读取完成,总大小:%lu字节", gpmfRawData.length); // 按GPMF格式解析GPS数据:提取经纬度、海拔、时间戳等信息 // 解析逻辑可参考GPMF格式规范,或使用GoPro官方的解析逻辑 } else { NSLog(@"GPMF数据读取失败:%@", reader.error.localizedDescription); } }
关键说明
- AVAsset默认过滤自定义数据轨道:
tracks方法仅返回AVFoundation预设的媒体类型轨道,自定义数据轨道需通过tracksWithMediaType:AVMediaTypeData主动请求。 - 必须异步加载资产:未加载完成的资产无法返回完整的轨道列表,需通过
loadValuesAsynchronouslyForKeys:确保加载完成。
内容的提问来源于stack exchange,提问作者Steve Mykytyn
相关产品推荐
相关产品推荐

