使用AVPlayer自定义播放器

使用AVPlayer前需要‘“#import <AVFoundation/AVFoundation.h>”,要通过AVPlayer来播放视频需要用到以下3项:

@property(nonatomic,strong)AVPlayer                        * player;             //播放属性
@property(nonatomic,strong)AVPlayerItem                    * playerItem;         //播放属性
@property(nonatomic,strong)AVPlayerLayer                   * playerLayer;        //播放属性

在开发中,单纯使用AVPlayer类是无法显示视频的,要将视频层添加至AVPlayerLayer中,这样才能将视频显示出来

#ragma mark  - 懒加载控件 -
- (AVPlayer *)player{
    if (!_player) {
        _player = [[AVPlayer alloc] init];
    }
    return _player;
}
- (AVPlayerLayer *)playerLayer{
    if (!_playerLayer) {
        _playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
        _playerLayer.frame = self.bounds;
        _playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    }
    return _playerLayer;
}

把视频播放器的Layer加到视图Layer上,播放视频

 [self.layer addSublayer:self.playerLayer];
 self.playerItem = [[AVPlayerItem alloc] initWithURL:playerURL];
 [_player replaceCurrentItemWithPlayerItem:_playerItem];
 [_player play];

我的自定义播放器

MoivePlayer.h
#import <UIKit/UIKit.h>
#import "PlayerCommandView.h"                         //控制界面
@interface MoivePlayer : UIView
@property(nonatomic,strong)PlayerCommandView          * CommandView;       //控制界面
@property(nonatomic,strong)NSURL                      * playerURL;         //视频地址
@property(nonatomic,strong)UIViewController           * superVc;          //播放器主页面
/*******************************************************************/
@end
MoivePlayer.m
#import "MoivePlayer.h"
#import <AVFoundation/AVFoundation.h>
@interface MoivePlayer()
@property(nonatomic,strong)AVPlayer                        * player;             //播放属性
@property(nonatomic,strong)AVPlayerItem                    * playerItem;         //播放属性
@property(nonatomic,strong)AVPlayerLayer                   * playerLayer;        //播放属性
@property(nonatomic,assign)BOOL                              isFullScreen;       //是否是全屏
@end
@implementation MoivePlayer

- (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        [self initStep];
    }
    return self;
}
#pragma mark  - 懒加载控件 -
- (AVPlayer *)player{
    if (!_player) {
        _player = [[AVPlayer alloc] init];
    }
    return _player;
}

