.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
#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}; }
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