在iOS多媒体开发的过程中,经常会用到视频播放器,简单是视频播放器,直接使用苹果封装好的MPMoviePlayerController和MPMoviePlayerViewController就可以实现视频播放功能了,但是,多数情况下,都需要自定制视频播放器,这是,就要使用神器AVPlayer来进行开发了,下面,就讲述一下AVPlayer的使用,这里列出两篇比较好的博客,供大家参考:

iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

AVFoundation编程指南2-用AVPlayer播放视频
前一篇博客主要是简答介绍了怎样自定制视音频播放器,后一篇则比较深层次的讲解了视频播放器的相关信息,有兴趣的同学也可以了解一下AVFoundation框架,跟着本篇博客,读者可以自定义出一个完整的视频播放器。好了,废话不多说,开始进行视频播放的讲解。
首先,要使用AVPlayer进行自定制视频播放,要引入头文件:
<span style="font-size:18px;">#import <AVFoundation/AVFoundation.h></span>
因为AVPlayer属于AVFoundation框架,所以要引入这个头文件。其次,当然是要创建我们的视频播放器AVPlayer了,这里在.h文件中声明了一个全局的Player对象,便于在不同的函数中进行相关操作。
<span style="font-size:18px;">@property (nonatomic,strong) AVPlayer * player;</span>
然后,在初始化方法中对其进行初始化。在初始化过程中,需要传入视频的URL,这个URL是NSURL类型的,这里简单说明一下,AVPlayer支持本地视频播放和媒体视频播放,因此,这个URL既可以是本地视频的URL,也可以是网络视频的URL,本篇博客选取了一段网络视频:
<span style="font-size:18px;">    //网络视频NSString * urlStr = [NSString stringWithFormat:@"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];NSURL * url = [NSURL URLWithString:urlStr];</span>
首先用字符串传进来一个地址,然后,为了对字符串进行UTF-8编码,之前是用的其他的方法,但是,在iOS9之后,已经被启用了,所以这里用上面的方法,进行编码,前后,用编码之后的字符串初始化URL。其实,如果不考虑比较多的内容的话,直接用下面的方法就可以创建一个AVPlayer了:
<span style="font-size:18px;">self.player = [[AVPlayer alloc] initWithURL:url];</span>
这其实是最简单的方法,但是一般不推荐使用,操作起来会很不方便。其实,自定制音频播放,也是用AVPlayer自定制,到这里的话,基本上就能够实现音频的播放了。但是,视频播放器的话,还要有画面,因此,还需要用这个Player去初始化一个图层,然后将图层加到当前的view的Layer上,这样,就有画面了,这里也是创建了一个全局的AVPlayerLayer对象:
<span style="font-size:18px;">@property (nonatomic,strong) AVPlayerLayer * playerLayer;</span>
然后在.m中,接着上面的方法写入下面的代码:
<span style="font-size:18px;">    self.player = [[AVPlayer alloc] initWithURL:url];self.playerLayer.frame = self.layer.bounds;self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;[self.layer addSublayer:self.playerLayer];</span>
我在创建的时候,是在一个View中创建的,所以直接是self.layer,如果是在Controller中,则是self.view.layer,然后,设置一下playerLayer的大小和方向。这样,就创建了一个Player。当然,上面说过,这只是简单的创建方式,通常情况下使用下面将要介绍的方式进行创建:
首先在.h中定义了一个AVPlayerItem对象:
<span style="font-size:18px;">@property (nonatomic,strong) AVPlayerItem * playerItem;</span>

