3

I'm using AVPlayer's -addBoundaryTimeOserverForTimes:queue:usingBlock: to execute some code at a specific time in my video (in this case, I want a un-hide a button when my video reaches its duration. Code is as follows:

- (void)viewWillAppear:(BOOL)animated
{
    ...

    _player = [AVPlayer playerWithURL:videoURL];

    AVPlayerLayer *newPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
    [newPlayerLayer setFrame:_videoView.bounds];
    [_videoView.layer addSublayer:newPlayerLayer];

    _observer = [_player addBoundaryTimeObserverForTimes:@[[NSValue valueWithCMTime:_player.currentItem.duration]] queue:NULL usingBlock:^{
        [someButton setHidden:NO];
    }];

    ...
}

For whatever reason, sometimes the block of code fires and the button becomes visible, and sometimes it doesn't. Haven't been able to find a pattern in this behavior. It happens very often (almost always) in the simulator, and occasionally when on a device. Has anyone encountered this problem? Any ideas what might be going on?

Edit

Also, if I put a breakpoint on the block, it ALWAYS fires.

kid_x
  • 1,415
  • 1
  • 11
  • 31
  • Just a shot in the dark here, but could it be that sometimes the observer is firing on a different thread, maybe try calling the sethidden method from the main thread. – amergin Apr 03 '13 at 09:27
  • The queue parameter, when set to NULL, executes the block on the main queue so, ostensibly, that's already happening. – kid_x Apr 03 '13 at 16:39
  • What about using AVPlayerItemDidPlayToEndTimeNotification instead? Only other thing I can think of is that the CMTime resolution is different for currentItem.duration than the observer is using. – amergin Apr 03 '13 at 21:28
  • Were you able to find a solution to this? I'm seeing a similar issue. – Chris Jun 07 '13 at 16:50
  • Just chiming in to say I'm experiencing this issue, not sure what the problem is. – Nick May 12 '14 at 20:12
  • I was never able to find a solution. It was a little while back, but I recall correctly, older devices and earlier versions of iOS were more vulnerable to the problem. Always thought it related to the 'special considerations' in the docs: "Special Considerations The thread block is invoked on may not be serviced by an application run loop. If you need to perform an operation in the user interface, you must ensure that the work is bounced to the main thread." Never found the way to properly implement it. – kid_x May 13 '14 at 15:30

2 Answers2

0

Main queue sometimes not call. You can use Sub queue, and call Main queue in Sub-queue's block.

// dispatch queue setting
dispatch_queue_t subQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

// notification setting
__block id blockObserver;
blockObserver = [self.queuePlayer addBoundaryTimeObserverForTimes:boundary
                 queue:subQueue // if NULL use mainQueue

  usingBlock:^{
    // do something
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_async(mainQueue, ^{
        // do something
    });
}];
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
siro
  • 1
  • 1
  • I haven't worked with this in quite some time and am not in a position to test this and accept it as the right answer. Should I close this question? – kid_x May 21 '18 at 19:12
0

For those wanting to observe when the player ends:

I browse this question about once a year because I always forget about the fix that works for me. This time around I had this issue on macOS. I am seeing the same behavior, the observer block sometimes does not get called. When I switch back from the app that is being debugged to Xcode the block suddenly fires. This might be related to having a breakpoint set in the block as described by the OP.

Here's the fix however: Simply switch to AVPlayerItemDidPlayToEndTimeNotification as described in this answer. Note however, as the name implies the notification's object is the player's current item not the player itself!

Because this notification triggers at the end time of an item, instead of observing some "boundary time" simply set the item's forwardPlaybackEndTime if you need another time than the item's actual end time, i.e. duration.

bfx
  • 897
  • 10
  • 16