畫中畫功能
iOS9就有了,以前只能在iPad上使用,iOS14開始在iPhone上也可以使用了,一直沒有這方面的需求也沒有具體的研究,不過畢竟是蘋果官方的東西,相信實(shí)現(xiàn)起來(lái)不會(huì)麻煩,有2種辦法來(lái)實(shí)現(xiàn)。前提都需要工程配置一定要對(duì)?。。?/p>
工程配置

// 開啟后臺(tái)播放權(quán)限
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
1. 使用AVPlayerViewController
如果使用的是AVPlayerViewController,只要AVAudioSession和BackgroundMode配置對(duì)就默認(rèn)支持的,不用做其他任何操作。雖然很簡(jiǎn)單,但是相信很少人會(huì)直接用這個(gè)方式,幾乎所有的項(xiàng)目都會(huì)自定義播放器,而不是直接使用系統(tǒng)的這個(gè)全屏播放器。
2. 使用AVPictureInPictureController
使用AVPictureInPictureController承接自己寫的播放器的AVPlayerLayer即可實(shí)現(xiàn),先放出來(lái)一個(gè)官方鏈接??梢灾苯尤タ聪嚓P(guān)API。
在API中可以看到有一個(gè)根據(jù)AVPlayerLayer來(lái)初始化Controller的方法:
/*!
@method initWithPlayerLayer:
@param playerLayer
The player layer from which to source the media content for the Picture in Picture controller.
@abstract Initialize the picture in picture controller with a player layer.
*/
- (nullable instancetype)initWithPlayerLayer:(AVPlayerLayer *)playerLayer;
我們就在ViewController中簡(jiǎn)單粗暴的來(lái)一個(gè)AVPlayer播放一個(gè)視頻嘗試一下,剛開始的思路是這樣的,先播放視頻,當(dāng)用戶將要退到后臺(tái)的時(shí)候,初始化AVPictureInPictureController并且啟動(dòng)畫中畫,后來(lái)實(shí)測(cè)發(fā)現(xiàn)這樣是行不通,初始化AVPictureInPictureController的動(dòng)作必須提前,然后在需要開啟或者停止畫中畫功能,下面的代碼是實(shí)現(xiàn)了在播放視頻的時(shí)候已經(jīng)初始化了AVPictureInPictureController,然后在應(yīng)用將要退到后臺(tái)的時(shí)候開啟畫中畫播放視頻,用戶回到前臺(tái)后停止畫中畫,AVPictureInPictureControllerDelegate中有一些相關(guān)的代理方法,全是可選實(shí)現(xiàn),基本上用不到,可以根據(jù)自己的需要進(jìn)行實(shí)現(xiàn):
#import <AVKit/AVKit.h>
@interface ViewController ()<AVPictureInPictureControllerDelegate>
@property(nonatomic,strong)AVPlayerItem *playItem;
@property(nonatomic,strong)AVPlayer *player;
@property(nonatomic,strong)AVPlayerLayer *playerLayer;
@property(nonatomic,strong)AVPictureInPictureController *pictureInPictureController;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// https://qiniu.hongwan.com.cn/hongwan/v/1982wi5b4690f4rqbd9kk.mp4 橫屏
// https://qiniu.hongwan.com.cn/hongwan/v/990g76sj2wvedbs53vji.mp4 豎屏
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
NSString *urlStr =@"https://qiniu.hongwan.com.cn/hongwan/v/990g76sj2wvedbs53vji.mp4";
self.playItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:urlStr]];
self.player = [[AVPlayer alloc] initWithPlayerItem:self.playItem];
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
_playerLayer.frame = self.view.frame;
_playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
[self.view.layer addSublayer:_playerLayer];
[self.playItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willResignActive) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
// 監(jiān)聽實(shí)現(xiàn)循環(huán)播放
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(loopPlay:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
self.pictureInPictureController = [[AVPictureInPictureController alloc] initWithPlayerLayer:self.playerLayer];
self.pictureInPictureController.delegate = self;
}
-(void)loopPlay:(NSNotification *)notification
{
if (!notification.object) {
return;
}
AVPlayerItem *item = (AVPlayerItem *)notification.object;
__weak __typeof(&*self)weakSelf = self;
[item seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
if (finished) {
[weakSelf.player play];
}
}];
}
-(void)willResignActive
{
if ([AVPictureInPictureController isPictureInPictureSupported]) {
if (self.pictureInPictureController.isPictureInPictureActive) {
[self.pictureInPictureController stopPictureInPicture];
} else {
[self.pictureInPictureController startPictureInPicture];
}
}
}
-(void)didBecomeActive
{
if ([AVPictureInPictureController isPictureInPictureSupported]) {
if (self.pictureInPictureController.isPictureInPictureActive) {
[self.pictureInPictureController stopPictureInPicture];
}
}
}
#pragma mark -------播放屬性監(jiān)聽--------
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"status"]) {
switch (self.playItem.status) {
case AVPlayerStatusReadyToPlay:
if (!self.player.timeControlStatus || self.player.timeControlStatus != AVPlayerTimeControlStatusPaused) {
[self.player play];
}
break;
default:
break;
}
}
}
可能有的同學(xué)會(huì)用到一個(gè)很流行的視頻播放框架ZFPlayer,需要將實(shí)現(xiàn)ZFPlayerMediaPlayback協(xié)議的PlayerManager,將內(nèi)部的avLayer拋出來(lái),然后用這個(gè)layer來(lái)初始化AVPictureInPictureController即可。
以上就是項(xiàng)目中簡(jiǎn)單實(shí)現(xiàn)畫中畫播放視頻的完整流程