Playing back video in an SKVideoNode causes a black flash before playback begins

一笑奈何 提交于 2019-12-07 05:48:00

问题


I'm using Sprite Kit and an SKVideoNode to play back a short video. When the video node is added to the scene, be that before of after the initial set up, the player flashes black for a brief second.

I have tried using an AVPlayer for the video instead of the video directly, also I've used KVO to only load the SKVideoNode when the video says it's ready to play.

Either way I get a black flash before my video starts to play.

Also there doesn't seem to be a way to add an AVPlayerLayer to the SKScene/SKView, although I don't know if that would help.

Any suggestions on what to try next would be great.

Here's the code I'm using

- (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];
    }
}

Here's an alternative piece of code which just plays the video and gives the same black flash between the video being loaded and it playing.

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];

回答1:


I had a similar problem and solved it like this:

I exported the first frame of the video as PNG. Then I added a SKSpriteNode with that PNG in front of the SKVideoNode. When I start the video, I set the hidden property of the SKSpriteNode to YES.


Here is an simplified example of my code with the relevant parts:

-(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;             
        }
    }
}


This is the best solution I've found so far. I hope that helps you!




回答2:


Having the same issue. My workaround :

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:


strange issue... can you try without using AVPlayerItem ? like this:

  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];


来源:https://stackoverflow.com/questions/22616190/playing-back-video-in-an-skvideonode-causes-a-black-flash-before-playback-begins

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!