显示下载进度条,支持边下载边播放。想支持边下边播放需要把视频文件放到指定类型的服务器上,服务器不支持流媒体类型无法支持该功能。
支持整屏播放和缩小屏幕播放。
整屏播放示例:
BGVideoPlayerContainerView *vpcView = [[BGVideoPlayerContainerView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width)]; [self.view addSubview:vpcView]; [vpcView updateWithWaitTime:[self.entity.watch_video_minutes integerValue] urlVideo:self.entity.part_course_video logo:nil playImage:[UIImage imageNamed:@"play_icon"] isShowPlayTime:NO isStartPlay:YES];
缩小局部播放代码示例:
-(BGVideoPlayerContainerView *)vpcView{ if (!_vpcView) { _vpcView = [[BGVideoPlayerContainerView alloc]initWithFrame:CGRectMake(0, 0, sCommonUnitFullWidth(), 217.5*FULL_WIDTH/375)]; [self.contentView addSubview:_vpcView]; } return _vpcView; }
[self.vpcView updateWithWaitTime:waitTime urlVideo:videoUrl logo:logo playImage:[UIImage imageNamed:@"play_icon"] isShowPlayTime:YES isStartPlay:NO];
BGVideoPlayerToolsView.h
#import <UIKit/UIKit.h> #define kVideoPlayerMainBottomHeightShift ({ float space = 0.0; if (@available(iOS 11.0, *)) space = (([[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom)); (space); }) @protocol BGVideoPlayerToolsViewDelegate <NSObject> -(void)playButtonWithStates:(BOOL)state; @end @interface BGVideoPlayerToolsView : UIView @property (nonatomic, strong) UIButton *bCheck;//播放暂停按钮 @property (nonatomic, strong) UISlider *progressSr;//进度条 @property (nonatomic, strong) UIProgressView *bufferPV;//缓冲条 @property (nonatomic, strong) UILabel *lTime;//时间进度和总时长 @property (nonatomic, strong) UIActivityIndicatorView * activityIndicator; @property (nonatomic, weak) id<BGVideoPlayerToolsViewDelegate> delegate; @end
BGVideoPlayerToolsView.m
#import "BGVideoPlayerToolsView.h" @interface BGVideoPlayerToolsView () @end @implementation BGVideoPlayerToolsView -(instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.01]; [self createUI];//创建UI } return self; } #pragma mark - 创建UI -(void)createUI{ [self addSubview:self.bCheck];//开始暂停按钮 [self addSubview:self.bufferPV];//缓冲条 [self addSubview:self.progressSr];//创建进度条 [self addSubview:self.lTime];//视频时间 [self addSubview:self.activityIndicator]; } #pragma mark - 视频时间 -(UILabel *)lTime{ if (!_lTime) { _lTime = [UILabel new]; _lTime.frame = CGRectMake(CGRectGetMaxX(_progressSr.frame) + 20, 0, self.frame.size.width - CGRectGetWidth(_progressSr.frame) - 40 - CGRectGetWidth(_bCheck.frame), self.frame.size.height); _lTime.text = @"00:00/00:00"; _lTime.textColor = [UIColor whiteColor]; _lTime.textAlignment = NSTextAlignmentCenter; _lTime.font = [UIFont systemFontOfSize:12]; _lTime.adjustsFontSizeToFitWidth = YES; } return _lTime; } #pragma mark - 创建进度条 -(UISlider *)progressSr{ if (!_progressSr) { _progressSr = [UISlider new]; _progressSr.frame = CGRectMake(CGRectGetMinX(_bufferPV.frame) - 2, CGRectGetMidY(_bufferPV.frame) - 10, CGRectGetWidth(_bufferPV.frame) - 4+10, 20); _progressSr.maximumTrackTintColor = [UIColor clearColor]; _progressSr.minimumTrackTintColor = [UIColor whiteColor]; [_progressSr setThumbImage:[UIImage imageNamed:@"point"] forState:0]; } return _progressSr; } #pragma mark - 缓冲条 -(UIProgressView *)bufferPV{ if (!_bufferPV) { _bufferPV = [UIProgressView new]; _bufferPV.frame = CGRectMake(CGRectGetMaxX(_bCheck.frame) + 20, CGRectGetMidY(_bCheck.frame) - 2, 200, 4); _bufferPV.trackTintColor = [UIColor grayColor]; _bufferPV.progressTintColor = [UIColor cyanColor]; } return _bufferPV; } -(UIActivityIndicatorView *)activityIndicator{ if (!_activityIndicator) { // _activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleWhite)]; _activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleGray)]; //设置小菊花的frame _activityIndicator.frame= CGRectMake(80, 10, 20, 20); //设置小菊花颜色 _activityIndicator.color = [UIColor redColor]; //设置背景颜色 _activityIndicator.backgroundColor = [UIColor clearColor]; //刚进入这个界面会显示控件,并且停止旋转也会显示,只是没有在转动而已,没有设置或者设置为YES的时候,刚进入页面不会显示 _activityIndicator.hidesWhenStopped = NO; } return _activityIndicator; } #pragma mark - 开始暂停按钮 -(UIButton *)bCheck{ if (!_bCheck) { _bCheck = [UIButton new]; _bCheck.frame = CGRectMake(50, 0, self.frame.size.height, self.frame.size.height); [_bCheck setImage:[UIImage imageNamed:@"pause"] forState:0]; [_bCheck addTarget:self action:@selector(btnCheckSelect:) forControlEvents:UIControlEventTouchUpInside]; } return _bCheck; } -(void)btnCheckSelect:(UIButton *)sender{ sender.selected = !sender.isSelected; if (sender.selected) { [_bCheck setImage:[UIImage imageNamed:@"play"] forState:0]; }else{ [_bCheck setImage:[UIImage imageNamed:@"pause"] forState:0]; } if ([_delegate respondsToSelector:@selector(playButtonWithStates:)]) { [_delegate playButtonWithStates:sender.selected]; } } @end
BGVideoPlayerContainerView.h
#import <UIKit/UIKit.h> NS_ASSUME_NONNULL_BEGIN @interface BGVideoPlayerContainerView : UIView @property (nonatomic, strong) NSString *urlVideo; @property (nonatomic, strong) UIImage *playImage; //@property (nonatomic, strong) NSString *videoUrl; @property (nonatomic, strong) NSString *logo; @property (nonatomic, assign) NSInteger waitTime; @property (nonatomic, assign) BOOL isShowPlayTime; @property (nonatomic, assign) BOOL isStartPlay; -(void)dealloc; - (void)updateWithWaitTime:(NSInteger)waitTime urlVideo:(NSString *)urlVideo logo:(NSString *)logo playImage:(UIImage *)playImage isShowPlayTime:(BOOL)isShowPlayTime isStartPlay:(BOOL)isStartPlay; @end NS_ASSUME_NONNULL_END
BGVideoPlayerContainerView.m
#import "BGVideoPlayerContainerView.h" #import <AVKit/AVKit.h> #import <SDAutoLayout/SDAutoLayout.h> #import <ReactiveCocoa/ReactiveCocoa.h> #import <SDWebImage/SDWebImage.h> #import "BITNoticeView.h" #import "BGVideoPlayerToolsView.h" @interface BGVideoPlayerContainerView ()<BGVideoPlayerToolsViewDelegate> @property (nonatomic, strong) AVPlayer *player; @property (nonatomic, strong) AVPlayerLayer *playerLayer; //@property (nonatomic, strong) NetworkSpeedMonitor *speedMonitor;//网速监听 @property (nonatomic, strong) UILabel *speedTextLabel;//显示网速Label @property (nonatomic, strong) BGVideoPlayerToolsView *vpToolsView;//工具条 @property (nonatomic, strong) id playbackObserver; @property (nonatomic) BOOL buffered;//是否缓冲完毕 @property (nonatomic) BOOL isLoad; @property (nonatomic) BOOL isStartBuffer; @property (nonatomic, strong) UILabel *describeTitleLabel; @property (nonatomic, strong) UIView *bigBackgroundView; @property (nonatomic, strong) UIImageView *photoImageView; @property (nonatomic, strong) UIImageView *iconImageView; @property (nonatomic, strong) UIButton *playButton; @property (nonatomic, assign) BOOL isPlay; @property (nonatomic, assign) BOOL isAuditionOver; @property (nonatomic, assign) float progress; @end @implementation BGVideoPlayerContainerView 设置播放地址 //-(void)setUrlVideo:(NSString *)urlVideo{ // // [self.player seekToTime:CMTimeMakeWithSeconds(0, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; // [self.player play];//开始播放视频 [self updatePlayBtn]; [self.speedMonitor startNetworkSpeedMonitor];//开始监听网速 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkSpeedChanged:) name:NetworkDownloadSpeedNotificationKey object:nil]; // _urlVideo = urlVideo; // AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:urlVideo]]; // [self vpc_addObserverToPlayerItem:item]; // dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // [self.player replaceCurrentItemWithPlayerItem:item]; // [self vpc_playerItemAddNotification]; // }); // //} //设置播放地址 -(void)startBuffer { [self.player seekToTime:CMTimeMakeWithSeconds(0, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; [self.player play];//开始播放视频 // [self updatePlayBtn]; // [self.speedMonitor startNetworkSpeedMonitor];//开始监听网速 // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkSpeedChanged:) name:NetworkDownloadSpeedNotificationKey object:nil]; // _urlVideo = urlVideo; AVPlayerItem *item = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:self.urlVideo]]; [self vpc_addObserverToPlayerItem:item]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self.player replaceCurrentItemWithPlayerItem:item]; [self vpc_playerItemAddNotification]; }); self.isStartBuffer = YES; [self.vpToolsView.activityIndicator startAnimating]; } -(instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { self.backgroundColor = [UIColor blackColor];//[UIColor groupTableViewBackgroundColor]; [self.layer addSublayer:self.playerLayer]; [self addSubview:self.speedTextLabel]; [self addSubview:self.vpToolsView]; [self setupViewWithFrame:frame]; } return self; } -(void)setupViewWithFrame:(CGRect)frame { self.backgroundColor = [UIColor blackColor]; // self.bigBackgroundView = [[UIView alloc]init]; // self.bigBackgroundView.backgroundColor = [UIColor clearColor]; // [self addSubview:self.bigBackgroundView]; self.frame = frame; [self addSubview:self.photoImageView]; [self addSubview:self.playButton]; [self addSubview:self.iconImageView]; [self addSubview:self.describeTitleLabel]; [self unitsSdLayout]; // @weakify(self); // [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil] subscribeNext:^(id x) { // @strongify(self); // [self.player pause]; // self.isPlay = NO; // self.vpToolsView.hidden = !self.isStartPlay; // [self updatePlayBtn]; // [[BITNoticeView currentNotice] showErrorNotice:@"试听结束"]; // }]; // [BGCommonCustomTimer sharedInstance].scanningTimerCallBack = ^{ // @strongify(self); // if(self.waitTime >0) // { // long long timeInterval = (self.startTime + self.waitTime*60000 - (long long)([[NSDate date] timeIntervalSince1970]*1000 + [BITSingleObject sharedInstance].localServerDifferenceTime))/1000 -113; // NSLog(@"timeInterval:%lld, self.waitTime:%d", timeInterval, self.waitTime); // if(timeInterval <= 0) // { self.isNotFirstPlay = YES; // [self stopTime]; // } // else if(timeInterval > self.waitTime*60000) // { self.isNotFirstPlay = YES; // [self stopTime]; // } // else // { long long minute = timeInterval / 60; self.describeTitleLabel.text = [NSString stringWithFormat:@"%lld:%lld", minute, timeInterval % 60]; // // } // } // else // { // self.hidden = YES; // } // }; } -(void)unitsSdLayout { // self.bigBackgroundView.sd_layout // .topSpaceToView(self, 0) // .leftSpaceToView(self, 0) // .widthIs(self.frame.size.width) // .heightIs(self.frame.size.height); self.photoImageView.sd_layout .topSpaceToView(self, 0) .leftSpaceToView(self, 0) .widthIs(self.frame.size.width) .heightIs(self.frame.size.height); self.iconImageView.sd_layout .centerYEqualToView(self) .centerXEqualToView(self) .widthIs(80) .heightIs(80); // self.playButton.backgroundColor = [UIColor redColor]; self.playButton.sd_layout .topSpaceToView(self, 0) .leftSpaceToView(self, 0) .widthIs(self.frame.size.width) .heightIs(self.frame.size.height-50); self.describeTitleLabel.sd_layout .topSpaceToView(self.iconImageView, 10) .leftSpaceToView(self, 15) .rightSpaceToView(self, 15) .heightIs(14); // [self.describeTitleLabel setSingleLineAutoResizeWithMaxWidth:200]; } - (void)updateWithWaitTime:(NSInteger)waitTime urlVideo:(NSString *)urlVideo logo:(NSString *)logo playImage:(UIImage *)playImage isShowPlayTime:(BOOL)isShowPlayTime isStartPlay:(BOOL)isStartPlay { if(self.waitTime > 0 && [self achiveStringWithWeb:urlVideo]) { if(!self.isLoad) { [self.layer addSublayer:self.playerLayer]; [self addSubview:self.speedTextLabel]; [self addSubview:self.vpToolsView]; self.isLoad = YES; } } self.waitTime = waitTime; self.logo = logo; self.playImage = playImage; self.isShowPlayTime = isShowPlayTime; self.isStartPlay = isStartPlay; self.isStartBuffer = NO; if([self achiveStringWithWeb:urlVideo]) { // self.bigBackgroundView.hidden = isStartPlay; self.urlVideo = urlVideo; if(isStartPlay) { [self startBuffer]; // self.playButton.hidden = YES; self.photoImageView.hidden = YES; self.iconImageView.hidden = YES; self.describeTitleLabel.hidden = YES; self.isPlay = YES; } else { self.isPlay = NO; [self updatePlayBtn]; [self.player pause]; } self.vpToolsView.hidden = !isStartPlay; } else { self.vpToolsView.hidden = YES; self.isPlay = NO; // self.playButton.hidden = YES; self.photoImageView.hidden = YES; self.iconImageView.hidden = YES; self.describeTitleLabel.hidden = YES; } } - (BOOL)achiveStringWithWeb:(NSString *)infor { if([infor isKindOfClass:[NSNull class]] || infor == nil || ![infor isKindOfClass:[NSString class]]) { return NO; } NSString *emailRegex = @"[a-zA-z]+://.*"; NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex]; return [emailTest evaluateWithObject:infor]; } -(void)setPlayImage:(UIImage *)playImage { if(playImage) { _playImage = playImage; self.iconImageView.image = playImage; self.iconImageView.sd_layout .centerYEqualToView(self) .centerXEqualToView(self) .widthIs(self.playImage.size.width) .heightIs(self.playImage.size.width); [self.iconImageView updateLayout]; [self.describeTitleLabel updateLayout]; } } -(void)setIsShowPlayTime:(BOOL)isShowPlayTime { _isShowPlayTime = isShowPlayTime; self.describeTitleLabel.hidden = !isShowPlayTime; if(isShowPlayTime) { if(self.waitTime == 10000000) { self.describeTitleLabel.hidden = YES; } else { self.describeTitleLabel.hidden = NO; self.describeTitleLabel.text = [NSString stringWithFormat:@"可试听%ld分钟", self.waitTime]; } [self.iconImageView updateLayout]; [self.describeTitleLabel updateLayout]; } } -(void)setLogo:(NSString *)logo { if([self achiveStringWithWeb:logo]) { [self.photoImageView sd_setImageWithURL:[NSURL URLWithString:logo]]; // self.photoImageView.hidden = NO; if([self achiveStringWithWeb:logo]) { // [self.photoImageView sd_setImageWithURL:[NSURL URLWithString:logo]]; self.photoImageView.hidden = NO; } else { self.photoImageView.hidden = YES; } } else { self.photoImageView.hidden = YES; } _logo = logo; } - (UILabel *)describeTitleLabel { if(!_describeTitleLabel) { _describeTitleLabel = [self createLabel]; _describeTitleLabel.backgroundColor = [UIColor clearColor]; _describeTitleLabel.text = @"可试听5分钟";//[NSString stringWithFormat:@"可试听%ld分钟", self.waitTime]; _describeTitleLabel.font = [UIFont systemFontOfSize:14]; _describeTitleLabel.textColor = [UIColor whiteColor]; _describeTitleLabel.textAlignment = NSTextAlignmentCenter; _describeTitleLabel.hidden = YES; } return _describeTitleLabel; } - (UIButton *)playButton { if (!_playButton) { _playButton = [[UIButton alloc] init]; [_playButton setTitle:@"" forState:UIControlStateNormal]; // [_playButton setImage:[UIImage imageNamed:@"play_icon"] forState:UIControlStateNormal]; _playButton.backgroundColor = [UIColor clearColor]; _playButton.userInteractionEnabled = YES; // _playButton.hidden = YES; @weakify(self); [[_playButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { @strongify(self); if(self.isAuditionOver) { [self.player pause]; self.isPlay = NO; self.vpToolsView.hidden = !self.isStartPlay; [self updatePlayBtn]; [[BITNoticeView currentNotice] showErrorNotice:@"试听结束"]; return; } if (self.isPlay) { [self.player pause]; self.isPlay = NO; self.vpToolsView.hidden = !self.isStartPlay; }else{ self.vpToolsView.hidden = NO; if(!self.isStartBuffer) { [self startBuffer]; } else { [self.player play]; } self.isPlay = YES; } [self updatePlayBtn]; // if(self.isNotFirstPlay || self.waitTime <= 0) // [self startPlay]; }]; } return _playButton; } - (UIImageView *)photoImageView { if(!_photoImageView) { _photoImageView = [self createImageView]; // [_photoImageView.layer setMasksToBounds:YES]; _photoImageView.contentMode = UIViewContentModeScaleAspectFit;//等比缩放把图片整体显示在ImageView中,所以可能会出现ImageView有空白部分 ;//等比缩放图片把整个ImageView填充满,所以可能会出现图片部分显示不出来 _photoImageView.clipsToBounds = YES; // _photoImageView.contentMode = UIViewContentModeScaleAspectFill;//等比缩放图片把整个ImageView填充满,所以可能会出现图片部分显示不出来 _photoImageView.hidden = NO; _photoImageView.backgroundColor = [UIColor clearColor]; _photoImageView.userInteractionEnabled = YES; } return _photoImageView; } -(UILabel *)createLabel { UILabel *label = [[UILabel alloc] init]; label.backgroundColor = [UIColor clearColor]; label.textAlignment = NSTextAlignmentLeft; label.font = [UIFont systemFontOfSize:14]; label.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1]; label.text = @""; return label; } - (UIImageView *)createImageView { UIImageView *imageView = [[UIImageView alloc] init]; imageView.contentMode = UIViewContentModeScaleAspectFit;//等比缩放把图片整体显示在ImageView中,所以可能会出现ImageView有空白部分 UIViewContentModeScaleAspectFill;//等比缩放图片把整个ImageView填充满,所以可能会出现图片部分显示不出来 imageView.clipsToBounds = YES; imageView.backgroundColor = [UIColor whiteColor]; return imageView; } - (UIImageView *)iconImageView { if(!_iconImageView) { _iconImageView= [[UIImageView alloc] init]; _iconImageView.contentMode = UIViewContentModeScaleAspectFit;//等比缩放把图片整体显示在ImageView中,所以可能会出现ImageView有空白部分 UIViewContentModeScaleAspectFill;//等比缩放图片把整个ImageView填充满,所以可能会出现图片部分显示不出来 _iconImageView.clipsToBounds = YES; _iconImageView.backgroundColor = [UIColor clearColor]; _iconImageView.image = [UIImage imageNamed:@"play_icon"]; // [_iconImageView addCornerWithCornerRadius:75.0/2]; } return _iconImageView; } -(void)updatePlayBtn { if([self achiveStringWithWeb:self.urlVideo]) { self.playButton.hidden = NO; if([self achiveStringWithWeb:self.logo]) { // [self.photoImageView sd_setImageWithURL:[NSURL URLWithString:logo]]; self.photoImageView.hidden = NO; self.photoImageView.hidden = self.isPlay; } else { self.photoImageView.hidden = YES; } // self.photoImageView.hidden = NO; self.iconImageView.hidden = self.isPlay; self.describeTitleLabel.hidden = self.isPlay; // [self.playButton setImage:[UIImage imageNamed:@"play_icon"] forState:UIControlStateNormal]; // [self.photoImageView sd_setImageWithURL:[NSURL URLWithString:self.entity.pic]]; } else { self.playButton.hidden = YES; self.photoImageView.hidden = YES; self.iconImageView.hidden = YES; self.describeTitleLabel.hidden = YES; } } //- (void)networkSpeedChanged:(NSNotification *)sender { // NSString *downloadSpped = [sender.userInfo objectForKey:NetworkSpeedNotificationKey]; // self.speedTextLabel.text = downloadSpped; //} #pragma mark - 工具条 -(BGVideoPlayerToolsView *)vpToolsView{ if (!_vpToolsView) { _vpToolsView = [[BGVideoPlayerToolsView alloc]initWithFrame:CGRectMake(0, CGRectGetHeight(self.frame) - (40+kVideoPlayerMainBottomHeightShift), CGRectGetWidth(self.frame), 40)]; _vpToolsView.delegate = self; // _vpToolsView.progressSr.backgroundColor = [UIColor redColor]; [_vpToolsView.progressSr addTarget:self action:@selector(vpc_sliderTouchBegin:) forControlEvents:UIControlEventTouchDown]; [_vpToolsView.progressSr addTarget:self action:@selector(vpc_sliderValueChanged:) forControlEvents:UIControlEventValueChanged]; [_vpToolsView.progressSr addTarget:self action:@selector(vpc_sliderTouchEnd:) forControlEvents:UIControlEventTouchUpInside]; } return _vpToolsView; } -(void)playButtonWithStates:(BOOL)state{ // if (state) { // [self.player pause]; // }else{ // [self.player play]; // } } - (void)vpc_sliderTouchBegin:(UISlider *)sender { if(self.isAuditionOver) { [self.player pause]; self.isPlay = NO; self.vpToolsView.hidden = !self.isStartPlay; [self updatePlayBtn]; [[BITNoticeView currentNotice] showErrorNotice:@"试听结束"]; return; } if (self.isPlay) { [self.player pause]; self.isPlay = NO; self.vpToolsView.hidden = !self.isStartPlay; }else{ self.vpToolsView.hidden = NO; if(!self.isStartBuffer) { [self startBuffer]; } else { [self.player play]; } self.isPlay = YES; } [self updatePlayBtn]; } #pragma mark - 播放进度 //- (void)updateProgress:(UISlider *)slider{ // [self.player seekToTime:CMTimeMakeWithSeconds(slider.value, self.player.currentItem.currentTime.timescale)]; //} - (void)vpc_sliderValueChanged:(UISlider *)sender { NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration) * _vpToolsView.progressSr.value; NSInteger currentMin = currentTime / 60; NSInteger currentSec = (NSInteger)currentTime % 60; _vpToolsView.lTime.text = [NSString stringWithFormat:@"%02ld:%02ld",currentMin,currentSec]; NSLog(@"time:%@, _vpToolsView.progressSr.value:%f", [NSString stringWithFormat:@"%02ld:%02ld",currentMin,currentSec], _vpToolsView.progressSr.value); // if(self.isAuditionOver || currentMin >= self.waitTime) // { // if(!self.isAuditionOver) // { // [self.player pause]; // self.isPlay = NO; // self.vpToolsView.hidden = !self.isStartPlay; // [self updatePlayBtn]; // [[BITNoticeView currentNotice] showErrorNotice:@"试听结束"]; // return; // } self.isAuditionOver = YES; // if (self.isPlay) { // [self.player pause]; // self.isPlay = NO; // self.vpToolsView.hidden = !self.isStartPlay; // }else{ // self.vpToolsView.hidden = NO; // if(!self.isStartBuffer) // { // [self startBuffer]; // } // else // { // [self.player play]; // } // self.isPlay = YES; // } // [self updatePlayBtn]; // } } - (void)vpc_sliderTouchEnd:(UISlider *)sender { if(self.isAuditionOver) { [self.player pause]; self.isPlay = NO; self.vpToolsView.hidden = !self.isStartPlay; [self updatePlayBtn]; [[BITNoticeView currentNotice] showErrorNotice:@"试听结束"]; return; } NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentItem.duration) * _vpToolsView.progressSr.value; NSInteger currentMin = currentTime / 60; NSInteger currentSec = (NSInteger)currentTime % 60; _vpToolsView.lTime.text = [NSString stringWithFormat:@"%02ld:%02ld",currentMin,currentSec]; NSLog(@"time:%@, _vpToolsView.progressSr.value:%f", [NSString stringWithFormat:@"%02ld:%02ld",currentMin,currentSec], _vpToolsView.progressSr.value); if(self.isAuditionOver || currentMin >= self.waitTime) { [self.player pause]; self.isPlay = NO; self.vpToolsView.hidden = !self.isStartPlay; [self updatePlayBtn]; [[BITNoticeView currentNotice] showErrorNotice:@"试听结束"]; return; // if(!self.isAuditionOver) // { // [self.player pause]; // self.isPlay = NO; // self.vpToolsView.hidden = !self.isStartPlay; // [self updatePlayBtn]; // [[BITNoticeView currentNotice] showErrorNotice:@"试听结束"]; // return; // } // self.isAuditionOver = YES; } else if(self.progress <= _vpToolsView.progressSr.value) { // if (self.isPlay) { // [self.player pause]; // self.isPlay = NO; // self.vpToolsView.hidden = !self.isStartPlay; // }else{ self.vpToolsView.hidden = NO; if(!self.isStartBuffer) { [self startBuffer]; } else { [self.player play]; } self.isPlay = YES; // } [self updatePlayBtn]; return; } self.isPlay = YES; NSTimeInterval slideTime = CMTimeGetSeconds(self.player.currentItem.duration) * _vpToolsView.progressSr.value; if (slideTime == CMTimeGetSeconds(self.player.currentItem.duration)) { slideTime -= 0.5; } [self.player seekToTime:CMTimeMakeWithSeconds(slideTime, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; // [self.player play]; self.vpToolsView.hidden = NO; if(!self.isStartBuffer) { [self startBuffer]; } else { [self.player play]; } self.isPlay = YES; [self updatePlayBtn]; } //#pragma mark - 网速监听器 //- (NetworkSpeedMonitor *)speedMonitor { // if (!_speedMonitor) { // _speedMonitor = [[NetworkSpeedMonitor alloc] init]; // } // return _speedMonitor; //} #pragma mark - 显示网速Label - (UILabel *)speedTextLabel { if (!_speedTextLabel) { _speedTextLabel = [UILabel new]; _speedTextLabel.frame = CGRectMake(0, 0, self.frame.size.width, 20); _speedTextLabel.textColor = [UIColor whiteColor]; _speedTextLabel.font = [UIFont systemFontOfSize:12.0]; _speedTextLabel.textAlignment = NSTextAlignmentCenter; _speedTextLabel.hidden = YES; _speedTextLabel.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5]; } return _speedTextLabel; } #pragma mark - AVPlayer -(AVPlayer *)player{ if (!_player) { _player = [[AVPlayer alloc] init]; __weak typeof(self) weakSelf = self; // 每秒回调一次 self.playbackObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:NULL usingBlock:^(CMTime time) { [weakSelf vpc_setTimeLabel]; NSTimeInterval totalTime = CMTimeGetSeconds(weakSelf.player.currentItem.duration);//总时长 NSTimeInterval currentTime = time.value / time.timescale;//当前时间进度 weakSelf.vpToolsView.progressSr.value = currentTime / totalTime; }]; } return _player; } #pragma mark - AVPlayerLayer -(AVPlayerLayer *)playerLayer{ if (!_playerLayer) { _playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player]; _playerLayer.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); } return _playerLayer; } #pragma mark ---------华丽的分割线--------- #pragma mark - lTime - (void)vpc_setTimeLabel { NSTimeInterval totalTime = CMTimeGetSeconds(self.player.currentItem.duration);//总时长 NSTimeInterval currentTime = CMTimeGetSeconds(self.player.currentTime);//当前时间进度 // 切换视频源时totalTime/currentTime的值会出现nan导致时间错乱 if (!(totalTime >= 0) || !(currentTime >= 0)) { totalTime = 0; currentTime = 0; } NSInteger totalMin = totalTime / 60; NSInteger totalSec = (NSInteger)totalTime % 60; NSString *totalTimeStr = [NSString stringWithFormat:@"%02ld:%02ld",totalMin,totalSec]; NSInteger currentMin = currentTime / 60; NSInteger currentSec = (NSInteger)currentTime % 60; NSString *currentTimeStr = [NSString stringWithFormat:@"%02ld:%02ld",currentMin,currentSec]; _vpToolsView.lTime.text = [NSString stringWithFormat:@"%@/%@",currentTimeStr,totalTimeStr]; NSLog(@"time:%@", [NSString stringWithFormat:@"%@/%@",currentTimeStr,totalTimeStr]); if(self.isAuditionOver || currentMin >= self.waitTime) { if(!self.isAuditionOver) { [[BITNoticeView currentNotice] showErrorNotice:@"试听结束"]; } self.isAuditionOver = YES; if (self.isPlay) { [self.player pause]; self.isPlay = NO; self.vpToolsView.hidden = !self.isStartPlay; }else{ self.vpToolsView.hidden = NO; if(!self.isStartBuffer) { [self startBuffer]; } else { [self.player play]; } self.isPlay = YES; } [self updatePlayBtn]; } } #pragma mark - 观察者 - (void)vpc_playerItemAddNotification { // 播放完成通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vpc_playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem]; } -(void)vpc_playbackFinished:(NSNotification *)noti{ [_vpToolsView.progressSr setValue:1.0]; [self.player pause]; } - (void)vpc_addObserverToPlayerItem:(AVPlayerItem *)playerItem { // 监听播放状态 [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil]; // 监听缓冲进度 [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil]; } - (void)vpc_playerItemRemoveNotification { [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem]; } - (void)vpc_playerItemRemoveObserver { [self.player.currentItem removeObserver:self forKeyPath:@"status"]; [self.player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { if ([keyPath isEqualToString:@"status"]) { AVPlayerStatus status= [[change objectForKey:@"new"] intValue]; if (status == AVPlayerStatusReadyToPlay) { self.isPlay = YES; [self vpc_setTimeLabel]; } } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) { NSArray *array = self.player.currentItem.loadedTimeRanges; CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次缓冲时间范围 NSTimeInterval startSeconds = CMTimeGetSeconds(timeRange.start);//本次缓冲起始时间 NSTimeInterval durationSeconds = CMTimeGetSeconds(timeRange.duration);//缓冲时间 NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度 float totalTime = CMTimeGetSeconds(self.player.currentItem.duration);//视频总长度 float progress = totalBuffer/totalTime;//缓冲进度 NSLog(@"progress = %lf, !self.buffered:%d, (progress == 1.0):%d",progress, !self.buffered, (progress == 1.0)); self.progress = progress; //如果缓冲完了,拖动进度条不需要重新显示缓冲条 if (!self.buffered) { if (fabs(1.0 - progress) <= 0.001) { self.buffered = YES; [self.vpToolsView.activityIndicator stopAnimating]; self.vpToolsView.activityIndicator.hidden = YES; } [self.vpToolsView.bufferPV setProgress:progress]; } NSLog(@"yon = %@",self.buffered ? @"yes" : @"no"); } } - (void)dealloc { // [self.speedMonitor stopNetworkSpeedMonitor]; // [[NSNotificationCenter defaultCenter] removeObserver:self name:NetworkDownloadSpeedNotificationKey object:nil]; // [self.player removeTimeObserver:self.playbackObserver]; [self vpc_playerItemRemoveObserver]; [self.player replaceCurrentItemWithPlayerItem:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } @end