iOS AVPlayer 使用详解

http://blog.csdn.net/yuhao111122/article/details/50589434

//
//  SMAVPlayerViewController.m
//  AVPlayerDemo
//
//  Created by Yx on 15/11/29.
//  Copyright © 2015年 WuhanBttenMobileTechnologyCo.,Ltd. All rights reserved.
//

#import "SMAVPlayerViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "SMSliderBar.h"
#import "MBMessageTip.h"
#import "VedioModel.h"
#import "VedioHistory.h"

#define ScreenHeight [[UIScreen mainScreen] bounds].size.height
#define ScreenWidth [[UIScreen mainScreen] bounds].size.width

@interface SMAVPlayerViewController ()<SMSliderDelegate>
@property (weak, nonatomic) IBOutlet UIView *viewHead;              //显示返回按钮View
@property (weak, nonatomic) IBOutlet UIView *viewLogin;             //加载view
@property (weak, nonatomic) IBOutlet UIImageView *imageViewLogin;   //加载image
@property (weak, nonatomic) IBOutlet UIView *viewAvPlayer;          //播放视图
@property (weak, nonatomic) IBOutlet SMSliderBar *slider;           //进度条
@property (weak, nonatomic) IBOutlet UIView *viewBottom;            //底部控制view
@property (weak, nonatomic) IBOutlet UIButton *btnPause;            //暂停播放按钮
@property (weak, nonatomic) IBOutlet UIButton *btnNetx;             //下一个按钮
@property (weak, nonatomic) IBOutlet UILabel *labelTimeNow;         //当前时间label
@property (weak, nonatomic) IBOutlet UILabel *labelTimeTotal;       //总时间label
@property (strong, nonatomic) AVPlayer *player;                     //播放器对象
@property (strong, nonatomic) id timeObserver;                      //视频播放时间观察者
@property (assign, nonatomic) float totalTime;                      //视频总时长
@property (assign, nonatomic) BOOL isHasMovie;                      //是否进行过移动
@property (assign, nonatomic) BOOL isBottomViewHide;                //底部的view是否隐藏
@property (assign, nonatomic) NSInteger subscript;                  //数组下标,记录当前播放视频
@property (assign, nonatomic) NSInteger currentTime;                //当前视频播放时间位置
@end

@implementation SMAVPlayerViewController
@synthesize subscript;

- (void)viewDidLoad {
    [super viewDidLoad];
    self.slider.type = SMSliderTypeHoz;
    self.slider.progressBgColor = [UIColor whiteColor];
    self.slider.isAllowDrag = YES;
    self.slider.delegate=self;
    subscript = 0;
    self.currentTime = 0;
    [self prohibitOperation];
    [self setMediaPlayer];
    [self addPlayerClick];//双击,单击事件
    [self addProgressObserver];//进度监听
    [self addNotification];//广播监听播放状态
    [self setupObservers];//监听应用状态
    self.viewLogin.layer.cornerRadius = 8;
    self.imageViewLogin.layer.masksToBounds = YES;
    self.imageViewLogin.layer.cornerRadius = 34/2;
    splashTimer = [NSTimer scheduledTimerWithTimeInterval:1  target:self selector:@selector(roteImageView) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:splashTimer forMode:NSRunLoopCommonModes];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [[UIApplication sharedApplication]setStatusBarHidden:YES];
    //接受远程控制事件
    [[UIApplication sharedApplication]beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [[UIApplication sharedApplication] setStatusBarHidden:NO];
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    [self resignFirstResponder];
    [splashTimer invalidate];
}

- (void)setMediaPlayer{
    //创建播放器层
    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    playerLayer.frame = CGRectMake(0, 0, ScreenHeight ,ScreenWidth );
    [self.viewAvPlayer.layer addSublayer:playerLayer];
    [self.player seekToTime:CMTimeMakeWithSeconds(self.startTime, 1000)];//设置播放位置1000 为帧率
    [_player play];
}


#pragma mark - set/get
- (AVPlayer *)player{
    if (!_player) {
        AVPlayerItem *playerItem = [self getPlayItem:subscript];
        [self addObserverToPlayerItem:playerItem];
        _player = [AVPlayer playerWithPlayerItem:playerItem];
    }
    return _player;
}

- (AVPlayerItem *)getPlayItem:(NSUInteger)videoIndex{
    /*播放本地视频
    NSString *urlStr=[[NSBundle mainBundle] pathForResource:@"testav.mp4" ofType:nil];
    NSURL *url=[NSURL fileURLWithPath:urlStr];
    AVPlayerItem *playerItem=[AVPlayerItem playerItemWithURL:url];
    return playerItem;*/
    //NSString *urlStr= @"http://7xoour.com2.z0.glb.qiniucdn.com/9605401000";
    _currentTime = 0;
    [self savePayHistory];
    VedioModel *vedioModel = _arrVedio[videoIndex];
    NSString *urlStr =[vedioModel.strURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    /*获取总帧数与帧率
     NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO]
     forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
     AVURLAsset *myAsset = [[AVURLAsset alloc] initWithURL:url options:opts];
     CMTimeValue  value = myAsset.duration.value;//总帧数
     CMTimeScale  timeScale =   myAsset.duration.timescale; //timescale为帧率  fps
     */
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:url];
    return playerItem;
}

#pragma mark - 通知
//给AVPlayerItem添加播放完成通知
- (void)addNotification{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
}

// 播放完成通知
- (void)playbackFinished:(NSNotification *)notification{
    NSLog(@"视频播放完成.");
    [self prohibitOperation];
    [self savePayHistory];
    [self nextClick:nil];
}

//注册通知
- (void)setupObservers
{
    NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
    [notification addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication]];
    [notification addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationWillResignActiveNotification object:[UIApplication sharedApplication]];
}

