加载值同步用于键和多个值加载



我想异步加载资产的持续时间、时间(创建视频的时间戳)和区域设置。

苹果为使用'loadValuesAsynchronouslyForKeys:keys'而显示的所有示例代码总是只显示一个键。即:

NSURL *url = aUrl; 
AVAsset asset = [[AVURLAsset alloc] initWithURL:url options:nil];
NSArray *keys = [NSArray arrayWithObject:@"duration"];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^() {
NSError *error = nil;
AVKeyValueStatus durationStatus = [asset statusOfValueForKey:@"duration" error:&error];
switch (durationSatus) {
    case AVKeyValueStatusLoaded:
            // Read duration from asset
            CMTime assetDurationInCMTime = [asset duration];            
        break;
        case AVKeyValueStatusFailed:
            // Report error
        break; 
        case AVKeyValueStatusCancelled:
        // Do whatever is appropriate for cancelation   
    }
}];

我是否可以假设,如果一个项的状态为"AVKeyValueStatusLoaded",则可以在完成块中同时读取其他值?即:

[asset tracks]
[asset commonMetadata];
[asset duration]

不,你不能这么认为。我的一个方法着眼于两个关键点,可玩性和持续时间,我发现可玩性通常是可用的,而持续时间还没有。因此,我已将loadValuesAsynchronouslyForKeys:代码移动到一个单独的方法shouldSave:中。我从名为saveWithDuration:的方法中的计时器调用的shouldSave:方法。一旦saveWithDuration:接收到一个非零的持续时间,它就会继续并保存内容。为了避免等待太久,我现在使用一个尝试计数器——将来,我会完善它(你会注意到错误实例目前并没有真正使用)

- (void)shouldSave:(NSTimer*)theTimer {
NSString * const TBDuration = @"duration";
NSString * const TBPlayable = @"playable";
__block float theDuration = TBZeroDuration;
__block NSError *error = nil;
NSArray *assetKeys = [NSArray arrayWithObjects:TBDuration, TBPlayable, nil];
[_audioAsset loadValuesAsynchronouslyForKeys:assetKeys completionHandler:^() {
    AVKeyValueStatus playableStatus = [_audioAsset statusOfValueForKey:TBPlayable error:&error];
    switch (playableStatus) {
        case AVKeyValueStatusLoaded:
            //go on
            break;
        default:
            return; 
    }
    AVKeyValueStatus durationStatus = [_audioAsset statusOfValueForKey:TBDuration error:&error];
    switch (durationStatus) {
        case AVKeyValueStatusLoaded:
            theDuration = CMTimeGetSeconds(_audioAsset.duration);
            break;
        default:
            return;
    }
}];
NSUInteger attempt = [[[theTimer userInfo] objectForKey:TBAttemptKey] integerValue];
attempt++;
[self saveWithDuration:theDuration attempt:attempt error:&error];

}

从技术上讲,你做不到。loadValuesAsynchronouslyForKeys:completeHandler:的文档说

密钥的完成状态指定in键不一定相同--一些可能已加载,并且其他人可能已经失败了。你必须检查每个按键的状态。

在实践中,我认为这通常是一个安全的假设——正如您所注意到的,苹果的StitchedStreamPlayer示例项目只是查看第一个密钥的状态。

不,你不能这么认为。我通常依靠@"duration"键来创建AVPlayerItem并开始播放,因为加载@"playable"通常不能保证资产已经准备好。然后,我生成一个计时器,定期检查是否加载了@"tracks"等其他密钥,这与Elise van Looij上面提到的类似。

另外,请注意,请记住loadValuesAsynchronouslyForKeys中的completionHandler是在任意后台线程上调用的。如果您正在处理UI或AVPlayerLayer,则必须将其分派到主线程。

最新更新