我想异步加载资产的持续时间、时间(创建视频的时间戳)和区域设置。
苹果为使用'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,则必须将其分派到主线程。