ios - 为什么AVPlayer的初始加载如此缓慢?

标签 ios objective-c avfoundation avplayer

我已经在iOS中开发了一个播放视频列表的应用程序。数据结构是,在创建viewController的视图之后,我向我自己的服务器发送请求,并立即获取所有视频的URL。

之后,我开始依次播放URL的第一项。
问题是,对于第一个视频,实际加载需要10秒钟以上的时间;但对于其他有时比第一个视频更长且更大的视频,则加载时间要少得多(可能需要1或2秒)。

通常,我的第一个视频非常短且非常小(平均200 KB),但加载时间仍然比我的第二个视频(1 mb)(更长的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并为我处理了一些额外的事情,例如应用程序进入后台并返回等。
我认为这种观点不会引起任何问题,因为对于其他使用其他初始化播放器方法的开发人员而言,该问题似乎仍然存在。

创建视图并将请求发送到自己的服务器后,我将获得一个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];方法播放视频播放器

播放完此视频后,我决定是否循环播放该视频,如果不循环,则返回该相同功能并播放下一个selectedMovementModel

我还使用self.player.status来观察self.player.rateself.player.timeControlStatusself.player.reasonForWaitingToPlayRACObserve,这与KVO的工作方式相同,只是在我关闭viewController之后不必摆脱它,所以那里也没有问题。

我尝试过的方法是使用:创建新的loadValuesAsynchronouslyForKeys:completionHandler:后在其资产上的currentItem。对于新的preferredForwardBufferDuration,我将currentItem设置为非常小的数字。

我还尝试将播放器的automaticallyWaitsToMinimizeStalling属性设置为false,但全部无效。
我还使用xCode工具对我的网络进行了配置,看来我的第一个视频和其他视频没有什么不同。 iOS开始以块的形式下载视频,然后在可用时立即播放这些块,即使我以在开始播放前下载整个视频的方式配置播放器,我的第一个视频也应该比第二个要早得多因为它要小得多。
我的猜测之一是可能需要更长的时间,因为玩家第一次建立与我的HOST的连接,然后玩家将会话保持未知的时间。如果来自两个不同网站的两个视频花费相对相似的时间加载,但是却没有,则很有意义。第一个仍然需要更长的时间。

我宁愿不惜一切代价避免的另一种解决方案是,我将在服务器响应甚至之前的页面之前创建播放器的实例,并加载一个非常短的视频,以便它可以执行其应做的工作在用户必须看到很长的负载之前要做的事情。

但是我宁愿知道采取什么绝望措施之前是什么原因造成的。

编辑1 **:我在应用程序中创建了一个单例,该单例中有我在所有视图控制器中使用的视频播放器的实例。我使用URL对其进行了初始化并加载了它。但是对于列表的第一个视频,我的视图控制器中仍然存在相同的问题。我还认为也许我的视频播放器没有加载缺少界面但结果没有变化。
我将尝试阅读Telegram的代码,因为我知道他们正在使用AVPlayer,即使在大多数情况下他们是在播放视频之前先下载视频,也可能有一些关于如何初始化视频播放器的线索。

预先谢谢你们。

最佳答案

我要回答我自己的问题。

AVPlayer最初延迟的原因是非常罕见的情况,任何人都不会发生,但是考虑到自己找到答案可能很有趣并且很奇怪,我将发布它。

经过进一步调查,我意识到xCode调试器中存在日志,指出视频URL的某个任务被“取消”,错误代码为“-999”。这当然很有趣,因为我还没有告诉视频播放器开始播放。

我还意识到,我的应用程序大约在调用viewController的viewDidLoad方法时使用了超过180 MB的内存。

考虑到我无权取消哪个任务(我自己的请求没有被取消)。我决定解决NSURLSessionDataTask类的cancel方法,发现了我的问题。初始化模型列表时,我正在向每个模型添加一个函数,该函数将确定我的视频是否应使用以下代码循环播放。

    _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手机上。自然地,没有设备能够同时发送这么多请求,并且其中一些请求被一遍又一遍地取消(例如我的第一个视频),当它们完成后,延迟就消失了。

现在,此问题已解决。所有其他建议(包括社区其他成员提供的解决方案)更加有效,并且实际上将初始实例化延迟降低到最低限度。所以,我感谢大家。

*我还检查了Telegram对AVPlayer的使用,发现我的初始化与它非常相似,因此您也可以在其Github上进行检查。

关于ios - 为什么AVPlayer的初始加载如此缓慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60037144/

相关文章:

c++ - 为 iOS 编译 XZ Utils

ios - 标准附件 View 可以位于 UITableViewCell 中的不同位置吗?

ios - AVCaptureVideoDataOutputSampleBufferDelegate.CaptureOutput 未调用

swift - 如何在运行时将 CIFilter 添加到视频

ios - UserDefaults - 使用 Xcode Simulator 时保存不一致

objective-c - 转换 if ((loc = [player locateCardValue :8]) > - 1) to Swift 3

ios - 在 CABasicAnimation 中控制速度

objective-c - 添加和删​​除 View 时跳转到字段时出现问题

iphone - iPhone 中 AVAssetWriter 的内存管理问题?

ios - SKNodes 之间的计算距离不会改变,尽管它们在移动