AVPlayer потоковый прогресс - PullRequest
       5

AVPlayer потоковый прогресс

34 голосов
/ 07 октября 2011

Я успешно использую AVPlayer для потоковой передачи аудио с сервера, и сейчас я хочу показать пользовательский UISlider, который показывает ход буферизации.

Примерно так:

enter image description here

С AVPlayer, похоже, нет способа получить общий размер загрузки или текущую сумму загрузки для аудиофайла, только текущее время воспроизведения иобщее время воспроизведения.

Есть ли обходные пути для этого?

Ответы [ 6 ]

56 голосов
/ 11 октября 2011

Я просто работаю над этим, и пока у меня есть следующее:

- (NSTimeInterval) availableDuration;
{
  NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
  CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
  Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
  Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
  NSTimeInterval result = startSeconds + durationSeconds;
  return result;
}
10 голосов
/ 07 июля 2015

Должно работать хорошо:

Objective-C:

- (CMTime)availableDuration
{
    NSValue *range = self.player.currentItem.loadedTimeRanges.firstObject;
    if (range != nil){
        return CMTimeRangeGetEnd(range.CMTimeRangeValue);
    }
    return kCMTimeZero;
}

Swift версия:

func availableDuration() -> CMTime
{
    if let range = self.player?.currentItem?.loadedTimeRanges.first {
        return CMTimeRangeGetEnd(range.timeRangeValue)
    }
    return .zero
}

Для просмотра текущего значения времени вы можете использовать: CMTimeShow ([self availableDuration]); или CMTimeShow (availableDuration ()) (для быстрого)

3 голосов
/ 22 марта 2018

Лично я не согласен, что значение timeRanges всегда будет иметь значение 1.

Согласно документации

Массив содержит объекты NSValue, содержащие значение CMTimeRange, указывающее временные диапазоны, в течение которых у элемента проигрывателя доступны медиаданные. Возвращенные диапазоны времени могут быть прерывистыми.

Так что это может иметь значения, подобные:

[(начало1, конец1), (начало2, конец2)]

Исходя из моего опыта работы с каркасом hls.js в мире настольных компьютеров, дыры между этими временными интервалами могут быть очень маленькими или большими в зависимости от множества факторов, например: поиск, разрывы и т. Д.

Таким образом, чтобы правильно получить общую длину буфера, вам нужно пройтись по массиву и получить длительность каждого элемента и конкататы.

Если вы ищете значение буфера в текущей воспроизводящей головке, вам необходимо отфильтровать временные диапазоны для времени начала, которое больше текущего времени, и времени окончания, которое меньше текущего времени.

public extension AVPlayerItem {

    public func totalBuffer() -> Double {
        return self.loadedTimeRanges
            .map({ $0.timeRangeValue })
            .reduce(0, { acc, cur in
                return acc + CMTimeGetSeconds(cur.start) + CMTimeGetSeconds(cur.duration)
            })
    }

    public func currentBuffer() -> Double {
        let currentTime = self.currentTime()

        guard let timeRange = self.loadedTimeRanges.map({ $0.timeRangeValue })
            .first(where: { $0.containsTime(currentTime) }) else { return -1 }

        return CMTimeGetSeconds(timeRange.end) - currentTime.seconds
    }

}
0 голосов
/ 05 ноября 2016

код от Суреш Кансуджия в Objective C

NSTimeInterval bufferAvail;

if (player.currentItem != nil) {

    AVPlayerItem *item = player.currentItem;
    if (item.status == AVPlayerStatusReadyToPlay) {
        NSArray *timeRangeArray = item.loadedTimeRanges;
        CMTimeRange aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];
        Float64 startTime = CMTimeGetSeconds(aTimeRange.start);
        Float64 loadedDuration = CMTimeGetSeconds(aTimeRange.duration);

        bufferAvail = startTime + loadedDuration;

        NSLog(@"%@ - %f", [self class], bufferAvail);
    } else {
        NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid)); }
}
else {
    NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid));
}
0 голосов
/ 04 августа 2016

Выбранный ответ может вызвать проблемы, если возвращаемый массив пуст. Вот фиксированная функция:

- (NSTimeInterval) availableDuration
{
    NSArray *loadedTimeRanges = [[_player currentItem] loadedTimeRanges];
    if ([loadedTimeRanges count])
    {
        CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
        Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
        Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
        NSTimeInterval result = startSeconds + durationSeconds;
        return result;
    }
    return 0;
}
0 голосов
/ 09 июня 2016

Этот метод вернет интервал времени буфера для вашего UISlider

public var bufferAvail: NSTimeInterval {

    // Check if there is a player instance
    if ((player.currentItem) != nil) {

        // Get current AVPlayerItem
        var item: AVPlayerItem = player.currentItem
        if (item.status == AVPlayerItemStatus.ReadyToPlay) {

            var timeRangeArray: NSArray = item.loadedTimeRanges
            var aTimeRange: CMTimeRange = timeRangeArray.objectAtIndex(0).CMTimeRangeValue
            var startTime = CMTimeGetSeconds(aTimeRange.start)
            var loadedDuration = CMTimeGetSeconds(aTimeRange.duration)

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