iOS开发——AVPlayer自定义播放器(持续更新,学习中)
文章目錄
- 一、 前言
- 二、相關(guān)知識點
- 2.1 AVplayerItem
- 2.2 AVplayer
- 2.3 AVPlayerLayer
- 三、代碼部分
- 3.1 單例
- 3.2 將播放器封裝成view
- 四、demo
一、 前言
邊學(xué)邊記錄AVPlayer封裝一個功能十分 全的自定義播放器,目前在學(xué)習(xí)階段,demo和文章會根據(jù)學(xué)習(xí)進(jìn)度與總結(jié)情況去更新,歡迎各位批評指正。
2020年8月1日更新3.2
二、相關(guān)知識點
- AVPlayer本身并不顯示視頻!需要一個AVPlayerLayer播放層來顯示視頻,然后添加到父視圖的layer中。
- AVPlayer只負(fù)責(zé)視頻管理和調(diào)控!而視頻資源是由AVPlayerItem提供的,每個AVPlayerItem對應(yīng)一個視頻地址。
- 工程內(nèi)需要引入AVFoundation庫
- 持續(xù)補(bǔ)充……
2.1 AVplayerItem
(instancetype)playerItemWithURL:(NSURL *)URL; 初始化視頻資源方法
duration 視頻總時長
status 視頻資源的狀態(tài) (需要監(jiān)聽的屬性)
loadedTimeRanges 在線視頻的緩沖進(jìn)度 (需要監(jiān)聽的屬性)
playbackBufferEmpty 進(jìn)行跳轉(zhuǎn),無緩沖 (可選監(jiān)聽)
playbackLikelyToKeepUp 進(jìn)行跳轉(zhuǎn),有緩沖 (可選監(jiān)聽)
2.2 AVplayer
(void) play;
(void) pause; 播放暫停
(void) seekToTime:(CMTime)time;跳轉(zhuǎn)到指定時間
(CMTime) currentTime;獲取當(dāng)前播放進(jìn)度
(void)removeTimeObserver:(id)observer;移除監(jiān)聽 (銷毀播放器的時候調(diào)用)
(void)replaceCurrentItemWithPlayerItem:(nullable AVPlayerItem *)item;切換視頻資源
2.3 AVPlayerLayer
videoGravity 視頻的填充方式
三、代碼部分
3.1 單例
3.2 將播放器封裝成view
單例形式適合多個視頻由一個播放器控制,但是上述寫法明顯存在問題 ,控制不了每個視圖,所以現(xiàn)在想讓每個視圖有自己的播放器
// 相關(guān)方法 - (instancetype)initWithFrame:(CGRect)frame;- (void)setupPlayerWith:(NSURL *)videoURL;- (void)play;- (void)pause;- (void)replay;- (void)destory; // 相關(guān)實現(xiàn) - (instancetype)initWithFrame:(CGRect)frame{self = [super initWithFrame:frame];if (self){self.backgroundColor = [UIColor whiteColor];}return self; }// 準(zhǔn)備播放器 - (void)setupPlayerWith:(NSURL *)videoURL{AVURLAsset *sset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];self.videoScale = [self getVideoSize:sset];[self creatPlayer:videoURL]; }// 獲取播放item - (AVPlayerItem *)getPlayerItem:(NSURL *)videoURL {AVPlayerItem *item = [AVPlayerItem playerItemWithURL:videoURL];return item; }// 創(chuàng)建播放器 - (void)creatPlayer:(NSURL *)videoURL {if (!_player) {self.currentItem = [self getPlayerItem:videoURL];_player = [AVPlayer playerWithPlayerItem:self.currentItem];[self creatPlayerLayer];[self addPlayerObserver];[self addObserverWithPlayItem:self.currentItem];[self addNotificatonForPlayer];} }// 創(chuàng)建視圖 - (void)creatPlayerLayer {CGFloat origin_x = 15;CGFloat main_width = kScreenWidth - (origin_x * 2);self.videoView = [[UIView alloc] initWithFrame:CGRectMake(origin_x, 85, main_width, main_width * self.videoScale)];AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.player];layer.frame = CGRectMake(0, 0, self.videoView.frame.size.width, self.videoView.frame.size.height);layer.videoGravity = AVLayerVideoGravityResizeAspect;[self.videoView.layer addSublayer:layer];[self addSubview:self.videoView];}// 獲取視頻的比例 - (CGFloat)getVideoSize:(AVAsset *)videoAsset{NSArray *array = videoAsset.tracks;CGSize videoSize = CGSizeZero;for(AVAssetTrack *track in array){if([track.mediaType isEqualToString:AVMediaTypeVideo]){videoSize = track.naturalSize;}}CGFloat videoH = videoSize.height;CGFloat videoW = videoSize.width;return videoH / videoW; }#pragma mark - 播放器功能 // 播放 - (void)play {if (self.player.rate == 0) {[self addNotificatonForPlayer];[self addPlayerObserver];}[self.player play]; }// 暫停 - (void)pause {if (self.player.rate == 1.0) {[self.player pause];[self.player seekToTime:kCMTimeZero];} }// 重新開始 - (void)replay {if (self.player.rate == 1.0) {[self.player pause];[self.player seekToTime:kCMTimeZero];[self removeNotification];} else if (self.player.rate == 0){[self addNotificatonForPlayer];[self play];} }- (void)destory {[self pause];[self removeNotification];[self removePlayerObserver]; }#pragma mark - 添加 監(jiān)控 // 給player 添加 time observer - (void)addPlayerObserver {__weak typeof(self)weakSelf = self;_timeObser = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {AVPlayerItem *playerItem = weakSelf.player.currentItem;float current = CMTimeGetSeconds(time);float total = CMTimeGetSeconds([playerItem duration]);NSLog(@"當(dāng)前播放進(jìn)度 %.2f/%.2f.",current,total);}]; } // 移除 time observer - (void)removePlayerObserver {[_player removeTimeObserver:_timeObser]; }- (void)addObserverWithPlayItem:(AVPlayerItem *)item {[item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];[item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];[item addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];[item addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil]; } // 移除 item 的 observer - (void)removeObserverWithPlayItem:(AVPlayerItem *)item {[item removeObserver:self forKeyPath:@"status"];[item removeObserver:self forKeyPath:@"loadedTimeRanges"];[item removeObserver:self forKeyPath:@"playbackBufferEmpty"];[item removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"]; }- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {AVPlayerItem *item = object;if ([keyPath isEqualToString:@"status"]) {// 播放狀態(tài)[self handleStatusWithPlayerItem:item];} }- (void)handleStatusWithPlayerItem:(AVPlayerItem *)item {AVPlayerItemStatus status = item.status;switch (status) {case AVPlayerItemStatusReadyToPlay: // 準(zhǔn)備好播放NSLog(@"AVPlayerItemStatusReadyToPlay");break;case AVPlayerItemStatusFailed: // 播放出錯NSLog(@"AVPlayerItemStatusFailed");break;case AVPlayerItemStatusUnknown: // 狀態(tài)未知NSLog(@"AVPlayerItemStatusUnknown");break;default:break;}}- (void)addNotificatonForPlayer {NSNotificationCenter *center = [NSNotificationCenter defaultCenter];[center addObserver:self selector:@selector(videoPlayEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];[center addObserver:self selector:@selector(videoPlayError:) name:AVPlayerItemPlaybackStalledNotification object:nil];[center addObserver:self selector:@selector(videoPlayEnterBack:) name:UIApplicationDidEnterBackgroundNotification object:nil];[center addObserver:self selector:@selector(videoPlayBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; } // 移除 通知 - (void)removeNotification {NSNotificationCenter *center = [NSNotificationCenter defaultCenter];[center removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:nil]; // [center removeObserver:self name:AVPlayerItemTimeJumpedNotification object:nil];[center removeObserver:self name:AVPlayerItemPlaybackStalledNotification object:nil];[center removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];[center removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];[center removeObserver:self]; }// 視頻播放結(jié)束 - (void)videoPlayEnd:(NSNotification *)notification {NSLog(@"視頻播放結(jié)束"); // self.currentItem = [notic object]; // [self.currentItem seekToTime:kCMTimeZero completionHandler:nil]; // [self.player play];[self.player seekToTime:kCMTimeZero]; // [self.player play]; }// 視頻異常中斷 - (void)videoPlayError:(NSNotification *)notification {NSLog(@"視頻異常中斷"); } // 進(jìn)入后臺 - (void)videoPlayEnterBack:(NSNotification *)notification {NSLog(@"進(jìn)入后臺"); } // 返回前臺 - (void)videoPlayBecomeActive:(NSNotification *)notification {NSLog(@"返回前臺"); }#pragma mark - 銷毀 release - (void)dealloc {NSLog(@"--- %@ --- 銷毀了",[self class]);[self removeNotification];[self removePlayerObserver];[self removeObserverWithPlayItem:self.player.currentItem];}四、demo
文章只是記錄一下相關(guān)部分代碼,會在慢慢進(jìn)行改善。
demo會持續(xù)更新,完善功能 ,一次比一次好。
總結(jié)
以上是生活随笔為你收集整理的iOS开发——AVPlayer自定义播放器(持续更新,学习中)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 吴恩达 深度学习
- 下一篇: 高中函数知识点太多记不住?一张思维导图教