2015-07-31 11:33:37 yangxinca 阅读数 1340

目录

  1. 导入框架
    导入

NSString *str = @"http://vmovier.qiniudn.com/559b918dbf717.mp4";
NSString *urlStr =[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];//链接接口中的汉字会导致请求失败
NSURL *url=[NSURL URLWithString:urlStr];
AVPlayerItem *playerItem=[AVPlayerItem playerItemWithURL:url];//主要创建方法,创建媒体资源管理对象
AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];//根据媒体资源管理对象创建AVPlayer对象
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];//AVPlayer要显示视频,必须创建一个播放器层AVPlayerLayer用于展示

(2)视频的播放、暂停功能。
这也是最基本的功能,AVPlayer对应着两个方法play、pause来实现。
[player play];//播放
[player pause];//暂停
通常我们会需要得知当前的播放状态来进行主动地改变播放状态,问题的关键是如何判断当前视频是否在播放。很不幸的是AVPlayer没有这样的状态属性,但是很幸运的是我们可以通过判断播放器的播放速度来获得播放状态。AVPlayer类包含一个极其重要的属性:

**@property (nonatomic) float rate;**

其代码注释为:/* indicates the current rate of playback; 0.0 means “stopped”, 1.0 means “play at the natural rate of the current item” */
解释为:”表示当前的播放速度;0表示“停止”,1表示“在当前的PlayerItem下以正常速率播放”。
通过监控这个属性,可以间接获取当前播放状态,获取这个属性值对于视频播放器的功能完善具有不可代替的作用。

(3)播放进度及缓存进度
MPMoviePlayerController拥有自己的进度条,AVPlayer想要要展示播放进度就没有那么简单了。视频播放器通常是使用通知来获得播放器的当前状态,媒体加载状态等,但是无论是AVPlayer还是AVPlayerItem(AVPlayer有一个属性currentItem是AVPlayerItem类型,表示当前播放的视频对象)都无法获得这些信息。当然AVPlayerItem是有通知的,但是对于获得播放状态和加载状态有用的通知只有一个:播放完成通知AVPlayerItemDidPlayToEndTimeNotification。
在播放视频时,特别是播放网络视频往往需要知道视频加载情况、缓冲情况、播放情况,这些信息可以通过KVO监控AVPlayerItem的status、loadedTimeRanges属性来获得。当AVPlayerItem的status属性为AVPlayerStatusReadyToPlay是说明正在播放,只有处于这个状态时才能获得视频时长等信息;当loadedTimeRanges的改变时(每缓冲一部分数据就会更新此属性)可以获得本次缓冲加载的视频范围(包含起始时间、本次加载时长),这样一来就可以实时获得缓冲情况。然后就是依靠AVPlayer的

- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block

方法获得播放进度,这个方法会在设定的时间间隔内定时更新播放进度,通过time参数通知客户端。有了这些视频信息,播放进度就不成问题了,事实上通过这些信息就算是平时看到的其他播放器的缓冲进度显示以及拖动播放的功能也可以顺利的实现。

  1. 具体实现
    具体实现的效果图:
    exp_1
    exp_2

具体代码:
(注:自知自己水平有限,代码优化处理方面做的也不是太好,但是幸好实现效果勉强可以,请各位读者勿喷就好)
(1)ViewController里的调用情况:

ViewController.h文件

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import "AVPlayer_S.h"

@interface ViewController : UIViewController
**//AVPlayer_S 为我自己创建的类,继承于UIView,用于承载AVPlayer**
@property (nonatomic, retain) AVPlayer_S *myVideoPlayer;
@end

ViewController.m文件

#import "ViewController.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];    
    self.view.backgroundColor = [UIColor whiteColor];

    //AVPlayer_S 为我自己创建的类,继承于UIView,用于承载AVPlayer,此处用了固定的frame,自己在使用时可以根据需要设定具体的frame
    self.myVideoPlayer = [[AVPlayer_S alloc] initWithFrame:CGRectMake(20, 60, 335, 280) videoURL:@"http://vmovier.qiniudn.com/559b918dbf717.mp4"];

    [self.view addSubview:self.myVideoPlayer];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end

AVPlayer_S.h文件

 #import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import "MBProgressHUD.h"//为视频添加缓冲时候的菊花旋转,此第三方可以再Github上下载,直接搜索MBProgressHUD即可下载使用,假如你不想用可以把与之相关的全部删除
