MystyxMac
MystyxMac

Reputation: 1552

iOS - How can i get the playable duration of AVPlayer

The MPMoviePlayerController has a property called playableDuration.

playableDuration The amount of currently playable content (read-only).

@property (nonatomic, readonly) NSTimeInterval playableDuration

For progressively downloaded network content, this property reflects the amount of content that can be played now.

Is there something similar for AVPlayer? I can't find anything in the Apple Docs or Google (not even here at Stackoverflow.com)

Thanks in advance.

Upvotes: 9

Views: 19461

Answers (5)

Michal Zaborowski
Michal Zaborowski

Reputation: 5099

Swift version of closes playable duration:

var playableDuration: TimeInterval? {
    guard let currentItem = currentItem else { return nil }
    guard currentItem.status == .readyToPlay else { return nil }

    let timeRangeArray = currentItem.loadedTimeRanges
    let currentTime = self.currentTime()

    for value in timeRangeArray {
        let timeRange = value.timeRangeValue
        if CMTimeRangeContainsTime(timeRange, currentTime) {
            return CMTimeGetSeconds(CMTimeRangeGetEnd(timeRange))
        }
    }

    guard let timeRange = timeRangeArray.first?.timeRangeValue else { return 0}

    let startTime = CMTimeGetSeconds(timeRange.start)
    let loadedDuration = CMTimeGetSeconds(timeRange.duration)
    return startTime + loadedDuration
}

Upvotes: 2

Syed Ali Salman
Syed Ali Salman

Reputation: 2915

all you need is

self.player.currentItem.asset.duration

simply best

Upvotes: 7

Corey Floyd
Corey Floyd

Reputation: 25969

Building on John's Answer…

This is the apparent default behavior of Apple players: "Show the Max Time of the playable range that encloses the current time"

- (NSTimeInterval)currentItemPlayableDuration{

//  use loadedTimeRanges to compute playableDuration.
AVPlayerItem * item = self.audioPlayer.currentItem;

if (item.status == AVPlayerItemStatusReadyToPlay) {
    NSArray * timeRangeArray = item.loadedTimeRanges;

    CMTime currentTime = self.audioPlayer.currentTime;

    __block CMTimeRange aTimeRange;

    [timeRangeArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {

       aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];

        if(CMTimeRangeContainsTime(aTimeRange, currentTime))
            *stop = YES;

    }];

    CMTime maxTime = CMTimeRangeGetEnd(aTimeRange);

    return CMTimeGetSeconds(maxTime);
}
else
{
    return(CMTimeGetSeconds(kCMTimeInvalid));
}

}

Upvotes: 4

John Lingburg
John Lingburg

Reputation: 276

playableDuration can be roughly implemented by following procedure:

- (NSTimeInterval) playableDuration
{
//  use loadedTimeRanges to compute playableDuration.
AVPlayerItem * item = _moviePlayer.currentItem;

if (item.status == AVPlayerItemStatusReadyToPlay) {
    NSArray * timeRangeArray = item.loadedTimeRanges;

    CMTimeRange aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];

    double startTime = CMTimeGetSeconds(aTimeRange.start);
    double loadedDuration = CMTimeGetSeconds(aTimeRange.duration);

    // FIXME: shoule we sum up all sections to have a total playable duration,
    // or we just use first section as whole?

    NSLog(@"get time range, its start is %f seconds, its duration is %f seconds.", startTime, loadedDuration);


    return (NSTimeInterval)(startTime + loadedDuration);
}
else
{
    return(CMTimeGetSeconds(kCMTimeInvalid));
}
}

_moviePlayer is your AVPlayer instance, by checking AVPlayerItem's loadedTimeRanges, you can compute a estimated playableDuration.

For videos that has only 1 secion, you can use this procedure; but for multi-section video, you may want to check all time ranges in array of loadedTimeRagnes to get correct answer.

Upvotes: 17

leviathan
leviathan

Reputation: 11161

You will have to detect when the AVPlayer is ready to play your media file. Let me know, if you don't know how to do this.

However, once the media file is loaded, you can use this method:

#import <AVFoundation/AVFoundation.h>

/**
 * Get the duration for the currently set AVPlayer's item. 
 */
- (CMTime)playerItemDuration {
    AVPlayerItem *playerItem = [mPlayer currentItem];
    if (playerItem.status == AVPlayerItemStatusReadyToPlay) {
        return [[playerItem asset] duration];
    }
    return(kCMTimeInvalid);
}

When you use this method its important to understand (because you're streaming content) that the length value may be invalid or something. So you must check this before using it for processing.

CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration)) {
    return;
}
double duration = CMTimeGetSeconds(playerDuration);

Upvotes: 2

Related Questions