Подтвердить что ты не робот

Прогресс AVPlayer

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

Что-то вроде этого:

enter image description here

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Лично я не согласен, что значение 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
    }

}

Ответ 4

Этот метод возвращает буферный интервал времени для вашего 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))
    }
}

Ответ 5

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

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

Ответ 6

Код Суреш Кансуджия в 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));
}