//附加MBProgressHUD的下载地址:https://github.com/jdg/MBProgressHUD

@interface AVPlayer_S : UIView<MBProgressHUDDelegate>

@property (nonatomic, retain) AVPlayer *player;//AVPlayer对象
@property (nonatomic, retain) AVPlayerLayer *playerLayer;//视频播放器的layer层视图,若不明白为何创建,请看目录2.AVPlayer类介绍

@property (nonatomic, retain) NSString *video_url;//接收视频连接
@property (nonatomic, assign) CMTime totalTime;//记录视频总时长
@property (nonatomic, assign) BOOL hidenBar;//视频UI控件是否显示的标识
@property (nonatomic, assign) BOOL didPlay;//缓冲结束立即播放的标识
@property (nonatomic, assign) BOOL isFullScreen;//全屏状态标识
@property (nonatomic, assign) CGRect originalFrame;//记录播放器原始frame

@property (nonatomic, retain) UIImageView *backIamge;//背景图
@property (nonatomic, retain) UILabel *didTimeLabel;//显示已完成的播放时长
@property (nonatomic, retain) UILabel *totalTimeLabel;//显示视频的总播放时长
@property (nonatomic, retain) UIButton *playButton;//播放暂停按钮
@property (nonatomic, retain) UIProgressView *playProgress;//缓冲条
@property (nonatomic, retain) UISlider *playSlider;//播放进度条
@property (nonatomic, retain) UIButton *fullScreenButton;
@property (nonatomic, retain) UIView *barView;//承载上述控件的UIView
@property (nonatomic, retain) UIView *superView;//记录下全屏前的父视图,便于退出全屏后视频处在正确的位置

