AVPlayer簡單使用

前言

  • 公司APP使用七牛的播放器,各類崩潰,各類卡頓問題,一怒之下抽時間,看看有沒蘋果自帶框架比較好解決播放問題,又不想引入其餘庫增長APP大小。發現AVPlayer,確實效率不錯,基本知足業務需求,和同事確認了APP某部分功能播放文件只使用了mp4,m3u8,flv (按使用量前後排序)。AVPlayer不支持flv,因此mp4,m3u8使用AVPlayer,其餘使用七牛播放器SDK.

注意

  • 因爲項目使用較多約束,可是AVPlayer默認渲染不能根據約束大小變化,因此須要重載UIView的一個方法,強制改變layerClass,做爲AVPlayer的渲染層,以便動態適配約束。
.h 文件

#import <UIKit/UIKit.h>
@interface TTVAVPlayerView : UIView
@end



.m 文件

#import "TTVAVPlayerView.h"
#import <AVFoundation/AVFoundation.h>

@implementation TTVAVPlayerView

+ (Class)layerClass {
    return [AVPlayerLayer class];
}

@end

AVPlayer

使用庫

#import <AVFoundation/AVFoundation.h>
#import<MediaPlayer/MediaPlayer.h>
#import<CoreMedia/CoreMedia.h>

初始化

- (NSDictionary*)setupPlayer:(NSString*)url{
    

    //防盜鏈headers
    NSMutableDictionary * headers = [NSMutableDictionary dictionary];
    [headers setObject:@"http://*.itouchtv.cn" forKey:@"Referer"];
    NSURL*liveURL = [NSURL URLWithString:url];
    AVAsset*liveAsset = [AVURLAsset URLAssetWithURL:liveURL options:@{@"AVURLAssetHTTPHeaderFieldsKey" : headers} ];
    AVPlayerItem* playerItem = [AVPlayerItem playerItemWithAsset:liveAsset];
    if (iOS9_OR_LATER) {
        playerItem.canUseNetworkResourcesForLiveStreamingWhilePaused = true;
    }
    if (iOS10_OR_LATER) {
        playerItem.preferredForwardBufferDuration = kPreferredForwardBufferDuration;
    }

    //播放器
    AVPlayer*player = [AVPlayer playerWithPlayerItem:playerItem];
    
    //渲染對象
    TTVAVPlayerView* avPlayerView = [[TTVAVPlayerView alloc ]init];
    AVPlayerLayer* playerLayer = (AVPlayerLayer *)avPlayerView.layer;
    [playerLayer setPlayer:player];
    
    
    return @{@"AVAsset":player,@"TTVAVPlayerView":avPlayerView};
}

狀態監聽

  • 方法一 KVO監聽
static NSString* const kStatusKeyName = @"status";
static NSString* const kLoadedTimeRangesKeyName = @"loadedTimeRanges";
static NSString* const kPlaybackBufferEmptyKeyName = @"playbackBufferEmpty";
static NSString* const kPlaybackLikelyToKeepUpKeyName = @"playbackLikelyToKeepUp";

 - (void)addKVO:(AVPlayerItem*)playerItem{
    if (playerItem == nil) return;
    [playerItem addObserver:self forKeyPath:kStatusKeyName options:NSKeyValueObservingOptionNew context:nil];
    [playerItem addObserver:self forKeyPath:kLoadedTimeRangesKeyName options:NSKeyValueObservingOptionNew context:nil];
    [playerItem addObserver:self forKeyPath:kPlaybackBufferEmptyKeyName options:NSKeyValueObservingOptionNew context:nil];
    [playerItem addObserver:self forKeyPath:kPlaybackLikelyToKeepUpKeyName options:NSKeyValueObservingOptionNew context:nil];
}

- (void)delKVO:(AVPlayerItem*)playerItem{
    @try {
        [playerItem removeObserver:self forKeyPath:kStatusKeyName context:nil];
        [playerItem removeObserver:self forKeyPath:kLoadedTimeRangesKeyName context:nil];
        [playerItem removeObserver:self forKeyPath:kPlaybackBufferEmptyKeyName context:nil];
        [playerItem removeObserver:self forKeyPath:kPlaybackLikelyToKeepUpKeyName context:nil];
    }
    @catch (NSException *exception) {
        DLog(@"屢次刪除了");
    }
}

