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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 04:07:08