專案概述
- 以下專案是基于AVPlayer的實際運用,實作音頻播放、橫豎屏視頻切換播放、類似抖音的豎屏全屏播放效果,
專案地址:AVPlayerAudioVideo
如果文章和專案對你有幫助,還請給個Star??,你的Star??是我持續輸出的動力,謝謝啦??
1.音頻播放器效果:
2.豎屏和橫屏的切換效果:
3.類似抖音豎屏全屏的效果:
豎屏全屏用UICollectionView實作,只創建了三個UICollectionViewCell視圖實體,無論有多少視頻需要播放,都是復用這三個UICollectionViewCell視圖實體,有效控制記憶體大小,避免記憶體加載過大、記憶體爆滿的情況,
UICollectionViewCell復用時有一個難點,就是記錄視頻當前已播放的位置,一開始用CMTime來保存發現不行,然后用CMTimeValue和CMTimeScale分別記錄也是存在各種問題,后來使用AVPlayerItem來保存已播放位置才徹底解決,
遇到的問題
- 播放時,揚聲器沒有聲音,插上耳機才有聲音,
原因是app揚聲器默認跟隨系統聲音模式,而手機調了靜音模式,因此揚聲器跟隨靜音模式,沒有聲音,
解決方式:設定Category,讓揚聲器不跟隨系統聲音模式,
//必須設定,否則揚聲器默認跟隨系統聲音模式
//AVAudioSessionCategoryPlayAndRecord模式能播放能錄音,該模式下聲音默認出口是聽筒(戴耳機才有聲音),切換到揚聲器通過以下方式
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
- 當反復快速移動滑塊時,滑塊會出現跳躍的現象,
這是由于移動滑塊時,會呼叫seekToTime:,該方法用于搜索并播放指定視頻幀,執行時需要一點時間,不會立馬搜索并播放到指定視頻幀,此時addPeriodicTimeObserverForInterval:queue:usingBlock:回呼會設定滑塊的位置,出現手指已讓滑塊移動到某一位置,突然有一瞬間滑塊回到之前的位置,然后立馬又回到手指停留的位置,
解決方式:用seekToTime:toleranceBefore:toleranceAfter:completionHandler:代替seekToTime:,搜索并播放到指定視頻幀會有completionHandler的回呼,獲得該回呼后再設定滑塊的位置,具體處理細節詳見專案,
什么是AVPlayer
- AVPlayer存在于AVFoundation框架中,它是一個視頻播放器,用來播放視頻,但也可以用來播放音樂,播放音樂時不需要實作界面,換句話說,只要掌握了視頻播放,音頻播放自然就掌握了,
- AVPlayerItem:和媒體資源存在對應關系,管理媒體資源的資訊和狀態,它的初始化需要URL或AVAsset,
- AVPlayer:播放器,控制資源的播放和暫停,AVPlayerItem是它的屬性,它的初始化需要URL或AVPlayerItem,
+ (instancetype)playerWithURL:(NSURL *)URL;
+ (instancetype)playerWithPlayerItem:(nullable AVPlayerItem *)item;
- AVPlayerLayer:播放器圖層,用于展示視頻內容,AVPlayer是它的屬性,它的初始化需要AVPlayer,如果是播放音頻,則不需要創建AVPlayerLayer,
+ (AVPlayerLayer *)playerLayerWithPlayer:(nullable AVPlayer *)player
- AVPlayerItem、AVPlayer、AVPlayerLayer三者關系,做個類比:
AVPlayerItem是光碟,AVPlayer是dvd影碟機,AVPlayerLayer是電視機螢屏,
視頻播放功能實作
1.通過網路鏈接播放視瞥澩
//url有中文時需要URL編碼
NSURL *url = [NSURL URLWithString:[self.str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:url];
AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
playerLayer.frame = CGRectMake(0, 50, self.view.frame.size.width, 200);
[self.view.layer addSublayer:playerLayer];
2.常用操作
- 播放和暫停
[player play];
[player pause];
- 替換播放資源
[player replaceCurrentItemWithPlayerItem:videoItem];
3.監聽播放進度
- 使用
addPeriodicTimeObserverForInterval:queue:usingBlock:監聽播放器的進度,常用于指示播放進度,獲取播放時長等資訊,
1)Interval引數表示回呼的間隔時間,block是每到一個間隔時間執行一次,
例如Interval傳CMTimeMake(1,10),1表示當前有1幀,10表示每秒10幀,1/10=0.1,即player在播放中時每0.1秒執行一次block,包括開始播放、暫停播放也會回呼,
2)方法回傳一個觀察者物件,當不再播放時,要移除該觀察者,
添加觀察者
self.timeObserve = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 10) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time);
float total = CMTimeGetSeconds(weakSelf.player.currentItem.duration);
weakSelf.playTime = [NSString stringWithFormat:@"%.f",current];
weakSelf.playDuration = [NSString stringWithFormat:@"%.2f",total];
if (weakSelf.slider.isTracking == NO) {
weakSelf.slider.value = https://www.cnblogs.com/johncahong/archive/2021/10/28/current / total;
}
}];
移除觀察者
if (self.timeObserve) {
[self.player removeTimeObserver:self.timeObserve];
}
4.移動滑塊播放指定時刻的視頻幀
- 使用
seekToTime:或seekToTime:completionHandler:或seekToTime:toleranceBefore:toleranceAfter:completionHandler:播放指定時刻的視頻內容,
精確搜索某一時刻的視頻幀可能會導致額外的解碼延遲,seekToTime:默認不是精確搜索,而是有一個小范圍的誤差,
seekToTime:toleranceBefore:toleranceAfter:completionHandler:的搜索的范圍是[time-toleranceBefore, time+toleranceAfter],當toleranceBefore和toleranceAfter設定為kCMTimePositiveInfinity時,執行效果等同于seekToTime:completionHandler:
[self.player seekToTime:goalTime toleranceBefore:kCMTimePositiveInfinity toleranceAfter:kCMTimePositiveInfinity completionHandler:^(BOOL finished) {
}];
本文來自博客園,作者:奔跑的鴻,轉載請注明原文鏈接:https://www.cnblogs.com/johncahong/p/15474081.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/340446.html
標籤:其他
