iOS - How can i get the playable duration of AVPlayer
Asked Answered
D

5

9

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.

Doran answered 25/7, 2011 at 11:25 Comment(0)
G
17

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.

Gasbag answered 4/9, 2012 at 9:37 Comment(1)
Thanks for your answer. I know it's been a couple of month ago, but today i was reviewing some old questions. This solution look like i could have used. So I mark this as the Answer.Doran
I
7

all you need is

self.player.currentItem.asset.duration

simply best

Internship answered 26/11, 2014 at 7:41 Comment(2)
The asset duration may not be the playable duration of the asset, for example if the asset is not fully loaded.Perpend
Yes that is what AVPlayer does when you initialize it from NSURLInternship
A
4

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

}

Aliment answered 29/8, 2013 at 19:48 Comment(1)
This code is wrong. It should have "obj" inside the block instead of [timeRangeArray objectAtIndex:0]Armillary
O
2

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);
Octant answered 5/8, 2011 at 15:57 Comment(2)
Thanks for your answer. But what i want is the playable duration, how much can i play before the movie will stall? I will edit my question.Doran
MystyxMac is right. [[playerItem asset] duration] will return the total duration of the movie; not the playable duration (i.e amount of downloaded data that can be played.Tallou
T
2

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
}
Thorpe answered 1/9, 2017 at 11:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.