【问题标题】:Playing back video in an SKVideoNode causes a black flash before playback begins在 SKVideoNode 中播放视频会导致播放开始前出现黑色闪烁
【发布时间】:2014-05-02 05:02:57
【问题描述】:

我正在使用 Sprite Kit 和 SKVideoNode 播放一个短视频。当视频节点添加到场景中时,无论是在初始设置之前还是之后,播放器都会短暂闪烁黑色。

我尝试使用 AVPlayer 来播放视频而不是直接播放视频,我还使用 KVO 仅在视频显示可以播放时加载 SKVideoNode。

无论哪种方式,我都会在视频开始播放之前出现黑色闪光。

似乎也没有办法将 AVPlayerLayer 添加到 SKScene/SKView,尽管我不知道这是否会有所帮助。

任何关于下一步尝试的建议都会很棒。

这是我正在使用的代码

- (void)didMoveToView:(SKView *)view
{
    if (!self.contentCreated) {
        [self createSceneContents];
    }
}

- (void)createSceneContents
{
    NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"IntroMovie" ofType:@"mov"];
    NSURL *introVideoURL = [NSURL fileURLWithPath:resourcePath];
    self.playerItem = [AVPlayerItem playerItemWithURL:introVideoURL];
    self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem];

    [self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

    SKSpriteNode *playButton = [SKSpriteNode spriteNodeWithImageNamed:@"PlayButton"];
    [playButton setPosition:CGPointMake(CGRectGetMidX(self.view.frame), (CGRectGetMidY(self.view.frame) / 5) * 3)];
    [self addChild:playButton];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"status"]) {
        if ([[change objectForKey:NSKeyValueChangeNewKey] integerValue] == AVPlayerItemStatusReadyToPlay) {
            NSLog(@"Change has the following %@", change);
                [self.player prerollAtRate:0 completionHandler:^(BOOL done){
                    SKVideoNode *introVideo = [SKVideoNode videoNodeWithAVPlayer:self.player];
                    [introVideo setSize:CGSizeMake(self.size.width, self.size.height)];
                    [introVideo setPosition:self.view.center];
                    [self addChild:introVideo];
                    [introVideo play];
                    [self.playerItem removeObserver:self forKeyPath:@"status"];
                }];
        }
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

这是一段替代代码,它只播放视频,并在加载视频和播放视频之间提供相同的黑色闪光。

NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"IntroMovie" ofType:@"m4v"];
NSURL *introVideoURL = [NSURL fileURLWithPath:resourcePath];
self.playerItem = [AVPlayerItem playerItemWithURL:introVideoURL];
self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem];

SKVideoNode *introVideo = [SKVideoNode videoNodeWithAVPlayer:self.player];
[introVideo setSize:CGSizeMake(self.size.width, self.size.height)];
[introVideo setPosition:self.view.center];
[self addChild:introVideo];
[introVideo play];

【问题讨论】:

  • skvideonode 在哪里初始化?你能发布skvideonode的代码吗?
  • 在我使用它的地方添加了代码。如您所见,我尝试了预卷代码,这对事情没有任何影响。
  • 在哪里调用[introVideo play]?
  • 对不起,我在测试其他东西时删除了它。在添加节点之后。我已将其添加回代码中。我也尝试过事先启动它,但结果还是一样。
  • 为什么使用观察者?您可以在 initWithSize 中加载视频,然后使用全局变量 SKVideoNode *_introVideo 您可以从任何地方播放视频

标签: sprite-kit avplayer skvideonode


【解决方案1】:

我遇到了类似的问题,然后这样解决了:

我将视频的第一帧导出为 PNG。然后我在SKVideoNode 前面添加了一个带有该PNG 的SKSpriteNode。当我开始播放视频时,我将SKSpriteNodehidden 属性设置为YES


这是我的代码与相关部分的简化示例:

-(void)didMoveToView:(SKView *)view {    

    // add first frame on top of the SKVideoNode 
    firstFrame = [SKSpriteNode spriteNodeWithImageNamed:@"firstFrame"];
    firstFrame.zPosition = 1;
    [self addChild:firstFrame];

    // here I add the SKVideoNode with AVPlayer  
    ......

    // Add KVO  
    [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

}


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (object == player.currentItem && [keyPath isEqualToString:@"status"]) {
        if (player.currentItem.status == AVPlayerItemStatusReadyToPlay) {

            [introVideo play]; 
            firstFrame.hidden = YES;             
        }
    }
}


这是迄今为止我找到的最好的解决方案。希望对你有帮助!

【讨论】:

  • 谢谢。我曾想过按照这些思路做一些事情,但希望会有更简单的事情。感谢您确认这是(至少目前是)要走的路。
【解决方案2】:

有同样的问题。 我的解决方法:

videoNode = SKVideoNode(AVPlayer: player)
videoNode.hidden = true

player.addBoundaryTimeObserverForTimes([1/30.0], queue: dispatch_get_main_queue()) { [unowned self] () -> Void in
    self.videoNode.hidden = false
}

【讨论】:

    【解决方案3】:

    奇怪的问题...您可以尝试不使用 AVPlayerItem 吗?像这样:

      NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"IntroMovie" 
                                                               ofType:@"m4v"];
      NSURL *introVideoURL = [NSURL fileURLWithPath:resourcePath];
    
      AVPlayer *player = [AVPlayer playerWithURL: introVideoURL];
    
      SKVideoNode *introVideo = [[SKVideoNode alloc] initWithAVPlayer: player];
    
      [introVideo setSize:CGSizeMake(self.size.width, self.size.height)];
      [introVideo setPosition:self.view.center];
      [self addChild:introVideo];
      [introVideo play];
    

    【讨论】:

    • 同样的结果。它似乎与使用 AVPlayer 或 AVPlayerItem 无关,并且在不使用任何一个并直接将视频加载到 SKVideoNode 时仍然会发生。
    • 我过去在使用 MPMoviePlayer 时遇到过类似的问题,但您可以将背景颜色或图像插入到处理它的那个中。由于 AVPlayer 和 SKVideoNode 没有视图支持,因此这里没有选项可以这样做。
    猜你喜欢
    • 2021-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-28
    • 2011-05-19
    • 1970-01-01
    相关资源
    最近更新 更多