- (instancetype)initWithFrame:(CGRect)frame videoURL:(NSString *)url;//自定义初始化方法,只需要给定frame和视频连接即可返回一个具有该frame的承载视频播放器的UIView
- (void)removeNotification;//移除通知
- (void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem;//移除playerItem的观察者

@end

AVPlayer_S.m文件

#import "AVPlayer_S.h"
@implementation AVPlayer_S

//自定义初始化方法
- (instancetype)initWithFrame:(CGRect)frame videoURL:(NSString *)url
{
    self = [super initWithFrame:frame];
    if (self) {
        self.didPlay = NO;
        self.originalFrame = frame;
        self.hidenBar = NO;
        self.isFullScreen = NO;
        self.video_url = url;
        self.backgroundColor = [UIColor blackColor];
        [self creatView:frame];//创建UI视图
        [self createPlayer:self.originalFrame];//创建layer层,用于播放视频
        [MBProgressHUD showHUDAddedTo:self animated:YES];//添加小菊花,若不想用就删除与之相关的东西
    }

    return self;
}

- (void)createPlayer:(CGRect)frame {

    NSString *urlStr =[self.video_url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url=[NSURL URLWithString:urlStr];
    //开辟线程执行AVPlayerItem的创建,若不开辟线程则会占用主线程,造成视图加载完成后暂时无法对页面进行操作的卡顿现象
    dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
    dispatch_async(globalQueue, ^{
    //创建AVPlayerItem
         AVPlayerItem *playerItem=[AVPlayerItem playerItemWithURL:url];
        dispatch_async(dispatch_get_main_queue(), ^{
            if (playerItem) {
                if (!_player) {
                    _player = [AVPlayer playerWithPlayerItem:playerItem];
                    if (_player) {
                    //保证AVPlayer对象存在,然后再为其添加进度观察,以便获取当前播放进度
                        [self addProgressObserver];
                        //给AVPlayerItem添加监控(最重要的监控)
                        [self addObserverToPlayerItem:playerItem];
                    }
                }
            } else {
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"无法连接到视频资源" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
                [alert show];
                [self removeFromSuperview];
            }

        });
    });
    //创建播放层(layer层)
    self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    self.playerLayer.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
    [self.layer addSublayer:self.playerLayer];
}


#pragma mark - 通知
//添加通知

- (void)addNotification {
    //添加 播放结束 通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
}

//移除所有通知
- (void)removeNotification {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

// 播放完成通知执行的方法:移除播放视图及小菊花假如想执行此操作可以解除注释

- (void)playbackFinished:(NSNotification *)notification {
/*
    [MBProgressHUD hideHUDForView:self animated:YES];
    [self removeFromSuperview];
*/
}

#pragma mark - 监控
// 给播放器添加进度更新

- (void)addProgressObserver {

    UISlider *slider = self.playSlider;//获取当前滑动条
    __block AVPlayer_S *av_s = self;

    //这里设置每秒执行一次
    [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {

        float current = CMTimeGetSeconds(time);//获取当前的播放时间

        if (current) {
            [slider setValue:current animated:YES];//实时设置滑动条当前值
            int currentTime = (int)current;
            int m = currentTime / 60;
            int s = currentTime % 60;
            NSString *strM = nil;
            NSString *strS = nil;
            if (m < 10) {
                strM = [NSString stringWithFormat:@"0%d", m];
            } else {
                strM = [NSString stringWithFormat:@"%d", m];
            }
            if (s < 10) {
                strS = [NSString stringWithFormat:@"0%d", s];
            } else {
                strS = [NSString stringWithFormat:@"%d", s];
            }
            //设置UILabel视图显示当前播放时长
            av_s.didTimeLabel.text = [NSString stringWithFormat:@"%@:%@", strM, strS];
        }

    }];
}
// 给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];

}

//通知移除方法
- (void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem {
    [playerItem removeObserver:self forKeyPath:@"status"];
    [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
}

/*
 *  通过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"]) {
        //获取status值
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        //暂停状态
        if (status == AVPlayerStatusReadyToPlay) {
            self.totalTime = playerItem.duration;//获取视频总时长
            [self customVideoSlider:playerItem.duration];//设置播放进度最大值
            int totalTime = (int)CMTimeGetSeconds(playerItem.duration);
            int m = totalTime / 60;
            int s = totalTime % 60;
            NSString *strM = nil;
            NSString *strS = nil;
            if (m < 10) {
                strM = [NSString stringWithFormat:@"0%d", m];
            } else {
                strM = [NSString stringWithFormat:@"%d", m];
            }
            if (s < 10) {
                strS = [NSString stringWithFormat:@"0%d", s];
            } else {
                strS = [NSString stringWithFormat:@"%d", s];
            }
            //设置视频时长的UILabel视图显示值
            self.totalTimeLabel.text = [NSString stringWithFormat:@"%@:%@", strM, strS];
        }
    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
    //播放状态
        [self addNotification];//添加播放完成通知
        NSArray *array = playerItem.loadedTimeRanges;
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次缓冲时间范围
        float startSeconds = CMTimeGetSeconds(timeRange.start);
        float durationSeconds = CMTimeGetSeconds(timeRange.duration);
        NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度
        //设置缓存条
        [self.playProgress setProgress:totalBuffer/CMTimeGetSeconds(self.totalTime) animated:YES];
        float currentPlayTime =  CMTimeGetSeconds([self.player currentTime]);//获取当前播放时长
        //设定当缓冲总时长超过播放时长3秒时开始播放视频
        if (totalBuffer - currentPlayTime > 3.0) {
            if (!self.didPlay) {
                [self createPlayer:self.frame];
                [self.player play];
                [MBProgressHUD hideHUDForView:self animated:YES];
                [self bringSubviewToFront:self.barView];
                [self.playButton setImage:[UIImage imageNamed:@"pause_64"] forState:UIControlStateNormal];
                self.didPlay = YES;
            }
        } else {
            [self.player pause];
            [MBProgressHUD showHUDAddedTo:self animated:YES];
            self.didPlay = NO;
            [self.playButton setImage:[UIImage imageNamed:@"play_64"] forState:UIControlStateNormal];
        }

    }
}
//播放视图的创建
- (void)creatView:(CGRect)frame {

    self.backIamge = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
    self.backIamge.image = [UIImage imageNamed:@"back_Image.png"];

    self.barView = [[UIView alloc] initWithFrame:CGRectMake(0, frame.size.height-40, frame.size.width, 40)];
    self.barView.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.5];

    self.playProgress = [[UIProgressView alloc] initWithFrame:CGRectMake(50, 15, self.barView.frame.size.width-100, 10)];
    [self.playProgress setProgressTintColor:[UIColor orangeColor]];

    self.playSlider = [[UISlider alloc] initWithFrame:CGRectMake(47, 11.2, self.playProgress.frame.size.width+10, 10)];
    [self.playSlider setThumbImage:[UIImage imageNamed:@"ball_16"] forState:UIControlStateNormal];

    self.didTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 25, 50, 10)];
    self.didTimeLabel.font = [UIFont systemFontOfSize:14];
    self.totalTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.barView.frame.size.width-100, 25, 50, 10)];
    self.totalTimeLabel.font = [UIFont systemFontOfSize:14];
    //=================
    UIGraphicsBeginImageContextWithOptions((CGSize){ 2, 2 }, NO, 0.0f);
    UIImage *transparentImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [self.playSlider setMinimumTrackTintColor:[UIColor blueColor]];
    [self.playSlider setMaximumTrackImage:transparentImage forState:UIControlStateNormal];
    //=================
    [self.playSlider addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];

    self.playButton = [UIButton buttonWithType:UIButtonTypeCustom];
    self.playButton.frame = CGRectMake(5, 5, 30, 30);
    [self.playButton addTarget:self action:@selector(playButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.playButton setBackgroundColor:[UIColor clearColor]];
    [self.playButton setImage:[UIImage imageNamed:@"play_64.png"] forState:UIControlStateNormal];

    self.fullScreenButton = [UIButton buttonWithType:UIButtonTypeCustom];
    self.fullScreenButton.frame = CGRectMake(self.barView.frame.size.width - 40, 5, 30, 30);
    [self.fullScreenButton addTarget:self action:@selector(fullScreenButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.fullScreenButton setBackgroundColor:[UIColor clearColor]];
    [self.fullScreenButton setImage:[UIImage imageNamed:@"fullScreen_64.png"] forState:UIControlStateNormal];

    [self.barView addSubview:self.playButton];
    [self.barView addSubview:self.playProgress];
    [self.barView addSubview:self.playSlider];
    [self.barView addSubview:self.didTimeLabel];
    [self.barView addSubview:self.totalTimeLabel];
    [self.barView addSubview:self.fullScreenButton];
    [self addSubview:self.barView];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
    [self addGestureRecognizer:tap];
}

- (void)tapAction:(UITapGestureRecognizer *)tap {

    if (self.hidenBar) {
        self.hidenBar = NO;
        [self bringSubviewToFront:self.barView];
    } else {
        self.hidenBar = YES;
    }
    self.barView.hidden = self.hidenBar;
}

- (void)playButtonAction:(UIButton *)button
{
    NSLog(@"%f", self.player.rate);
    if(self.player.rate == 0){ //说明是暂停
        [button setImage:[UIImage imageNamed:@"pause_64"] forState:UIControlStateNormal];
        self.backIamge.hidden = YES;
        if (self.didPlay) {
            [self.player play];
        }
    }else if(self.player.rate == 1){//正在播放
        [self.player pause];
        [button setImage:[UIImage imageNamed:@"play_64"] forState:UIControlStateNormal];
    }
}

//全屏设置
- (void)fullScreenButtonAction:(UIButton *)button {

    if (self.isFullScreen) {
        self.isFullScreen = NO;
        [self.fullScreenButton setImage:[UIImage imageNamed:@"fullScreen_64.png"] forState:UIControlStateNormal];

        [UIView animateWithDuration:0.2 animations:^{

            self.transform = CGAffineTransformRotate(self.transform, -M_PI_2);

            self.frame = self.originalFrame;
            [self.playerLayer removeFromSuperlayer];
            [self createPlayer:self.originalFrame];

            self.barView.frame = CGRectMake(0, self.originalFrame.size.height-40, self.originalFrame.size.width, 40);
            [self bringSubviewToFront:self.barView];

            self.center = CGPointMake(self.originalFrame.origin.x + self.originalFrame.size.width/2.0, self.originalFrame.origin.y + self.originalFrame.size.height/2.0);

            self.backIamge.frame = CGRectMake(0, 0, self.originalFrame.size.width, self.originalFrame.size.height);
            self.playProgress.frame = CGRectMake(50, 15, self.barView.frame.size.width-100, 10);
            self.playSlider.frame = CGRectMake(45, 11, self.playProgress.frame.size.width+10, 10);
            self.playButton.frame = CGRectMake(5, 5, 30, 30);
            self.fullScreenButton.frame = CGRectMake(self.barView.frame.size.width - 40, 5, 30, 30);

            [self.superView addSubview:self];
        }];

    } else {
        self.isFullScreen = YES;
        self.superView = self.superview;

        [self.fullScreenButton setImage:[UIImage imageNamed:@"exitFullScreen_64.png"] forState:UIControlStateNormal];
        [self.window addSubview:self];
        [self.window bringSubviewToFront:self];

        [UIView animateWithDuration:0.2 animations:^{
            self.frame = CGRectMake(20, 0, [UIScreen mainScreen].bounds.size.height-20, [UIScreen mainScreen].bounds.size.width);
            [self.playerLayer removeFromSuperlayer];

            [self createPlayer:self.frame];

            self.barView.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.width-40, [UIScreen mainScreen].bounds.size.height-20, 40);
            [self bringSubviewToFront:self.barView];
            self.backIamge.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.height-20, [UIScreen mainScreen].bounds.size.width);

            self.transform = CGAffineTransformRotate(self.transform, M_PI_2);
            self.center = CGPointMake([UIScreen mainScreen].bounds.size.width/2.0, ([UIScreen mainScreen].bounds.size.height+20)/2.0);
            self.playProgress.frame = CGRectMake(50, 15, self.barView.frame.size.width-100, 10);
            self.playSlider.frame = CGRectMake(45, 11, self.playProgress.frame.size.width+10, 10);
            self.playButton.frame = CGRectMake(5, 5, 30, 30);
            self.fullScreenButton.frame = CGRectMake(self.barView.frame.size.width - 40, 5, 30, 30);
            self.totalTimeLabel.frame = CGRectMake(self.barView.frame.size.width-100, 25, 50, 10);
        }];

    }
}

//UISlider基本设置
- (void)customVideoSlider:(CMTime)duration {

    self.playSlider.maximumValue = CMTimeGetSeconds(duration);
    self.playSlider.minimumValue = 0.0;
}

//拖动进度条到任何位置播放
- (void)sliderAction:(UISlider *)slider {

    if (self.player.rate == 0) {
        [self.player seekToTime:CMTimeMake((int)slider.value*10, 10.0)];
        [self.player play];
        [self.playButton setImage:[UIImage imageNamed:@"pause_64.png"] forState:UIControlStateNormal];
    } else if(self.player.rate == 1) {
        [self.player pause];
        [self.player seekToTime:CMTimeMake((int)slider.value*10, 10.0)];
        [self.player play];
        [self.playButton setImage:[UIImage imageNamed:@"pause_64.png"] forState:UIControlStateNormal];
    }
}

@end

Demo :http://download.csdn.net/detail/yangxinca/8949003

2015-11-06 16:58:14 MyCSDN_FanJinxin 阅读数 6406

首先需要创建AVPlayer  这时候要先包含头文件,因为是9.0了,所以不用包含库,直接导入头文件即可

#import <AVFoundation/AVFoundation.h>

在这里可以把播放器作为成员变量,方便全局使用,当然,也可以不用,我在这里是作为全局变量来使用的,方便内存的管理

@property (nonatomic,strong) AVPlayer *player;//视频播放
@property (nonatomic,strong)AVPlayerLayer *playerLayer;

接着就是创建了

//创建视频播放器
NSString *filePath =[[NSBundle mainBundle]pathForResource:@"flash" ofType:@"mp4"];
NSURL *sourceMovieURL = [NSURL fileURLWithPath:filePath];
//初学者这里先不要管,但是必须要创建
AVAsset *movieAsset    = [AVURLAsset URLAssetWithURL:sourceMovieURL options:nil];        
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:movieAsset];
_player = [AVPlayer playerWithPlayerItem:playerItem];
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
//大小
_playerLayer.frame = CGRectMake(ScreenWidth/4.4, ScreenHeight/3.3, _coverView.pictureAndAvView.frame.size.width, _coverView.pictureAndAvView.frame.size.height+100);
_playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;
_playerLayer.backgroundColor  = [UIColor blackColor].CGColor;
//要添加的地方
[_coverView.AirBubble.layer addSublayer:_playerLayer];
[_player play];            



用完是需要注意要对其进行释放:写在你退出的点击事件当中,比如说要pop视图了

[self.playerLayer removeFromSuperlayer];
self.playerLayer=nil;   
self.player=nil;


搞定!


2016-05-23 16:57:46 u013282507 阅读数 5068

*说明:利用AVPlayer可以制作视频播放器、音频播放器;使用AVPlayer播放过的格式有 .mp4  .m3u8   .mp3

1、创建播放器:

_player = [[AVPlayer alloc] initWithPlayerItem:[AVPlayerItem playerItemWithURL:[NSURL URLWithString:@""]]];

2、切换播放地址

    AVPlayerItem *item = [AVPlayerItem playerItemWithURL:mediaUrl];
    [_player replaceCurrentItemWithPlayerItem:item];

3、跳转进度, 参数second秒

    CMTime changedTime = CMTimeMakeWithSeconds(second, 1);
    [_player seekToTime:changedTime completionHandler:^(BOOL finished) {
    }];

4、改变播放速率 0.5为正常速度的一半 默认rate是1 

    [_player setRate:0.5];

5、暂停/继续

    [_player pause];
    [_player play];

6、播放时间(单位:秒)

    CGFloat currentPlayTime =_player.currentItem.currentTime.value/_player.currentItem.currentTime.timescale;

7、缓冲时间

    NSArray *loadedTimeRanges = [[_player currentItem] loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];//获取缓冲区域
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    NSTimeInterval result = startSeconds + durationSeconds;//计算缓冲总进度
2018-03-01 15:26:43 findhappy117 阅读数 71

代码地址如下:
http://www.demodashi.com/demo/11168.html

一、运行效果

总效果.gif

二、实现过程

①、创建播放器avPlayer

       //创建播放器
        url = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        AVPlayer *player = [AVPlayer playerWithURL:[NSURL URLWithString:url]];
        self.avPlayer = player;

②、创建显示屏_videoLayer

- (void)createDisplay{

    // 显示图像的
    _videoLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
    //锚点的坐标
    _videoLayer.position = CGPointMake(KPLAYVIEWWIDTH/2, KPLAYVIEWHEIGHT/2);
    _videoLayer.bounds = CGRectMake(0, 0, KPLAYVIEWWIDTH, KPLAYVIEWHEIGHT);
    // 锚点,值只能是0,1之间
    _videoLayer.anchorPoint = CGPointMake(0.5, 0.5);

    //     AVLayerVideoGravityResizeAspect 按比例压缩,视频不会超出Layer的范围(默认)
    //     AVLayerVideoGravityResizeAspectFill 按比例填充Layer,不会有黑边
    //     AVLayerVideoGravityResize 填充整个Layer,视频会变形
    //     视频内容拉伸的选项
    _videoLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    //    //播放时,视频实际占的区域
    //    NSLog(@"%@", NSStringFromCGRect(videoLayer.videoRect));

    //Layer只能添加到Layer上面
    [self.displayView.layer addSublayer:_videoLayer];
}

③、添加观察者和通知,用于监测更新视频播放的状态、进度、屏幕方向、状态栏属性、音量等等。

主要代码如下:

//监测屏幕旋转
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChange:) name:UIDeviceOrientationDidChangeNotification object:nil];

    //添加AVPlayerItem播放结束通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayer.currentItem];

    //添加AVPlayerItem开始缓冲通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bufferStart:) name:AVPlayerItemPlaybackStalledNotification object:self.avPlayer.currentItem];

//KOV监控 播放器进度更新
- (void)addObserverForAVPlayer
{
    AVPlayerItem *playerItem = self.avPlayer.currentItem;

    // 给AVPlayer添加观察者 必须实现 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;

    //监控播放速率
    [self.avPlayer addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:nil];
    //监控状态属性(AVPlayer也有一个status属性,通过监控它的status也可以获得播放状态)
    [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    //监控网络加载缓冲情况属性
    [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //监控是否可播放
    [playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];


    //播放进度观察者  //设置每0.1秒执行一次
    __weak GOVVideoView *weakSelf = self;
    _playerTimeObserver =  [self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {

        if (weakSelf.dragSlider) {
            return ;
        }

        CGFloat current = CMTimeGetSeconds(time);
        weakSelf.current = current;
        CMTime totalTime = weakSelf.avPlayer.currentItem.duration;
        CGFloat total = CMTimeGetSeconds(totalTime);
        weakSelf.total = total;
        weakSelf.slider.value = current/total;
        weakSelf.currentTimeLabel.text = [weakSelf timeFormatted:current];
        weakSelf.totalTimeLabel.text = [NSString stringWithFormat:@"/%@",[weakSelf timeFormatted:total]] ;

    }];
}

//通过KVO监控回调
//keyPath 监控属性 object 监视器 change 状态改变 context 上下文
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

    if ([keyPath isEqualToString:@"loadedTimeRanges"]) {

        //监控网络加载情况属性
        NSArray *array = self.avPlayer.currentItem.loadedTimeRanges;
        //本次缓冲时间范围
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];
        CGFloat startSeconds = CMTimeGetSeconds(timeRange.start);
        CGFloat durationSeconds = CMTimeGetSeconds(timeRange.duration);
        //现有缓冲总长度
        CGFloat totalBuffer = startSeconds + durationSeconds;
        //视频总时长
        CMTime totalTime = self.avPlayer.currentItem.duration;
        CGFloat total = CMTimeGetSeconds(totalTime);
        if (totalBuffer/total <= 1.0 ) {
            [self.progressView setProgress:totalBuffer/total animated:YES];
        }

    }else if([keyPath isEqualToString:@"playbackLikelyToKeepUp"]){

        if (self.avPlayer.currentItem.playbackLikelyToKeepUp == YES) {

            if (_activityView != nil) {
                [self.activityView startAnimating];
                [self.activityView removeFromSuperview];
                _activityView = nil;
            }
        }
    }else if ([keyPath isEqualToString:@"status"]){

        //监控状态属性
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];

        switch ((status)) {
            case AVPlayerStatusReadyToPlay:

                break;
            case AVPlayerStatusUnknown:

                break;
            case AVPlayerStatusFailed:

                break;

        }
    }else if ([keyPath isEqualToString:@"rate"]){
        if (self.avPlayer.rate == 1) {
        }
    }

}

隐藏/显示状态栏的方法:

[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];这个方法在iOS9之后弃用了,并且需要
将View controller-based status bar appearance设置为NO;而下面的重写方法需要将View controller-based status bar appearance设置为YES,这个方法在iOS7之后就有了;
//刷新状态栏状态
[self setNeedsStatusBarAppearanceUpdate];

#pragma mark -- 隐藏/显示状态栏的方法
/*[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];这个方法在iOS9之后弃用了,并且需要
 将View controller-based status bar appearance设置为NO;而下面的重写方法需要将View controller-based status bar appearance设置为YES,这个方法在iOS7之后就有了;
//刷新状态栏状态
 [self setNeedsStatusBarAppearanceUpdate];
 */
//设置样式
- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}
//设置是否隐藏
- (BOOL)prefersStatusBarHidden {
    return self.isHiddenStatusBar;
}
//设置隐藏动画
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
    return UIStatusBarAnimationNone;
}

④、创建用于处理播放结束、关闭播放器、全屏/退出全屏、隐藏/展示footBar和topBar的Block回调方法和代理方法,方便用户做些自定义的操作。

//Block回调方法
typedef void(^FullScreenBlock)(BOOL isFull);

typedef void(^ClosePLayerBlock)();

typedef void(^ShowBarBlock)(BOOL isShow);

typedef void(^PlayFinishedBlock)();

@class GOVVideoPlayer;
//代理方法
@protocol GOVVideoPlayerDelegate  <NSObject>

//播放结束
- (void)videoPlayerPlayFinished:(GOVVideoPlayer *)videoPlayer;

//关闭播放器
- (void)videoPlayerClosePlayer:(GOVVideoPlayer *)videoPlayer;

//全屏按钮
- (void)videoPlayerFullScreen:(GOVVideoPlayer *)videoPlayer withIsFull:(BOOL)isFull;

//隐藏/展示footBar和topBar
- (void)videoPlayerShowBar:(GOVVideoPlayer *)videoPlayer withIsShow:(BOOL)isShow;

三、项目结构图

项目结构图

四、补充

GOVVideoPlayer是在继承于UIView的基础上封装的视频View;
GOVVideoController是在继承于UIViewController的基础上封装的视频视图控制器。
两者最大的不同是在全屏和取消全屏的处理上面:前者是一个视图View,可以直接加在父视图上面,全屏时是加在 [UIApplication sharedApplication].keyWindow上的,而后者,小屏时是取GOVVideoController的View加在父视图上,全屏和取消全屏时是采用present和dismiss模态化转场的方法 。

iOS AVPlayer视频播放器

代码地址如下:
http://www.demodashi.com/demo/11168.html

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

没有更多推荐了,返回首页