有谁知道如果 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];
}

按照以下步骤。如果有任何疑问,则建议请。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top