ios开发-搭建自定义的视频播放器

本来有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(11)指的是1/1这个时间走一次block。

ios开发-搭建自定义的视频播放器_第1张图片

你可能感兴趣的:(控件,ios,界面,ios开发,视频)