- (AVPlayerLayer *)playerLayer{
    if (!_playerLayer) {
        _playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
        _playerLayer.frame = self.bounds;
        _playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    }
    return _playerLayer;
}
- (PlayerCommandView *)CommandView{
    if (!_CommandView) {
        _CommandView = [[PlayerCommandView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
        _CommandView.backgroundColor = [UIColor clearColor];
    }
    return _CommandView;
}

- (void)setPlayerURL:(NSURL *)playerURL{
    self.playerItem = [[AVPlayerItem alloc] initWithURL:playerURL];
    [_player replaceCurrentItemWithPlayerItem:_playerItem];
    [self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];// 监听loadedTimeRanges属性
}

#pragma mark - 初始化 -
- (void)initStep{
    [self.layer addSublayer:self.playerLayer];
    [self addSubview:self.CommandView];
    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(stup) userInfo:nil repeats:YES];
    /*------------------------------*/
    [self play];
    [self progressSlider];
    [self fullScreen];
    _isFullScreen = NO;
    /*------------------------------*/
    [self gestureAction];
}
#pragma mark  - Bottomview上的按钮响应方法 -
- (void)play{
    [_player play];
    __weak typeof(self)weakself = self;
    _CommandView.playActionBlock = ^ (int n){
        if (n==1) {
            [weakself.player pause];
        }
        if (n==0) {
            [weakself.player play];
        }
    };
}
- (void)progressSlider{
      __weak typeof(self)weakself = self;
    _CommandView.slideActionBlock = ^(int n){
        if (n==100) {
            if (_player.status == AVPlayerStatusReadyToPlay) {
                CGFloat total = _playerItem.duration.value/_playerItem.duration.timescale;
                NSInteger dragedSeconds = floorf(total * _CommandView.slider.value);
                CMTime dragedCMTime = CMTimeMake(dragedSeconds, 1);
                [weakself.player pause];
                [weakself.player seekToTime:dragedCMTime completionHandler:^(BOOL finished) {
                     [weakself.player play]; 
                }];
            }
        }
    };
}

- (void)fullScreen{
    
    __weak typeof(self)weakself = self;
    
    _CommandView.fullActionBlock = ^(int n){
    
        if (n==200) {
        
            if (weakself.isFullScreen) {
                
                [weakself removeFromSuperview];
            
                [weakself.superVc.view addSubview:weakself];
                
                [UIView animateWithDuration:0.5 animations:^{
                    
                    weakself.transform = CGAffineTransformMakeRotation(2*M_PI);
                    
                    weakself.frame = CGRectMake(0, 0, 375, 240);
                    weakself.playerLayer.frame = CGRectMake(0, 0, 375, 240);
                    weakself.CommandView.frame = CGRectMake(0, 0, 375, 240);
                    
                } completion:^(BOOL finished) {
                    
                }];
    
            }else{
                
                [weakself removeFromSuperview];
                
                [[UIApplication sharedApplication].keyWindow addSubview:weakself];
                
                [UIView animateWithDuration:0.5 animations:^{
                    
                    CGRect MovieRect = weakself.frame;
                    
                    MovieRect.size.width = [UIScreen mainScreen].bounds.size.height;
                    MovieRect.size.height = [UIScreen mainScreen].bounds.size.width;
                    weakself.frame = MovieRect;
                    weakself.playerLayer.frame = MovieRect;
                    weakself.CommandView.frame = MovieRect;
                    weakself.center = [UIApplication sharedApplication].keyWindow.center;

                    weakself.transform = CGAffineTransformMakeRotation(M_PI_2);
                    
                } completion:^(BOOL finished) {
                }];

            }
            
            _isFullScreen = !_isFullScreen;
        }
    };
}
#pragma mark - 手势相关 -

- (void)gestureAction{

    __weak typeof(self)weakself = self;
    
    _CommandView.gestureActionBlock = ^(int n){
    
        if (n  == 1) {
            
            if (!weakself.CommandView.bottomView.hidden) {
                
                weakself.CommandView.bottomView.hidden = !weakself.CommandView.bottomView.hidden;
                
                weakself.CommandView.topView.hidden   = !weakself.CommandView.topView.hidden ;
                
            }else{
        
                weakself.CommandView.bottomView.hidden = !weakself.CommandView.bottomView.hidden;
                
                weakself.CommandView.topView.hidden   = !weakself.CommandView.topView.hidden ;
            }
        }
        
        if (n==2) {
            
            if (weakself.player.status == AVPlayerStatusReadyToPlay) {
                
                [weakself.player pause];
                
                weakself.CommandView.playBtn.selected = YES;
                
            }else {
                
                [weakself.player play];
                
                weakself.CommandView.playBtn.selected = NO;
            }
        }
    };
}

#pragma mark - 计时器事件 -

- (void)stup
{
    if (_playerItem.duration.timescale !=0) {
        
        _CommandView.slider.maximumValue = 1;
        
         _CommandView.slider.value = CMTimeGetSeconds([_playerItem currentTime])/(_playerItem.duration.value/_playerItem.duration.timescale);
        
        NSInteger proMin = CMTimeGetSeconds([_player currentTime])/60;                                 //当前秒
        
        NSInteger proSec = (NSInteger)CMTimeGetSeconds([_player currentTime]) % 60;                    //当前分钟
        
        NSInteger durMin = (NSInteger)_playerItem.duration.value / _playerItem.duration.timescale / 60;//总秒
        
        NSInteger durSec = (NSInteger)_playerItem.duration.value / _playerItem.duration.timescale % 60;//总分钟
        
        _CommandView.currentTimeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld / %02ld:%02ld", proMin, proSec, durMin, durSec];
    }
    
    if (_player.status == AVPlayerStatusReadyToPlay) {
        
        
       // [_activity stopAnimating];
        
    }else{
        
        //[_activity startAnimating];
        
    }
}

#pragma mark - KVO键值观察 -

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    AVPlayerItem *playerItem = (AVPlayerItem *)object;
    
    if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        
        NSTimeInterval timeInterval = [self availableDuration];                   // 计算缓冲进度
        
        CMTime duration = self.playerItem.duration;
        
        CGFloat totalDuration = CMTimeGetSeconds(duration);
        
        [_CommandView.progress setProgress:timeInterval / totalDuration animated:NO];
    }
    
    if ([playerItem status] == AVPlayerStatusReadyToPlay) {
        
       // _duration = playerItem.duration.value / playerItem.duration.timescale;  //视频总时间
    }
}