- (void)applicationDidBecomeActive:(NSNotification *)notification
{
    if (self.player.rate == 0) {
        [self.player play];
        [self.btnPause setTitle:@"暂停" forState:UIControlStateNormal];
        [self.btnPause setBackgroundImage:[UIImage imageNamed:@"play_stop.png"] forState:UIControlStateNormal];
    }
}

- (void)applicationDidEnterBackground:(NSNotification *)notification
{
    if (self.player.rate == 1){
        [self.player pause];
        [self.btnPause setTitle:@"播放" forState:UIControlStateNormal];
        [self.btnPause setBackgroundImage:[UIImage imageNamed:@"play_start.png"] forState:UIControlStateNormal];
    }
}

- (void)removeNotification{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark - KVO
- (void)addProgressObserver{
    AVPlayerItem *playerItem = self.player.currentItem;
    //这里设置每秒执行一次
    __weak __typeof(self) weakself = self;
    self.timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        float current = CMTimeGetSeconds(time);
        float total = CMTimeGetSeconds([playerItem duration]);
        NSLog(@"当前已经播放%f",current);
        weakself.currentTime = current;
        if (current) {
            [weakself setTime:current withTotal:total];
        }
    }];
}

/**
 *  给AVPlayerItem添加监控
 *  @param playerItem AVPlayerItem对象
 */