然后,在.m文件中进行下面的操作:
<span style="font-size:18px;">    AVURLAsset * movieAsset = [[AVURLAsset alloc] initWithURL:URL options:nil];self.playerItem = [AVPlayerItem playerItemWithAsset:movieAsset];self.player = [AVPlayer playerWithPlayerItem:self.playerItem];self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];self.playerLayer.frame = self.layer.bounds;self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;[self.layer addSublayer:self.playerLayer];</span>
使用这种方式,就创建了一个player,并加到的当前视图的layer上。这里涉及到了其他的两个类AVURLAsset和AVPlayerItem。这里的AVURLAsset是AVAsset的子类,AVAsset不能直接用AVAsset进行初始化,需要用子类初始化,AVAsset和AVURLAsset其实是一个资源类,代表了视频资源,AVAsset也是AVFoundation中最终要的一个类,是对资源的抽象,想详细了解的,可以了解一下AVFoundation框架。而AVPlayerItem对应的其实就是要播放的视频了,先通过URL来创建一个视频播放器资源,然后,再用这个资源来初始化一个要播放的视频,之后,用这个视频初始化播放器,将播放器指定要播放的图层,基本上就创建完成了一个视频播放器,这里的初始化,是一层层进行的,希望大家不要被绕晕了,可以反复揣摩一下。player有一个rate属性,用来表示视频播放的速度,取值范围是0-1,1为正常速度,0的话,表示视频暂停了。上面说到,AVPlayerItem其实就相当于要播放的视频,因此,可以通过这个item,可以获得视频的总时长以及当前缓存到了哪里,所以,为了获取这些信息,要对item的相关属性进行监听:
<span style="font-size:18px;">    /***  监听AVPlayerItem的属性*/[self.playerItem addObserver:self forKeyPath:@"status" options:0 context:NULL];[self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:0 context:NULL];self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
</span>
然后,添加监听的方法:
<span style="font-size:18px;">/***  KVO监听playItem的属性变化**  @param keyPath keyPath description*  @param object  object description*  @param change  change description*  @param context context description*/
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{AVPlayerItem * item = self.player.currentItem;if ([keyPath isEqualToString:@"status"]) {//正在播放if (AVPlayerItemStatusReadyToPlay == item.status) {NSLog(@"正在播放...,视频总长度:%.2f",CMTimeGetSeconds(item.duration));}else if (AVPlayerItemStatusUnknown == item.status){NSLog(@"视频加载中");}else if (AVPlayerStatusFailed == item.status){NSLog(@"视频获取失败");NSLog(@"%@",item.error);}} else if([keyPath isEqualToString:@"loadedTimeRanges"]){NSArray *array=item.loadedTimeRanges;CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];//本次缓冲时间范围float startSeconds = CMTimeGetSeconds(timeRange.start);float durationSeconds = CMTimeGetSeconds(timeRange.duration);NSTimeInterval totalBuffer = startSeconds + durationSeconds;//缓冲总长度NSLog(@"共缓冲:%.2f",totalBuffer);}
}</span>
通过监听status属性,来获得当前食品播放的状态,当状态为AVPlayerItemStatusReadyToPlay的时候,便是视频已经准备好了,此时,就可以播放当前的视频,可以在这里调用方法:
<span style="font-size:18px;"> [self.player play];</span>
来播放当前的视频,player有一个属性叫做currentItem,这个属性,就是当前player的item,也就是前面初始化过程中的那个item。监听item的loadedTimeRanges属性,可以获得当前缓冲了多少视频以及视频的总长度。item的loadedTimeRanges其实是一个数组,里面存放了CMTimeRange类型的结构体,通过获得该array的firstObject可以获得本次缓冲的时间信息timeRange,timeRange.start表示本次缓冲的开始位置,timeRange.duration表示本次缓冲的视频长度,两者相加,就获得了缓冲的总时长,这就是好多播放器中,底部进度条中缓冲的视频长度的获取方式。由于loadedTimeRanges经常要变化,所以,会反复出发这个KVO的监听,因此,可以做到随时刷新缓冲进度。此外,当退出播放器页面的时候,要移除相关的观察者。
<span style="font-size:18px;">//移除观察者
-(void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem{[playerItem removeObserver:self forKeyPath:@"status"];[playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
}</span>
然后在dealloc调用这个方法该方法即可。
此外,当视频播放完成之后,还会有相关的通知,在这里,可以对其进行监听,当播放完成之后,进行相关的UI刷新:
<span style="font-size:18px;">/***  添加播放器通知*/
-(void)addNotification{//给AVPlayerItem添加播放完成通知[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
}</span>
例如,可以更改播放按钮的图片:
<span style="font-size:18px;">- (void)playbackFinished:(NSNotification *)notification{[self.playButton setImage:[UIImage imageNamed:@"button_normal"] forState:UIControlStateNormal];}</span>
既然监听通知了,就要在dealloc中移除监听:
<span style="font-size:18px;">    [self removeNotification];</span>
上面只是创建了视频播放器,下面将讲解视频播放器的控制。我们在进行视频自定制的时候,还要实现视频播放器的播放、暂停、继续播放、停止功能,因此,还要进行一些其他的操作,我这里将播放和继续播放进行了区分,这里说的播放,是从头开始播放,继续播放,则是从上次暂停的位置进行播放,因此要设置一个属性,来保存当前播放的位置:
<span style="font-size:18px;">//当前播放进度
@property (nonatomic,assign) double currentTime;</span>
下面是从头播放的方法:
<span style="font-size:18px;">/***  开始播放*/
- (void)play{AVPlayerItem * item = self.player.currentItem;
//    [item seekToTime:CMTimeMakeWithSeconds(0, 1.0)];[item seekToTime:CMTimeMakeWithSeconds(0, 1.0) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];self.progressBar.value = 0;[self.player play];//设置播放速度
}</span>
在该方法中,用到了seekToTime方法,该方法用来从指定位置开始播放,传入一个CMTime类型的时间值,来指定比方的位置。我的项目中,添加了一个进度条(UISlider),来表示当前播放的进度,因此,当从0来说播放的时候,在这里将slider的value设置成0。这里还注释掉了一个seek方法,下面简单说一下,第一个seek方法,seek的时间没有第二个精确,但第二个更好性能,但还是推荐使用第二个。
下面是暂停的方法:
<span style="font-size:18px;">/***  暂停播放*/
- (void)pause{self.currentTime = [self playableCurrentTime];[self.player pause];//设置播放按钮[self.playButton setImage:[UIImage imageNamed:@"button_normal"] forState:UIControlStateNormal];
}</span>
Avplayer自带一个pause方法,因此,这里可以直接调用,还有上面的play方法也是自带的。下面是resume方法:
<span style="font-size:18px;">/***  继续播放*/
- (void)resume{AVPlayerItem * item = self.player.currentItem;
//    [item seekToTime:CMTimeMakeWithSeconds(self.currentTime, 1.0)];[item seekToTime:CMTimeMakeWithSeconds(self.currentTime, 1.0) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];[self.player play];//设置播放速度self.player.rate = self.rate;
}</span>
上面说到了player的rate属性,其实这个属性的取值并不一定非要在0-1之间,当大于1的时候,会加速播放,小于1会减缓,这里可以通过这个属性来控制播放的速度。下面是停止方法:
<span style="font-size:18px;">/***  停止*/
- (void)stop{AVPlayerItem * item = self.player.currentItem;
//    [item seekToTime:CMTimeMakeWithSeconds(0, 1.0)];[item seekToTime:CMTimeMakeWithSeconds(0, 1.0) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];[self.player pause];self.currentTime = 0;}</span>
这里使用seek方法,seek到0,然后调用player的pause方法,将视频pause,就实现了视频的stop功能。
此外,有些情况下,还会遇到这样的需求,就是将视频静音,在AVFoundation中,已经为我们提供了这样一个方法,就是将play的volume值设置为0。但是,这里要仔细考虑一下了,当设置为0之后,要想设置回来,怎么办呢?因此,要将当前的volume保存起来。定义一个变量保存当前的音量。
//音量
@property (nonatomic,assign) float volumn;
当点击静音按钮的时候,调用下面的方法即可:
<span style="font-size:18px;">/***  设置静音**  @param mute 静音传入的一个BOOL值,YES为静音,NO不静音*/
- (void)playerMute:(BOOL)mute{if (mute) {[self.player setVolume:0];} else {[self.player setVolume:self.volumn];}
}</span>
这里有一个问题需要注意,这里设置的音量,只是应用中的音量,并不是系统音量,也就是说,当系统音量为0的时候,及时这个volume再大,也是没有声音的,因此,当想要恢复音量的时候,这里的volume一般都设置1,即正常的音量。这时候,有些通过就会想了,那么,该怎么获取系统音量,然后点击手机上的音量键来调节音量,其实还是有方法的,下面是我写的另一篇博客:
iOS更改系统音量
想获取系统音量,请跳转到这个博客,了解一下就好,也可以查询一下其他的博客。
下面,再讲一些其他的控制。
自定制播放器的过程中,当视频播放进度发生改变的时候,我们也希望对应的进度条也跟着变化,因此,要监听视频播放的进度,可以使用下面的方法进行实现:
<span style="font-size:18px;">/***  进度更新设置,监听视频播放进度,同时更新进度条的value*/
- (void)addProgressBarObserver{AVPlayerItem *playerItem=self.player.currentItem;__weak typeof(self) weakSelf = self;[self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {float current = CMTimeGetSeconds(time);float total = CMTimeGetSeconds([playerItem duration]);if (current) {[weakSelf.progressBar setValue:(current/total) animated:YES];}}];
}</span>
这里将进度条更新的操作封装成了一个方法,其实还是调用了AVPlayer自带的方法
<span style="font-size:18px;">- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;</span>

这个方法的前一个参数还是CMTime类型的,后面是一个block,表示每个interval的时间,就回调一下这个block,这样的话,我们就可以在这里通过播放进度和总时长,来设置进度条的value值了。

通过以上的方法,基本上就能实现一个简单的视频播放器了,可能有些地方说的不好或者说法有误,欢迎大家在下面进行评论,指出我的错误,大家共同进步。想进一步了解视频播放器的内容,欢迎阅读下一篇博客:

AVPlayer自定制视频播放器(2)——耳机线控、中断以及AVAudioSession的使用

AVPlayer自定制视频播放器(1)——视频播放器基本实现相关推荐

  1. AVPlayer自定制视频播放器(2)——耳机线控、中断以及AVAudioSession的使用

    在上一篇博客中说到了使用AVPlayer进行自定义视频播放器.这里讲继续讲述视频播放器的自定制.下面是上一篇博客的链接,本篇博客将承接上一篇博客进行讲解,如果有AVPlayer自定制视频播放器基础的同 ...

  2. Qt实用技巧:使用OpenCV库的视频播放器(支持播放器操作,如暂停、恢复、停止、时间、进度条拽托等...

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 需求 使用OpenCV库的视频播放器(支持播放器操作,如暂停.恢复 ...

  3. android vr播放器 开发,Android应用开发之Android VR Player(全景视频播放器)- ExoPlayer播放器MPEG-DASH视频播放...

    本文将带你了解Android应用开发之Android VR Player(全景视频播放器)- ExoPlayer播放器MPEG-DASH视频播放,希望本文对大家学Android有所帮助. Androi ...

  4. 基于qt开发的智能系统:电子相册,监控摄像头模块,音乐播放器,视频播放器,电子时钟

    登录模块 源码请移步 //登录验证按钮函数 void MainWindow::on_loginBtn_clicked() {//获得userNameLEd输入框的文本userNameLEd->t ...

  5. 安卓视频播放器 一行代码快速实现视频播放,Android视频播放,AndroidMP3播放,安卓视频播放一行代码搞定,仿今日头条 Android视频播放器

    一行代码快速实现视频播放,Android视频播放,AndroidMP3播放,安卓视频播放一行代码搞定,真正实现Android的全屏功能 github地址:https://github.com/qius ...

  6. html做全景视频播放器,一种全景视频播放方法及播放器的制造方法

    一种全景视频播放方法及播放器的制造方法 [技术领域] [0001]本发明涉及视频播放领域,尤其涉及一种全景视频播放方法及播放器. [背景技术] [0002]随着近年来视频拍摄技术的发展,全景图片.全景 ...

  7. jqm视频播放器,html5视频播放器,html5音乐播放器,html5播放器,video开发demo,html5视频播放示例,html5手机视频播放器

    最近在论坛中看到了很多实用html5开发视频播放,音乐播放的功能,大部分都在寻找答案.因此我就在这里做一个demo,供大家相互学习.html5开发越来越流行了,而对于视频这一块也是必不可少的一部分.如 ...

  8. Android制作简易的音乐播放器和视频播放器

    文章目录 制作简易的音乐播放器和视频播放器 播放多媒体文件 播放音频 MediaPlayer的工作流程 项目示例 播放视频 项目示例 制作简易的音乐播放器和视频播放器 播放多媒体文件 Android在 ...

  9. iOS开发之AVPlayer的精彩使用---网易新闻视频播放界面的另类实现

    遇到个需求需要涉及到视频播放,那么没办法,先找资料开始进一步了解下这个不熟悉的东西 . 一个是 MP ,一个 是AV,MP是封装好的,用起来非常简单,但是自定义样式就基本不可能了.AVPlayer存在 ...

最新文章

  1. 非抢占式优先算法例题_三维点云的经典算法与前沿技术有哪些?
  2. 学python可以做什么知乎-学会python有哪些好处?python抓取知乎神回复
  3. fopen需要改写成fopen_s的时候
  4. iOS UISegmentedControl 的使用
  5. android 界面跳转封装,【Android】Fragment跳转系列
  6. 用uGUI开发自定义Toggle Slider控件
  7. pyQt显示系统文件目录
  8. 经典算法大全之河内之塔
  9. 互动教程 for Excel 2016
  10. 没有提取码怎么获取百度网盘资源?
  11. 2017.4.8微软笔试题
  12. ERP和SAP是什么意思
  13. 服务器系统分辨率调不了,win10系统分辨率调整显示灰色_网站服务器运行维护
  14. adb 查看浏览器内核版本
  15. 一张思维导图完成淘宝精细化运营
  16. alios 系统配置转存到一个头文件
  17. 制作自定义图标(icon)
  18. Minecraft基岩版电脑端游戏按键整合
  19. java日期格式化为json字符串,看这个就够了
  20. Java生成名片式的二维码源码分享

热门文章

  1. 模拟电路复习--总结
  2. 【转载】关于模拟电路的学习历程
  3. java基础项目_Java 教程整理:基础、项目全都有
  4. 在Oracle中巧用column_value解决游标传入多值问题
  5. SpringBoot+shiro 实现rememberMe
  6. 【3D实践】3D模型骨架提取及分析
  7. 《富爸爸的财富自由之路》
  8. 当删除后微软再次出现如何再次关掉微软输入法
  9. odbc java 驱动程序_java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 在指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配...
  10. Ubuntu给clion添加快捷图标