- (NSTimeInterval)availableDuration {
    
    NSArray *loadedTimeRanges = [[_player currentItem] loadedTimeRanges];
    
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];      // 获取缓冲区域
    
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    
    NSTimeInterval result = startSeconds + durationSeconds;                       // 计算缓冲总进度
    
    return result;
}

@end

下方播放器控制类

PlayerCommandView.h
#import <UIKit/UIKit.h>
typedef void(^playActionBlock)(int n);
typedef void(^slideActionBlock)(int n);
typedef void(^fullActionBlock)(int n);
typedef void(^gestureActionBlock)(int  n);

typedef void(^panActionBlock)(int n);

@interface PlayerCommandView : UIView

@property(nonatomic,copy)playActionBlock    playActionBlock;
@property(nonatomic,copy)slideActionBlock   slideActionBlock;
@property(nonatomic,copy)fullActionBlock    fullActionBlock;
@property(nonatomic,copy)gestureActionBlock gestureActionBlock;
@property(nonatomic,copy)panActionBlock     panActionBlock;

@property(nonatomic,strong) UIView                  * topView;               //顶部视图
@property(nonatomic,strong) UIView                  * bottomView;            //底部视图

@property(nonatomic,strong) UIProgressView      * progress;                 // 缓冲条
@property(nonatomic,strong) UISlider            * slider;                   // 进度条
@property(nonatomic,strong) UILabel             * currentTimeLabel;         // 当前播放时间
@property(nonatomic,strong) UIButton            * playBtn;                  //播放、暂停按钮
@property(nonatomic,strong) UIButton            * screenBtn;                //全屏按钮

@property(nonatomic,strong) UITapGestureRecognizer  * tapGesture;           //单击手势
@property(nonatomic,strong) UITapGestureRecognizer  * doubleTapGesture;     //双击手势
@property(nonatomic,strong) UIPanGestureRecognizer  * panGesture;           //拖动手势

@end
PlayerCommandView.m
#import "PlayerCommandView.h"

@interface PlayerCommandView()
{
    BOOL          _hasMoved;             //手势是否移动过
    BOOL          _isTouchDirection;     //是否判断出手势方向
    CGPoint       _touchBeginPoint;      //触摸开始的点
}

@end

@implementation PlayerCommandView

- (instancetype)initWithFrame:(CGRect)frame{

    if (self = [super initWithFrame:frame]) {
        
        [self initStep];
    }

    return self;
}

- (void)layoutSubviews{
    
    _topView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height * 0.1);
    
    _bottomView.frame = CGRectMake(0, self.frame.size.height - 40, self.frame.size.width, 40);
    
    _playBtn.frame = CGRectMake(5, 5, 30, 30);
    
    _progress.frame = CGRectMake(self.frame.size.width * 0.15, 20, self.frame.size.width * 0.5, 15);
    
    _slider.frame = CGRectMake(self.frame.size.width * 0.15, 13, self.frame.size.width * 0.5, 15);
    
    _currentTimeLabel.frame = CGRectMake(self.frame.size.width * 0.65 + 5 , 10, self.frame.size.width * 0.3, 20);
    _screenBtn.frame = CGRectMake(self.frame.size.width  - 30, 5, 30, 30);
}

#pragma mark - 懒加载 -

- (UIView *)topView{
    
    if (!_topView) {
        
        _topView = [[UIView alloc] init];
        
        _topView.backgroundColor = [UIColor brownColor];
    }
    
    return _topView;
}

- (UIView *)bottomView{

    if (!_bottomView) {
        
        _bottomView = [[UIView alloc] init];
        
        _bottomView.backgroundColor = [UIColor brownColor];
    }
    
    return _bottomView;
}

- (UIButton *)playBtn{

    if (!_playBtn) {
        
        _playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        
        [_playBtn setImage:[UIImage imageNamed:@"pauseBtn"] forState:UIControlStateNormal];
        
        [_playBtn setImage:[UIImage imageNamed:@"playBtn"] forState:UIControlStateSelected];
        
        [_playBtn addTarget:self action:@selector(playBtnAction:) forControlEvents:UIControlEventTouchUpInside];
    }
    
    return _playBtn;
}

- (UIProgressView *)progress{

    if (!_progress) {
        
        _progress = [[UIProgressView alloc] init];
    }
    
    return _progress;
}

