我从AVPlayer编写自定义播放器以进行视频播放。根据Apple docs设置的视频层:
self.player = [IPLPlayer new];
self.player.playerLayer = (AVPlayerLayer *)self.playerView.layer;
其中self.playerView是这些文档的常用类:
@implementation PlayerView
+ (Class) layerClass {
return [AVPlayerLayer class];
}
- (AVPlayer *)player {
return [(AVPlayerLayer *)[self layer] player];
}
- (void)setPlayer:(AVPlayer *) player {
[(AVPlayerLayer *) [self layer] setPlayer:player];
}
问题是: 当关闭app(主页按钮)或阻止屏幕时,视频播放停止,当恢复仅播放音频播放时,屏幕上的图像仍然是块屏幕之前的图像 - 它是完全静态的并且记录更改帧。
如何在屏幕被阻止后恢复视频播放?
似乎我必须注册通知,并且在应用变为活动后恢复视频层:
-(void)registerNotification
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(willEnterBackground)
name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didEnterForeground)
name:UIApplicationDidBecomeActiveNotification object:nil];
}
-(void)unregisterNotification
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)willEnterBackground
{
NSLog(@"willEnterBackground");
[self.playerView willEnterBackground];
}
-(void)didEnterForeground
{
NSLog(@"didEnterForeground");
[self.playerView didEnterForeground];
}
答案 0 :(得分:17)
一种将所有这些信息捆绑在一起的解决方案。
也许播放器状态应该以不同方式处理,但我喜欢递归方式。
注意:如果您不需要确切的搜索时间,可以使用[_player seekToTime:<#(CMTime)#> completionHandler:<#^(BOOL finished)completionHandler#>]
它更快但它会寻找最近的关键帧。
- (void)viewDidLoad
{
[super viewDidLoad];
....
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
}
-(void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}
....
-(void) appEnteredForeground {
AVPlayerLayer *player = (AVPlayerLayer *)[playerView layer];
[player setPlayer:NULL];
[player setPlayer:_player];
[self playAt:currentTime];
}
-(void) appEnteredBackground {
[_player pause];
currentTime = [_player currentTime];
}
-(void)playAt: (CMTime)time {
if(_player.status == AVPlayerStatusReadyToPlay && _player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
[_player seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
[_player play];
}];
} else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self playAt:time];
});
}
}
答案 1 :(得分:6)
这适用于 Swift 3
在设置视图时添加某处:
NotificationCenter.default.addObserver(self,
selector: #selector(appWillEnterForegroundNotification),
name: .UIApplicationWillEnterForeground, object: nil)
抓住你的玩家并强制它玩:
func appWillEnterForegroundNotification() {
myPlayer.play()
}
如果您不需要,请不要忘记删除观察员:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
答案 2 :(得分:3)
也可以使用UIApplicationWillEnterForegroundNotification
。这样,您就知道您的应用将处于活动状态且对用户可见:
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(appEnteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
答案 3 :(得分:1)
经过一些研究后我发现,同一个包在iOS播放器(WebBrowser,MPMoviePlayerController)中。可能是因为分发类型的内容是渐进式下载。
所以解决方案是:
在所有其他情况下,图像被阻止,或者视图变黑。
答案 4 :(得分:1)
诀窍是当应用 进入后台时将所有视频图层与其玩家分离,并在应用 再次激活后重新附加这些图层。
所以在你的-applicationDidEnterBackground:
中你必须触发一个导致
avPlayerLayer.player = nil;
并在你的-applicationDidBecomeActive:
中重新加入播放器
avPlayerLayer.player = self.avPlayer;
另请参阅Apple的技术说明(QA1668)。