iOS AVPlayer 使用详解

来源:互联网 发布:凡科微传单软件 编辑:程序博客网 时间:2024/05/04 04:51

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 0
原创粉丝点击