//監聽得到消息
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    {
        AVPlayerItem *playerItem = (AVPlayerItem *)object;
        
        if ([keyPath isEqualToString:@"status"]) {
            if ([playerItem status] == AVPlayerStatusReadyToPlay) {
                self.playerStatus = TTVPlayerStatusReady;
                
                //status 點進去看 有三種狀態
                CGFloat duration = playerItem.duration.value / playerItem.duration.timescale; //視頻總時間
                DLog(@"準備好播放了,總時間:%.2f", duration);//還能夠得到播放的進度,這裏能夠給播放進度條賦值了
                
                
            } else if ([playerItem status] == AVPlayerStatusFailed || [playerItem status] == AVPlayerStatusUnknown) {
    
                [_player pause];
            }
            
        } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {  //監聽播放器的下載進度
            
            NSArray *loadedTimeRanges = [playerItem loadedTimeRanges];
            CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 獲取緩衝區域
            float startSeconds = CMTimeGetSeconds(timeRange.start);
            float durationSeconds = CMTimeGetSeconds(timeRange.duration);
            NSTimeInterval timeInterval = startSeconds + durationSeconds;// 計算緩衝總進度
            CMTime duration = playerItem.duration;
            CGFloat totalDuration = CMTimeGetSeconds(duration);
            CGFloat bufferdDuration = round(timeInterval);
            
            DLog(@"下載進度:%.2f 當前下載時長:%.2f 總時長:%.2f", timeInterval / totalDuration,self.bufferedTime,totalDuration);
            
            
        } else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) { //監聽播放器在緩衝數據的狀態
            
            DLog(@"緩衝不足暫停了");
            
            
        } else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {
            DLog(@"緩衝達到可播放程度了");
            
           

            //因爲 AVPlayer 緩存不足就會自動暫停,因此緩存充足了須要手動播放,才能繼續播放
            [_player play];
            
        }
 
    }
}
  • 方法二 通知監聽
- (void)addNotification{
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[NSNotificationCenter defaultCenter] removeObserver:self.player];
    
    @weakify(self)
    [[NSNotificationCenter defaultCenter]
     addObserverForName:AVPlayerItemDidPlayToEndTimeNotification
     object:nil queue:[NSOperationQueue mainQueue]
     usingBlock:^(NSNotification * _Nonnull note) {
        @strongify(self)
         DLog(@"播放完成");
    }];
    
    [[NSNotificationCenter defaultCenter]
     addObserverForName:AVPlayerItemFailedToPlayToEndTimeNotification
     object:nil queue:[NSOperationQueue mainQueue]
     usingBlock:^(NSNotification * _Nonnull note) {
         @strongify(self)
         DLog(@"播放出錯");
     }];
}
  • 一些狀態的判斷
@property (nonatomic, strong) AVPlayer *player;


- (BOOL)playing {
    if (self.playerItem.isPlaybackLikelyToKeepUp &&  self.player.rate == 1) {
        return true;
    }
    return false;
}

- (NSUInteger)currentPlayingTime {
    CMTime time = self.player.currentTime;
    return CMTimeGetSeconds(time);
}

- (NSUInteger)totalPlayingTime {
    CMTime time = self.player.currentItem.duration;
    Float64 seconds = CMTimeGetSeconds(time);
    return seconds;
}

- (void)seekTo:(NSUInteger)sec{
    CMTime time = CMTimeMakeWithSeconds(sec, 1);
    [self.player seekToTime:time];
}

- (void)play{
    [self.player play];
}

- (void)resume{
    [self seekTo:self.currentPlayingTime];
    [self.player play];
}

- (void)pause{
    [self.player pause];
}

- (void)stop{
    [self.player pause];
    self.player.muted = true;
    self.player.rate = 0.0;
}

原文:http://raychow.linkfun.top/2017/12/28/archives/1_ios/AVPlayer/index/ios

相關文章
相關標籤/搜索