- (UISlider *)slider{

    if (!_slider) {
        
        _slider = [[UISlider alloc] init];
        
        [_slider setThumbImage:[UIImage imageNamed:@"iconfont-yuan.png"] forState:UIControlStateNormal];
        
        [_slider addTarget:self action:@selector(progressSlider:) forControlEvents:UIControlEventValueChanged];
        
        _slider.minimumTrackTintColor = [UIColor colorWithRed:30 / 255.0 green:80 / 255.0 blue:100 / 255.0 alpha:1];
        
        //生成透明的图形
        
        UIGraphicsBeginImageContextWithOptions((CGSize){ 1, 1 }, NO, 0.0f);
        
        UIImage * transparentImage = UIGraphicsGetImageFromCurrentImageContext();
        
        UIGraphicsEndImageContext();
        
        [self.slider setMinimumTrackImage:transparentImage forState:UIControlStateNormal];
        
        [self.slider setMaximumTrackImage:transparentImage forState:UIControlStateNormal];
    }
    
    return _slider;
}

- (UILabel *)currentTimeLabel{

    if (!_currentTimeLabel) {
        
        _currentTimeLabel = [[UILabel alloc] init];
        
        _currentTimeLabel.textColor = [UIColor whiteColor];
        
        _currentTimeLabel.font = [UIFont systemFontOfSize:12];
        
        _currentTimeLabel.text = @"00:00/00:00";
    }
    
    return _currentTimeLabel;
}

- (UIButton *)screenBtn{
    
    if (!_screenBtn) {
        
        _screenBtn = [UIButton  buttonWithType:UIButtonTypeCustom];
        
        [_screenBtn addTarget:self action:@selector(screenBtnAction:) forControlEvents:UIControlEventTouchUpInside];
        
        [_screenBtn setImage:[UIImage imageNamed:@"icon_full"] forState:UIControlStateNormal];
    }

    return _screenBtn;
}

- (UITapGestureRecognizer *)tapGesture{
    
    if (!_tapGesture) {
        
        _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
        
        _tapGesture.numberOfTapsRequired = 1;
        
        _tapGesture.numberOfTouchesRequired = 1;
    }
    
    return _tapGesture;
}

- (UIPanGestureRecognizer *)panGesture{

    if (!_panGesture) {
        
        _panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
        
        [_panGesture setMaximumNumberOfTouches:1];
        
        [_panGesture setMinimumNumberOfTouches:1];
    }
    
    return _panGesture;
}

- (UITapGestureRecognizer *)doubleTapGesture{

    if (!_doubleTapGesture) {
        
        _doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
        
        [_doubleTapGesture setNumberOfTapsRequired:2];
    }
    
    return _doubleTapGesture;
}

#pragma mark  - 初始化 -

- (void)initStep
{
    [self addSubview:self.topView];
    
    [self addSubview:self.bottomView];
    
    [_bottomView addSubview:self.playBtn];
    
    [_bottomView addSubview:self.progress];
    
    [_bottomView addSubview:self.slider];
    
    [_bottomView addSubview:self.currentTimeLabel];
    
    [_bottomView addSubview:self.screenBtn];
    
    [self addGestureRecognizer:self.tapGesture];
    
    [self addGestureRecognizer:self.doubleTapGesture];
    
    [self addGestureRecognizer:self.panGesture];
}

#pragma mark - 按钮的点击事件 -

- (void)playBtnAction:(UIButton *)button
{
    if (button.selected) {
        
        if (_playActionBlock) {
            
            _playActionBlock(0);
        }
        
    }else{
    
        if (_playActionBlock) {
            
            _playActionBlock(1);
        }
    }
    
    button.selected = !button.selected;
}

- (void)progressSlider:(UISlider *)slider{
    
    if (_slideActionBlock) {
        
        _slideActionBlock(100);
    }
}

- (void)screenBtnAction:(UIButton *)button{

    if (_fullActionBlock) {
        
        _fullActionBlock(200);
    }
}

#pragma mark - 手势相关 -

- (void)tapAction:(UITapGestureRecognizer *)gesture
{
    if (gesture.numberOfTapsRequired == 1) {
        
        if (_gestureActionBlock) {
            
            _gestureActionBlock(1);
        }
    }

    if (gesture.numberOfTapsRequired == 2 ) {
        
        if (_gestureActionBlock) {
            
            _gestureActionBlock(2);
        }
    }
}

- (void)panAction:(UIPanGestureRecognizer *)gesture
{
    CGPoint touchPoint = [gesture locationInView:self];
    
    NSLog(@"%f,%f",touchPoint.x,touchPoint.y);
}

@end

使用

    MoivePlayer * Player = [[MoivePlayer alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 240)];
    Player.playerURL = [NSURL URLWithString:@"http://7xnujb.com2.z0.glb.qiniucdn.com/zczs02%2Fsj2-001.mp4"];
    Player.superVc = self;
    [self.view addSubview:Player];
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容