帶你用AVPlayer實現音訊和視訊播放

奔跑的鴻發表於2021-10-28

專案概述

  • 以下專案是基於AVPlayer的實際運用,實現音訊播放、橫豎屏視訊切換播放、類似抖音的豎屏全屏播放效果。
    專案地址:AVPlayerAudioVideo
    如果文章和專案對你有幫助,還請給個Star⭐️,你的Star⭐️是我持續輸出的動力,謝謝啦?

1.音訊播放器效果:

帶你用AVPlayer實現音訊和視訊播放

2.豎屏和橫屏的切換效果:

帶你用AVPlayer實現音訊和視訊播放

3.類似抖音豎屏全屏的效果:

帶你用AVPlayer實現音訊和視訊播放

豎屏全屏用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 = 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) {
    }];

相關文章