本来有AVPlayer和MPPlayerviewcontrller的。后者现在被弃用了,所以就用AVplayerviewcontrller原生的开发
#import
@interface ViewController : UIViewController
@property(nonatomic,retain)AVPlayerViewController * avc;
@property(nonatomic,retain)avplayerSetView * setview;
@interface ViewController ()<AVPlayerViewControllerDelegate,AVPictureInPictureControllerDelegate>
{
AVPlayer * player;
CGFloat _viewLength;
float currenttime;
BOOL isFullscreen;
NSURL * videlurl;
}
@property(nonatomic,retain)AVPlayerItem * playItem;
@end
首先。上面有一个setview,这个是我用来放置AVplayerviewcontrller的view,相当于替代他的AVplaylayer,这个setview里面用懒加载写了一个UIprogressview和UIslider,两个label和一个uibutton,
![左边的button是暂停按钮,靠右的是progress和UIslider用来显示网络加载视频的缓冲进度和滑动条,两个label用来显示当前播放时间和总时长](http://img.blog.csdn.net/20160808174043119)
首先,要定义好avplayer这个播放器的显示范围,他是由AVplayerviewcontrller实例化生成的,那么对应的他就有自己的view,我们让这个view=自己写的view就可以了,还有当屏幕旋转时要设置好setview的各个控件的方向大小,别弄错了就行,
这里关于setview的控件初始化懒加载部分我就不写了,直接来主要的
-(void)initSomething{
[self.avc.view setFrame:CGRectMake(0, 0, self.view.bounds.size.width, 300)];
[self.setview setFrame:self.avc.view.frame];
[self.avc.view addSubview:self.setview];
[self.setview.progress addTarget:self action:@selector(changeprogress:) forControlEvents:UIControlEventValueChanged];
[self.setview.pause addTarget:self action:@selector(pausevideo:) forControlEvents:UIControlEventTouchUpInside];
videlurl=[NSURL URLWithString:@"http://ys-l.ys168.com/566310237/ULVJgkn3K3N1K75HGO5L/music.mp4"];
NSString * url1=[[NSBundle mainBundle]pathForResource:@"duanpian" ofType:@"mp4"];
//确定视频资源 一个视频用一个item
self.playItem=[AVPlayerItem playerItemWithURL:[NSURL videlurl]];
//确定视频视频框架
player = [AVPlayer playerWithPlayerItem: self.playItem];
[self addObserver];
self.avc.player=player;
// 隐藏系统自带的进度条播放界面
self.avc.showsPlaybackControls = NO;
[self.view addSubview:self.avc.view];
player.externalPlaybackVideoGravity=AVLayerVideoGravityResizeAspectFill;
}
-(void)addObserver{
//获取视频信息,要用item添加kvo,编程的时候最好使用item 的status,会准确点。
[ self.playItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
[self.playItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)removeVideokvo{
[self.playItem removeObserver:self forKeyPath:@"status"];
[self.playItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"status"]) {
switch (self.playItem.status) {
case AVPlayerItemStatusReadyToPlay:
{
//视频总长度
_viewLength=self.playItem.duration.value*1/ self.playItem.duration.timescale;
// 设置播放进度UI
[self showPlayeritemInformation:self.playItem];
[player play];
}
break;
case AVPlayerItemStatusFailed:
break;
default:
break;
}
}
if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
if (videlurl) {
NSTimeInterval timeInterval = [self availableDuration];// 计算缓冲进度
NSLog(@"Time Interval:%f",timeInterval);
CMTime duration = self.playItem.duration;
CGFloat totalDuration = CMTimeGetSeconds(duration);
self.setview.schedule.trackTintColor=[UIColor grayColor];
self.setview.schedule.progress=timeInterval/totalDuration;
}
}
}
-(void)showPlayeritemInformation:(AVPlayerItem *)item{
__weak typeof(self) weakSelf = self;
//设置检查频率,1s更新一次这个block
CMTime time = CMTimeMake(1.0, 1.0);
[self.avc.player addPeriodicTimeObserverForInterval:time queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
//当前播放时间
currenttime =item.currentTime.value/item.currentTime.timescale;
weakSelf.setview.progress.value=currenttime/_viewLength;
//显示时间的俩label
weakSelf.setview.goForward.text=[NSString stringWithFormat:@"%@",[weakSelf getVideoLengthFromTimeLength:item.duration.value*1/ item.duration.timescale]];
weakSelf.setview.backForward.text=[NSString stringWithFormat:@"%@",[weakSelf getStringFromCMTime:item.currentTime.value/item.currentTime.timescale]];
}];
}
-(void)changeprogress:(UISlider *)sender{
CGFloat currt= sender.value * _viewLength;
[self.avc.player seekToTime:CMTimeMake(currt, 1)];
}
//点击按钮暂停播放,再点击继续播放
bool ispause=NO;
-(void)pausevideo:(UIButton *)sender{
ispause=!ispause;
if (ispause) {
[self.avc.player pause];
}else{
[self.avc.player play];
}
}
#pragma mark 工具方法
//计算缓冲进度
- (NSTimeInterval)availableDuration {
NSArray *loadedTimeRanges = [[self.avc.player currentItem] loadedTimeRanges];
CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域
float startSeconds = CMTimeGetSeconds(timeRange.start);
float durationSeconds = CMTimeGetSeconds(timeRange.duration);
NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度
return result;
}
//将当前进度转换成分秒
- (NSString *)getStringFromCMTime:(CGFloat)time
{
// float currentTimeValue = (CGFloat)time.value/time.timescale;//得到当前的播放时
NSDate * currentDate = [NSDate dateWithTimeIntervalSince1970:time];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSInteger unitFlags = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond ;
NSDateComponents *components = [calendar components:unitFlags fromDate:currentDate];
if (time >= 3600 )
{
return [NSString stringWithFormat:@"%02ld:%02ld:%02ld",components.hour,components.minute,components.second];
}
else
{
return [NSString stringWithFormat:@"%02ld:%02ld",components.minute,components.second];
}}
//将总时长转换成时分秒
- (NSString *)getVideoLengthFromTimeLength:(float)timeLength
{
NSDate * date = [NSDate dateWithTimeIntervalSince1970:timeLength];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSInteger unitFlags = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond ;
NSDateComponents *components = [calendar components:unitFlags fromDate:date];
if (timeLength >= 3600 )
{
return [NSString stringWithFormat:@"%02ld时:%02ld分:%02ld秒",components.hour,components.minute,components.second];
}
else
{
return [NSString stringWithFormat:@"%02ld分:%02ld秒",components.minute,components.second];
}
}
//判断设备是否支持旋转
-(void)lisenDeviceRotated{
[[UIDevice currentDevice]beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onDeviceOrientationChange) name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (void)onDeviceOrientationChange {
UIDeviceOrientation oriention = [UIDevice currentDevice].orientation;
UIInterfaceOrientation interfaceOriention = (UIInterfaceOrientation)oriention;
switch (interfaceOriention) {
case UIInterfaceOrientationUnknown:
NSLog(@"位置方向");
break;
case UIInterfaceOrientationPortrait:
NSLog(@"第0个旋转方向---电池栏在上");
[self backOrientationPortrait];
break;
case UIInterfaceOrientationPortraitUpsideDown:
NSLog(@"第3个旋转方向---电池栏在下");
[self backOrientationPortrait];
break;
case UIInterfaceOrientationLandscapeLeft:
[self setDeviceOrientationLandscapeLeft];
NSLog(@"第2个旋转方向---电池栏在右");
break;
case UIInterfaceOrientationLandscapeRight:
[self setDeviceOrientationLandscapeRight];
NSLog(@"第1个旋转方向---电池栏在左");
break;
default:
break;
}
}
//隐藏navigation tabbar 电池栏
-(BOOL)prefersStatusBarHidden{
return YES;
}
//返回小屏幕
-(void)backOrientationPortrait{
[UIView animateWithDuration:.5f animations:^{
[self.avc.view setFrame:CGRectMake(0, 0, self.view.bounds.size.width, 300)];
[self.setview setFrame:self.avc.view.frame];
[self.avc.view setTransform:CGAffineTransformIdentity];
}completion:^(BOOL finished) {
}];
}
-(void)setDeviceOrientationLandscapeRight{
//全屏(横屏frame计算)
CGFloat height = [[UIScreen mainScreen] bounds].size.width;
CGFloat width = [[UIScreen mainScreen] bounds].size.height;
CGRect frame = CGRectMake(0, 0, height, width);
[UIView animateWithDuration:0.3f animations:^{
self.avc.view.frame = frame;
self.setview.frame=frame;
// [self.avc.view setTransform:CGAffineTransformMakeRotation(M_PI)];
} completion:^(BOOL finished) {
}];
}
- (void)setDeviceOrientationLandscapeLeft {
//全屏(横屏frame计算)
CGFloat height = [[UIScreen mainScreen] bounds].size.width;
CGFloat width = [[UIScreen mainScreen] bounds].size.height;
CGRect frame = CGRectMake(0, 0, height, width);
[UIView animateWithDuration:0.3f animations:^{
self.avc.view.frame = frame;
self.setview.frame=frame;
// [self.avc.view setTransform:CGAffineTransformMakeRotation(-M_PI)];
} completion:^(BOOL finished) {
}];
}
到这里 就可以播放了,没怎么太完善功能,只是初学用的,其中[self.avc.player addPeriodicTimeObserverForInterval:time queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
//当前播放时间
currenttime =item.currentTime.value/item.currentTime.timescale;
weakSelf.setview.progress.value=currenttime/_viewLength;
//显示时间的俩label
weakSelf.setview.goForward.text=[NSString stringWithFormat:@"%@",[weakSelf getVideoLengthFromTimeLength:item.duration.value*1/ item.duration.timescale]];
weakSelf.setview.backForward.text=[NSString stringWithFormat:@"%@",[weakSelf getStringFromCMTime:item.currentTime.value/item.currentTime.timescale]];
}];
这个点我觉得是重要的,cmtimemake(1,1)指的是1/1这个时间走一次block。