Почему начальная загрузка AVPlayer такая медленная? - PullRequest
2 голосов
/ 03 февраля 2020

Я разработал приложение в iOS, которое воспроизводит список видео. Структура данных такова, что я отправляю запрос на свой собственный сервер и получаю URL-адрес сразу для всех видео после создания представлений моего viewController.

После этого я начинаю воспроизводить первый элемент своих URL-адресов один за другим. Проблема в том, что для первого видео загрузка занимает более 10 секунд; но для остальных видеороликов, которые иногда длиннее и длиннее первого, загрузка занимает намного меньше времени (возможно, 1 или 2 секунды).

Обычно мое первое видео очень короткое и очень маленькое. (В среднем 200 КБ), но загрузка по-прежнему занимает намного больше времени, чем, скажем, мое второе видео размером 1 МБ (в 5 раз длиннее, но в 5 раз меньше).

Я изучал проблему для последние 3 дня, и я пробовал много разных способов, которые я упомяну ниже, но мой вопрос: «Почему это происходит?» не способ, который мог бы решить это. Я хочу знать, почему это происходит, поэтому я могу решить эту проблему с моими знаниями об AVFoundation или написать собственный проигрыватель, который, наконец, решит эту проблему для меня.

Это мой код для его инициализации:

self.player = [AVPlayer new];
self.playerView = [[NZPlayerView alloc] initWithPlayer:self.player];
self.playerView.videoGravity = AVLayerVideoGravityResizeAspect;
self.playerView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:self.playerView];
// Constraints

Обратите внимание, что то, что вы видите выше как NZPlayerView, принадлежит мне, и это просто представление, которое содержит AVPlayerLayer внутри него и обрабатывает некоторые дополнительные вещи для меня, такие как приложение, уходящее в фоновый режим и возвращающееся, и так далее, c. Я не думаю, что это представление вызывает какие-либо проблемы, потому что проблема кажется постоянной с другими разработчиками, использующими другие методы инициализации своего проигрывателя.

После того, как я создаю свое представление и отправляю запрос на свой собственный сервер, я получаю список URL-адресов, которые я затем воспроизводил один за другим, используя приведенный ниже код

AVPlayerItem *newCurrentItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:[[self.selectedMovementModel videoURL] url]]];
[self.player replaceCurrentItemWithPlayerItem:newCurrentItem];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];

Затем я воспроизводил видеоплеер, используя метод [self.player playImmediatelyAtRate:1];, который является одним из способов, которыми я на самом деле пытался минимизировать первоначальное зависание Я обычно воспроизводил свой видеопроигрыватель по методу [self.player play];

После завершения воспроизведения этого видео я решаю, стоит ли мне oop видео или нет, и если нет, то оно возвращается к той же самой функции и воспроизводит следующие selectedMovementModel.

Я также наблюдаю self.player.status, self.player.rate, self.player.timeControlStatus и self.player.reasonForWaitingToPlay, используя RACObserve, который работает так же, как KVO, за исключением того, что я надеваю Мне не нужно избавляться от него после того, как я уволил свой viewController, поэтому никаких проблем там тоже нет.

Способы, которые я пробовал, используют: loadValuesAsynchronouslyForKeys:completionHandler: после того, как я создаю свой новый currentItem и на его Активе. Для моего нового currentItem.

я установил для preferredForwardBufferDuration очень маленькое число. Я также попытался установить для свойства automaticallyWaitsToMinimizeStalling моего проигрывателя значение false, но все безрезультатно. Я также профилировал свою сеть, используя инструменты xCode, и кажется, что между моим первым видео и другими нет ничего особенного. iOS начинает загрузку видео порциями, а затем воспроизводит эти порции, как только они становятся доступны, и даже если я настрою свой плеер так, чтобы он загружал все видео перед запуском, мое первое видео должно начаться намного раньше, чем, скажем, мой второй, потому что он намного меньше. Одно из моих предположений состоит в том, что это может занять больше времени, потому что игрок впервые устанавливает соединение с моим ХОСТОМ, а затем игрок поддерживает этот сеанс в течение неизвестного периода времени. Это имело бы смысл, если бы два видео с двух разных сайтов загружались относительно одинаково, но это не так. Первое все еще занимает больше времени.

Другое решение, которое я бы предпочел избежать любой ценой, - это то, что я бы создал экземпляр моего проигрывателя до того, как мой сервер откликнется, или даже страницу раньше и загрузил его с очень маленькое и короткое видео, чтобы оно могло делать то, что должно, прежде чем пользователь увидит длинную загрузку.

Но я бы предпочел знать, что вызывает проблему, прежде чем предпринимать такие отчаянные меры.

EDIT 1 **: я создал синглтон в приложении, в котором есть экземпляр видеоплеера, который я использую во всех моих контроллерах вида. Я инициализировал его с помощью URL и загрузил его. Но у меня все еще есть та же проблема в моих контроллерах представления для первого видео списка. Я также подумал, что, возможно, мой видеоплеер не загружается без интерфейса, но без изменений в результатах. Я попытаюсь прочитать код Telegram, потому что я знаю, что они используют AVPlayer, хотя в большинстве случаев они загружают видео перед его воспроизведением, возможно, есть некоторая подсказка относительно того, как они инициализируют свои видеопроигрыватели.

Заранее спасибо, ребята.

1 Ответ

0 голосов
/ 07 февраля 2020

Я собираюсь ответить на свой вопрос.

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

После дальнейшего изучения я понял, что в моем отладчике xCode есть журналы, в которых говорится, что определенная задача с URL-адресами моего видео "отменяется" с кодом ошибки "-999". Что, безусловно, было интересно, потому что я еще не сказал моему видеоплееру начать воспроизведение.

Я также понял, что мое приложение использует более 180 МБ памяти примерно в то время, когда вызывался метод viewController viewDidLoad. .

Учитывая, что у меня не было доступа к тому, какая задача отменялась (мой собственный запрос не отменялся). Я решил воспользоваться методом отмены класса NSURLSessionDataTask и нашел свою проблему. При инициализации списка моей модели я добавлял в каждую модель функцию, которая определяла бы, должно ли мое видео l oop, используя приведенный ниже код.

    _defineWeakSelf;
    AVAsset *asset = [AVAsset assetWithURL:[NSURL URLWithString:[self.videoURL url]]];
    [asset loadValuesAsynchronouslyForKeys:@[@"duration"] completionHandler:^{
        AVKeyValueStatus status = [asset statusOfValueForKey:@"duration" error:nil];

        weakSelf._shouldLoop = YES;
        if (status == AVKeyValueStatusLoaded)
        {
            CGFloat fullDurationSeconds = CMTimeGetSeconds([asset duration]);
            if (weakSelf._movementType == MovementTypeTime)
                weakSelf._shouldLoop = (fullDurationSeconds < weakSelf.duration);
            else
                weakSelf._shouldLoop = YES;
        }
    }];

Обратите внимание, что _defineWeakSelf - это что-то вроде @strongify и @weakify, за исключением того, что его намного проще использовать.

И это была проблема. каждый раз, когда эта функция использовалась при создании моей модели, создавался новый фоновый поток и отправлялся новый запрос на фактическое получение видео одновременно. что на моем ноутбуке не было бы такой большой проблемой, если бы было максимум 30-40 моделей, но было более 90 моделей, и представьте, что это происходит с телефоном iOS. естественно, ни одно устройство не может отправлять столько запросов одновременно, и некоторые из них отменяются (например, мое первое видео) снова и снова, и когда они будут выполнены, задержка будет go.

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

* Я также проверил использование TelePlay AVPlayer и обнаружил, что моя инициализация очень похожа на него, так что вы можете проверить это также на их Github .

...