iOS - 如何获取AVPlayer的可播放时长?

9
MPMoviePlayerController有一个名为playableDuration的属性。 playableDuration:当前可播放内容的数量(只读)。
@property(nonatomic,readonly)NSTimeInterval playableDuration
对于逐步下载的网络内容,此属性反映了可以立即播放的内容量。
AVPlayer是否有类似的功能? 我在Apple Docs或Google中找不到任何信息(甚至在Stackoverflow.com上也找不到)。
提前感谢。
5个回答

17

可以通过以下步骤大致实现playableDuration:

- (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 是你的 AVPlayer 实例,通过检查 AVPlayerItem 的 loadedTimeRanges 属性,可以计算出估计的可播放时长。

对于只有一个 section 的视频,您可以使用此过程;但对于多节视频,您可能希望检查 loadedTimeRanges 数组中的所有时间范围以获得正确的答案。


1
感谢您的回答。我知道这已经是几个月前的事了,但今天我在回顾一些旧问题。这个解决方案看起来很适合我使用。所以我将其标记为答案。 - MystyxMac

7

你所需要的一切

self.player.currentItem.asset.duration

最好的选择


1
资产持续时间可能不是资产的可播放持续时间,例如当资产未完全加载时。 - yuf
是的,当您从NSURL初始化AVPlayer时,它就是这样工作的。 - Syed Ali Salman

4
在John的回答基础上进行补充... 这是Apple播放器的明显默认行为:“显示包含当前时间的可播放范围的最大时间”。
- (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));
}

}


这段代码是错误的。应该在块内使用“obj”,而不是[timeRangeArray objectAtIndex:0]。 - Joris Weimar

2
你需要检测 AVPlayer 准备好播放媒体文件的时机。 如果你不知道如何操作,请告诉我。
然而,一旦媒体文件加载完毕,你可以使用以下方法:
#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);
}

使用这个方法时很重要的一点是要明白(因为你正在流式传输内容),长度值可能是无效的或其他情况。所以,在使用该方法进行处理之前,必须先检查其有效性。
CMTime playerDuration = [self playerItemDuration];
if (CMTIME_IS_INVALID(playerDuration)) {
    return;
}
double duration = CMTimeGetSeconds(playerDuration);

谢谢您的回答。但是我想知道的是可播放的持续时间,也就是在电影卡顿之前可以播放多久?我会编辑我的问题。 - MystyxMac
MystyxMac是正确的。[[playerItem asset] duration]将返回电影的总持续时间;而不是可播放的持续时间(即可以播放的下载数据量)。 - spd

2

关闭可播放时长的Swift版本:

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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接