- (void)addObserverToPlayerItem:(AVPlayerItem *)playerItem{
    //监控状态属性,注意AVPlayer也有一个status属性,通过监控它的status也可以获得播放状态
    [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    //监控网络加载情况属性
    [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //监听播放的区域缓存是否为空
    [playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
    //缓存可以播放的时候调用
    [playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem{
    [playerItem removeObserver:self forKeyPath:@"status"];
    [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    [playerItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];
    [playerItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
}
/**
 *  通过KVO监控播放器状态
 *  @param keyPath 监控属性
 *  @param object  监视器
 *  @param change  状态改变
 *  @param context 上下文
 */
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    AVPlayerItem *playerItem = object;
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerStatus status= [[change objectForKey:@"new"] intValue];
        if(status == AVPlayerStatusReadyToPlay){
            self.totalTime = CMTimeGetSeconds(playerItem.duration);
            NSLog(@"开始播放,视频总长度:%.2f",CMTimeGetSeconds(playerItem.duration));
            [self.btnPause setTitle:@"暂停" forState:UIControlStateNormal];
             [self.btnPause setBackgroundImage:[UIImage imageNamed:@"play_stop.png"] forState:UIControlStateNormal];
            [_player play];
            [self.viewLogin setHidden:YES];
            [self clearProhibitOperation];
        }else if(status == AVPlayerStatusUnknown){
            NSLog(@"%@",@"AVPlayerStatusUnknown");
        }else if (status == AVPlayerStatusFailed){
            NSLog(@"%@",@"AVPlayerStatusFailed");
        }
    }else if([keyPath isEqualToString:@"loadedTimeRanges"]){
        NSArray *array = playerItem.loadedTimeRanges;
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次缓冲时间范围
        float startSeconds = CMTimeGetSeconds(timeRange.start);
        float durationSeconds = CMTimeGetSeconds(timeRange.duration);
        NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度
        if (self.currentTime < (startSeconds + durationSeconds + 8)) {
            self.viewLogin.hidden  = YES;
            if ([self.btnPause.titleLabel.text isEqualToString:@"暂停"]) {
                [_player play];
            }
        }else{
            self.viewLogin.hidden = NO;
        }
        self.slider.bufferValue = totalBuffer/self.totalTime;
        NSLog(@"缓冲:%.2f",totalBuffer);
    }else if ([keyPath isEqualToString:@"playbackBufferEmpty"]){
        NSLog(@"playbackBufferEmpty");
        [self.viewLogin setHidden:YES];
    }else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]){
        [self.viewLogin setHidden:NO];
        NSLog(@"playbackLikelyToKeepUp");
    }
}

#pragma mark - 手势监听
- (void)addPlayerClick{
    //单机手势监听
    UITapGestureRecognizer * tapGes=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(playerSingleClick:)];
    tapGes.numberOfTapsRequired=1;
    [self.viewAvPlayer addGestureRecognizer:tapGes];
    /*
    //双击手势监听
    UITapGestureRecognizer * tapGesDouble=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(playerDoubleTap:)];
    tapGesDouble.numberOfTapsRequired=2;
    [self.viewAvPlayer addGestureRecognizer:tapGesDouble];
    //双击手势确定监测失败才会触发单击手势的相应操作
    [tapGes requireGestureRecognizerToFail:tapGesDouble];*/
}

//显示或隐藏控制view
- (void)playerSingleClick:(UITapGestureRecognizer*)recognizer{
    if (self.isBottomViewHide) {
        //显示
        [UIView animateWithDuration:0.3 animations:^{
            [self.viewBottom setAlpha:1];
            [self.viewHead setAlpha:1];
        }];
    }else{
        //隐藏
        [UIView animateWithDuration:0.3 animations:^{
            [self.viewBottom setAlpha:0.0];
            [self.viewHead setAlpha:0.0];
        }];
    }
    self.isBottomViewHide=!self.isBottomViewHide;
}

//改变播放模式
- (void)playerDoubleTap:(UITapGestureRecognizer*)recognizer{
    AVPlayerLayer *playerLayer=[AVPlayerLayer playerLayerWithPlayer:self.player];
    if ([playerLayer.videoGravity isEqualToString:AVLayerVideoGravityResizeAspect]) {
        playerLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;
    }else if ([playerLayer.videoGravity isEqualToString:AVLayerVideoGravityResizeAspectFill]){
        playerLayer.videoGravity=AVLayerVideoGravityResize;
    }else if ([playerLayer.videoGravity isEqualToString:AVLayerVideoGravityResize]){
        playerLayer.videoGravity=AVLayerVideoGravityResizeAspect;
    }
}

#pragma mark - smSliderDelegate
- (void)SMSliderBar:(UIView *)slider valueChanged:(float)value{
    self.isHasMovie = YES;
}

- (void)SMSliderBarBeginTouch:(UIView *)slider{
    [_player pause];
    self.isHasMovie = NO;
}

- (void)SMSliderBarEndTouch:(UIView *)slider{
    if (self.isHasMovie) {
        [_player seekToTime:CMTimeMakeWithSeconds(self.totalTime*self.slider.value, _player.currentItem.duration.timescale)completionHandler:^(BOOL finished) {
            if (finished) {
                [_player play];
            }
        }];
    }
}


#pragma mark - IBAction

- (IBAction)pauseClick:(id)sender {
    if (_player.rate == 0) {
        [_player play];
        [self.btnPause setTitle:@"暂停" forState:UIControlStateNormal];
        [self.btnPause setBackgroundImage:[UIImage imageNamed:@"play_stop.png"] forState:UIControlStateNormal];
    }else{
        [_player pause];
        [self.btnPause setTitle:@"播放" forState:UIControlStateNormal];
        [self.btnPause setBackgroundImage:[UIImage imageNamed:@"play_start.png"] forState:UIControlStateNormal];
    }
}

- (IBAction)nextClick:(id)sender {
    ++subscript;
    self.labelTimeNow.text = @"00:00:00";
    self.labelTimeTotal.text = @"00:00:00";
    self.slider.value = 0;
    if (subscript < self.arrVedio.count) {
        [self.player seekToTime:CMTimeMakeWithSeconds(0, _player.currentItem.duration.timescale)];
        [self removeNotification];
        [self removeObserverFromPlayerItem:self.player.currentItem];
        [self.player removeTimeObserver:self.timeObserver];
         [_player replaceCurrentItemWithPlayerItem:[self getPlayItem:subscript]];
        [self addObserverToPlayerItem:self.player.currentItem];
        [self addNotification];
        [self addProgressObserver];
        if (self.player.rate == 0 ) {
            [self.player play];
        }
    }else{
        --subscript;
        /*
         [self.player.currentItem cancelPendingSeeks];
         [self.player.currentItem.asset cancelLoading];
         */
        [self.btnPause setTitle:@"播放" forState:UIControlStateNormal];
        [self.btnPause setBackgroundImage:[UIImage imageNamed:@"play_start.png"] forState:UIControlStateNormal];
        self.labelTimeTotal.text = @"00:00:00";
        self.labelTimeNow.text = @"00:00:00";
        [MBMessageTip messageWithTip:self.view withMessage:@"没有更多了" ];
    }
}

- (IBAction)backAction:(id)sender {
    [self savePayHistory];
    [self.player pause];
    [self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark - interface rotation

//横屏
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
    
    return YES;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeRight;
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    NSString *frameString = NSStringFromCGRect(self.viewAvPlayer.frame);
    
    NSLog(@"视频窗口的frame:%@",frameString);
}

#pragma mark - 私有方法
//设置播放时长
- (void)setTime:(float)current withTotal:(float)total{
    self.slider.value = current/total;
    self.labelTimeNow.text = [self displayTime:(int)current];
    self.labelTimeTotal.text = [self displayTime:(int)total];
}

- (NSString*)displayTime:(int)timeInterval{
    NSString * time = @"";
    int seconds = timeInterval % 60;
    int minutes = (timeInterval / 60) % 60;
    int hours = timeInterval / 3600;
    NSString * secondsStr=seconds<10?[NSString stringWithFormat:@"%@%d",@"0",seconds]:[NSString stringWithFormat:@"%d",seconds];
    NSString * minutesStr=minutes<10?[NSString stringWithFormat:@"%@%d",@"0",minutes]:[NSString stringWithFormat:@"%d",minutes];
    NSString * hoursStr=hours<10?[NSString stringWithFormat:@"%@%d",@"0",hours]:[NSString stringWithFormat:@"%d",hours];
    time = [NSString stringWithFormat:@"%@%@%@%@%@",hoursStr,@":",minutesStr,@":",secondsStr];
    return time;
}

//视频加载指示条
- (void)roteImageView{
    CABasicAnimation* rotationAnimation;
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 ];
    rotationAnimation.cumulative = YES;
    rotationAnimation.repeatCount = 1;
    rotationAnimation.duration = 1;
    [self.imageViewLogin.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
}

//保存播放历史
- (void)savePayHistory{
    NSDate *currentDate = [NSDate date];//获取当前时间,日期
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"YYYY-MM-dd"];
    NSString *dateString = [dateFormatter stringFromDate:currentDate];
    VedioModel *vedioModel = _arrVedio[subscript];
    VedioHistory *vedioHistory = [[VedioHistory alloc] init];
    [vedioHistory insertTitle:vedioModel.strTitle createTime:dateString userId:[NSNumber numberWithInt:[vedioModel.strUserID intValue]] videoType:[NSNumber numberWithInt:vedioModel.vedioType]  playTime:[NSNumber numberWithInteger:self.currentTime] videoUrl:vedioModel.strURL picUrl:vedioModel.strImage];
}

//视频未播放时禁止点击
- (void)prohibitOperation{
    self.btnNetx.enabled = NO;
    self.btnPause.enabled = NO;
    self.slider.isAllowDrag = NO;
}

//视频播放时取消禁止点击
- (void)clearProhibitOperation{
    self.btnNetx.enabled = YES;
    self.btnPause.enabled = YES;
    self.slider.isAllowDrag = YES;
}

- (void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [self removeObserverFromPlayerItem:self.player.currentItem];
    [self.player removeTimeObserver:self.timeObserver];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end


  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值