AVQueuePlayer 的预缓冲
-
26-09-2019 - |
题
有谁知道如果 AVQueuePlayer
开始缓冲下一个 AVPlayerItem
当前项目何时即将结束播放?
我知道文档中没有任何内容表明这一点,我主要是问是否有人观察到这种行为。
解决方案
好吧,我看过了这个问题,并再次写一些代码来看看AVQueuePlayer
。
jollyCocoa的回答通过建议,观察AVPlayerItem
状态属性指出我朝着正确的方向发展。然而,文件似乎并没有指出,该物业(特别是它的AVPlayerItemStatusReadyToPlay
值)可能与缓冲。
然而AVPlayerItem's
loadedTimeRanges
属性似乎更涉及缓冲。
这阵列上做国际志愿者组织是一个有点棘手 - 数组对象本身并没有变化,只是它的项目做的 - 所以我使出打印出它的内容每秒
什么我发现是,在队列中的第一项几秒钟后,loadedTimeRanges
第二项显示了启动时间0和一些小的持续时间的新CMTimeRange
。而以前的项保持的演奏持续时间可以增加高达60秒左右。
<强>短答案:强> AVQueuePlayer
而播放当前的一个将缓冲器中的下一AVPlayerItem
其他提示
作为iOS 5的的,看来AVQueuePlayer不再预缓冲器。它没有预缓冲在IOS 4中的下一个轨道。
我不知道为什么会出现已经有变化,或者如果它甚至在苹果公司的一部分,或者只是一个错误审议。在任何情况下,这是一个痛苦,我将提交错误给他们。
找到了解决办法!经过几个小时的搜索和失败的测试,我找到了一个适用于 iOS 5 及更高版本的解决方案。
这将在播放文件之间没有任何延迟。如果您想在文件之间切换,则不太方便,但肯定会为您将所有内容组合在一起。仍然可以跟踪每个文件的开始位置,添加 AVURLAsset 时,保留 CMTime 变量,例如:
NSValue *toJumpTo = [NSValue valueWithCMTime:composition.duration];
[array addObject:toJumpTo];
然后只需遍历数组,检查当前时间值并使用 CMTimeCompare 进行比较。
编辑:被发现于 这一页 从网络档案中可见(该链接当前指向垃圾邮件)。
我一直在尝试使用由服务器提供的电影AVQueuePlayer。在这个特殊的测试中,我成立了一个queuePlayer与URL的初始化为不同类型的两个不同的视频资产AVPlayerItems。一个是.MP4文件(渐进式下载),另一种的.m3u8 HTTP的流媒体文件。它确实起到了一下时髦,我必须说。
根据我在其中排队文件的顺序,我得到完全不同的行为。如果我开始与.MP4文件,该AVPlayerLayer一片空白无声当nextItem开始播放器(该.m3u8文件)。如果我更改顺序,并与M3U8文件开始,该AVPlayerLayer一片空白,但是从第二个文件中的音频播放罚款。
我的印象中,从我迄今所看到的,就是AVQueuePlayer确实<击>不是击>开始下载下一AVPlayerItem当前AVPlayerItem播放完毕前。但我可能是错的。
要继续我猜...
编辑:好了,我已经做了一些更多的测试,似乎下一个项目开始下载的最后一个项目结束前打。请参见下面的帖子。行程 “NOT” ...
EDIT2:添加我的解释,而不是在这里,因为评论给我留下了没有格式化选项。 (这个最好的做法是值得欢迎的,如果这是一个糟糕的方式来处理答案更新)
总之,我通过使用状态属性的我的itemsArray加入观察迭代KVO ...
[playerItem addObserver: self forKeyPath:@"status" options: 0 context: NULL];
我还设置我的控制器作为AVPlayerItem通知的观察者的 AVPlayerItemDidPlayToEndTimeNotification 强>:
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(playerItemDidReachEnd:)
name: AVPlayerItemDidPlayToEndTimeNotification
object: nil];
现在我可以登录该AVPlayerItem的状态变化,原来在队列中的下一个AVPlayerItem登录状态更改的 AVPlayerItemStatusReadyToPlay 当前项目结束播放之前。
我的结论是为此,在线路的下一个项开始之前的当前项端下载。
但是! 我创建,我用它来创建我的球员AVPlayerItems的数组。阅读AVAssets的AVFoundation文档,我得到的印象是,这些下载他们的资产以异步方式,但我仍然不明朗时,这些下载正在由IAPlayerItem启动。我还有一些时髦的行为,当我的.m3u8文件添加到队列中,这使我怀疑这些资产在开始创建时下载(似乎有些奇怪,我虽然)。的
我做了简单的演示为你和别人说要减少缓冲来自URL每个视频的时间。
注意:不知道这是正确的方式或没有,但它的工作非常适合我没有任何问题。如果有人知道更多或想改善的代码更好的结果,那么欢迎来改变我的答案。
在下面的代码,第一视频采取正常缓冲时间。当前,当视频完成下一个视频将自动启动,您可以刷卡左,右移动下一个和以前的视频。
按照下面的步骤。
<强> 1)在 videoPlayerVC.h 文件强>
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>
@interface videoPlayerVC : UIViewController
{
AVPlayerViewController *avPlyrViewController;
AVPlayerItem *currentAVPlyrItem;
int currentVideoNO; // For current video track.
NSMutableArray *arrOfAVPItems;
NSMutableArray *arrOfPlyer;
}
<强> 2)在 videoPlayerVC.m 文件
在这里,你可以开始通过点击按钮来播放视频。下面是按钮的操作方法。
-(void)clickOnPlayVideosImage:(UIButton *)sender
{
// In my App. all video URLs is up to 15 second.
currentVideoNO = 0;
NSMutableArray *arrForVideoURL = [[NSMutableArray alloc]initWithObjects:
[NSURL URLWithString:@"http://videos/url1.mov"],
[NSURL URLWithString:@"http://videos/url2.mov"],
[NSURL URLWithString:@"http://videos/url3.mov"],
[NSURL URLWithString:@"http://videos/url3.mov"],
[NSURL URLWithString:@"http://videos/url4.mov"],
[NSURL URLWithString:@"http://videos/url5.mov"], nil];
AVPlayerItem *thePlayerItemA = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:0]];
AVPlayerItem *thePlayerItemB = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:1]];
AVPlayerItem *thePlayerItemC = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:2]];
AVPlayerItem *thePlayerItemD = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:3]];
AVPlayerItem *thePlayerItemE = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:4]];
AVPlayerItem *thePlayerItemF = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:5]];
if(arrOfAVPItems.count > 0)
[arrOfAVPItems removeAllObjects];
arrOfAVPItems = nil;
if(arrOfPlyer.count > 0)
[arrOfPlyer removeAllObjects];
arrOfPlyer = nil;
arrOfPlyer = [[NSMutableArray alloc] init];
arrOfAVPItems = [NSMutableArray arrayWithObjects:thePlayerItemA, thePlayerItemB, thePlayerItemC, thePlayerItemD, thePlayerItemE, thePlayerItemF, nil]; // Add All items in the Array
for(AVPlayerItem *myPlyrItem in arrOfAVPItems)
{
AVPlayer *videoPlayerNext = [AVPlayer playerWithPlayerItem:myPlyrItem]; /// Add item in the player
[videoPlayerNext play];
[videoPlayerNext pause];
[arrOfPlyer addObject:videoPlayerNext]; /// Make Array of "AVPlayer" just reduce buffering of each video.
}
avPlyrViewController = [AVPlayerViewController new];
avPlyrViewController.delegate = self;
avPlyrViewController.player = (AVPlayer *)arrOfPlyer[0]; // Add first player from the Array.
avPlyrViewController.showsPlaybackControls = YES;
avPlyrViewController.allowsPictureInPicturePlayback = YES;
avPlyrViewController.videoGravity = AVLayerVideoGravityResizeAspect;
[self presentViewController:avPlyrViewController animated:YES completion:^{
[self performSelector:@selector(playVideos) withObject:nil afterDelay:1];/// call method after one second for play video.
UISwipeGestureRecognizer * swipeleft=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeleftToNextVideo:)];
swipeleft.direction=UISwipeGestureRecognizerDirectionLeft;
[avPlyrViewController.view addGestureRecognizer:swipeleft]; // Add left swipe for move on next video
UISwipeGestureRecognizer * swiperight=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeleftToPerviousVideo:)];
swiperight.direction=UISwipeGestureRecognizerDirectionRight;
[avPlyrViewController.view addGestureRecognizer:swiperight]; // Add right swipe for move on previous video
}];
}
现在写playVideos
方法的代码。
#pragma mark - AVPlayer Methods -
-(void)playVideos
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem]; // remove current "AVPlayerItem" from the notification observe.
if(arrOfAVPItems.count > 0)
{
currentAVPlyrItem = (AVPlayerItem *)arrOfAVPItems[currentVideoNO]; // Add "AVPlayerItem" from the array.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem]; // Add notification observer to indication current "AVPlayerItem" is finish.
// pause and nil previous player if available.
[avPlyrViewController.player pause];
avPlyrViewController.player = nil;
avPlyrViewController.player = (AVPlayer *)arrOfPlyer[currentVideoNO]; // add new player from the array
[avPlyrViewController.player.currentItem seekToTime:kCMTimeZero]; // set for start video on initial position.
[avPlyrViewController.player play]; // Play video
}
}
通知观察者指示视频是光洁度。
- (void)playerItemDidReachEnd:(NSNotification *)notification
{
NSLog(@"IT REACHED THE END");
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem]; // remove current "AVPlayerItem" from the notification observe.
[self swipeleftToNextVideo:nil]; // Call method for next video.
}
方法播放下一个视频
-(void)swipeleftToNextVideo:(UISwipeGestureRecognizer*)gestureRecognizer
{
currentVideoNO++;
if(currentVideoNO > (arrOfAVPItems.count -1))
currentVideoNO = 0;
NSLog(@"current - %d and last - %d", currentVideoNO, (int)(arrOfAVPItems.count -1));
[self playVideos];
}
方法播放一个视频。
-(void)swipeleftToPerviousVideo:(UISwipeGestureRecognizer*)gestureRecognizer
{
currentVideoNO--;
if(currentVideoNO < 0)
currentVideoNO = (int)(arrOfAVPItems.count -1);
NSLog(@"current - %d and last - %d", currentVideoNO, (int)(arrOfAVPItems.count -1));
[self playVideos];
}
按照以下步骤。如果有任何疑问,则建议请。