简体   繁体   中英

AVPlayerLayer doesn't appear for a few seconds but sound works perfectly

I am working on an app where feed have videos looping in it (inside table view cells). There can be multiple videos present at the same time, but only one of them may be playing. I'm creating AVPlayer s in background, and putting their playerLayer s into my view's layer as a subview, and play the video with the most area on screen when user stops scrolling the feed.

However, recently I noticed that the video is not displayed in the feed when the user stops scrolling. The sound starts immediately, but the video is not displayed. I've checked the player layer's bounds are it's perfectly fine. I've seen AVPlayerLayer shows black screen but sound is working but that question applies only to an older version of iOS. I've also seen AVPlayer Video Blank but Hear Sound but that question is resolved as the OP realized that the bounds of the layer was zero rect. I've added a timer to print my video player's bounds repeatedly, and the bounds is correct even when the video is not displayed.

After a few seconds of sound-only playback, the video just kicks in playing perfectly. I've double checked that the "kick in" doesn't coincide of the video seeking back to 0:00. It just kicks in at a random part of the video. I've also iterated all the superlayers until I've reached UIWindow 's layer. The layer hierarchy correctly reaches the window's layer, and none of the intermediate layers have zero rect. Also, when the video randomly kicks in, none of the above data (superlayers, their rects) change at all. Just to be sure, I've added the following code and I don't get any assertion failures (I've already had NSLog s in it, so yes, it's called):

timer = [NSTimer scheduledTimerWithTimeInterval:0.1 repeats:YES block:^(NSTimer * _Nonnull timer) {
    NSAssert(_playerLayer.bounds.size.width, @"bounds");
    NSAssert(_playerLayer.bounds.size.height, @"bounds");
    NSAssert(!_playerLayer.hidden, @"hidden");
    BOOL inWindow = NO;
    CALayer *layer = _playerLayer.superlayer;
    while(layer){
        layer = layer.superlayer;
        NSAssert(layer.bounds.size.width, @"bounds");
        NSAssert(layer.bounds.size.height, @"bounds");
        NSAssert(!layer.hidden, @"hidden");
        if(layer == [UIApplication sharedApplication].keyWindow.layer){
            inWindow = YES;
            break;
        }
    }
     NSAssert(inWindow, @"not in window");
}]; 

Some observations and summary:

  • The video always plays correctly at the first attempt. The problem starts when I play another video, then come back.
  • None of the layers/views have zero rect, and it goes all the way up to window's layer. I check this in a loop with a timer 10 times every second, and everything looks perfect.
  • The sound starts immediately with no delay, even in those subsequent "problematic" playbacks. In short: there is no problem with sound at all.
  • The videos are streamed over the web (from our own S3 bucket), but are already loaded as they can be played to the end and looped before the problem starts, as the problem doesn't occur at the first playback anyway.
  • I'm using AVPlayer / AVPlayerLayer combo and I don't create new players or layers for the same video again, I have a dictionary of URL-to-player/layer mapping and I use them again.
  • I am on iOS 11.2.5 and iPhone X, though I've also tried the simulator and the problem is present, so I don't think it's related to device.

What might be the problem?

Okay, I've missed out the fact that setting player's bounds must be called on the main queue. I was calling it on a background queue to offload some work from the main queue (which apparently failed), and it was resulting in undefined behavior. I've dispatched it to the main queue and it started working correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM