Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

loadValuesAsynchronouslyForKeys and multiple values loading

I would like to asynchronously load the duration, time (timestamp the video was created) and locale of an Asset.

All of the sample code shown by Apple for the usage of 'loadValuesAsynchronouslyForKeys:keys' is always shows with only one key. ie:

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   
    }
}];

Can I assume that if one item's status is 'AVKeyValueStatusLoaded', the other values can be read at the same time in the completion block? ie:

[asset tracks]
[asset commonMetadata];
[asset duration]
like image 672
Peter Kovich Avatar asked Jun 21 '11 00:06

Peter Kovich


1 Answers

No, you can't assume that. One of my methods looks at two keys, playable and duration, and I have found that playable is often available while duration isn't yet. I therefor have moved the loadValuesAsynchronouslyForKeys: code into a separate method shouldSave:. The shouldSave: method I call from a timer in a method called saveWithDuration:. Once saveWithDuration: receives a non-zero duration, it goes ahead and saves stuff. To avoid waiting too long, I use an attempt counter for now -- in the future, I'll refine this (you'll notice that the error instance isn't really used at the moment)

- (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];

}

like image 125
Elise van Looij Avatar answered Sep 28 '22 05:09

Elise van Looij