录制完视频后,我们想在录制视频的预览层上无限循环播放我们的小视频,是不是很炫酷,这时候我们就有三中选择了:
1.MPMoviePlayerController
2.AVPlayer
3.AVAssetReader+AVAssetReaderTrackOutput

但是我们这个预览层是自定义的喔,所以MPMoviePlayerController只能马上给筛选掉了,所以用,那么我们就要用到 AVPlayer 了,虽然上 AVPlayer 最多只能创建16个,性能上不及用 AVAssetReader+AVAssetReaderTrackOutput 方法好,但是对于这么个视频小播放也是足够的了。(PS:接下来博主会写一篇关于如何用AVAssetReader+AVAssetReaderTrackOutput来实现播放视频)

AVPlayer

AVPlayer本身并不能显示视频,而且它也不像MPMoviePlayerController有一个view属性。如果AVPlayer要显示必须创建一个播放器层AVPlayerLayer用于展示,播放器层继承于CALayer,
有了AVPlayerLayer之添加到控制器视图的layer中即可。要使用AVPlayer首先了解一下几个常用的类: AVAsset:主要用于获取多媒体信息,是一个抽象类,不能直接使用。
AVURLAsset:AVAsset的子类,可以根据一个URL路径创建一个包含媒体信息的AVURLAsset对象。
AVPlayerItem:一个媒体资源管理对象,管理者视频的一些基本信息和状态,一个AVPlayerItem对应着一个视频资源。

我们先来熟悉一下 AVPlayer 的这些类
那么运用AVPlayer播放视频的步骤如下:
1.创建 AVPlayerItem ,用来实例化AVPlayer并监控视频的状态

- (AVPlayer *)player
{
if (!_player ) {
AVPlayerItem *playerItem = [self getPlayItem];
_player = [[AVPlayer alloc]initWithPlayerItem:playerItem];
// 可以利用 AVPlayerItem 对这个视频的状态进行监控 }
return _player;
} - (AVPlayerItem *)getPlayItem
{
NSString *cachePath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *savePath=[cachePath stringByAppendingPathComponent:MOVIEPATH];
NSURL *saveUrl=[NSURL fileURLWithPath:savePath]; // 通过文件 URL 来实例化 AVPlayerItem
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:saveUrl]; return playerItem;
}

2.通过AVPlayer 创建预览层(AVPlayerLayer)并添加到可视的图层上播放

 AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
playerLayer.frame = _viewContrain.bounds;
playerLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//视频填充模式
[_viewContrain.layer addSublayer:playerLayer];
[self.player play];

3.通过 KVO 来监听视频的属性,查看是否播放完成,播放长度为多小,缓冲了多少等等

/** * 给播放器添加进度更新 */
-(void)addProgressObserver{
AVPlayerItem *playerItem=self.player.currentItem;
UIProgressView *progress=self.progress; //这里设置每秒执行一次
[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]);
NSLog(@"当前已经播放%.2fs.",current);
if (current) {
[progress setProgress:(current/total) animated:YES];
}
}];
} #pragma mark - KVO
/** * 给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];
} -(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<NSString *,id> *)change context:(void *)context
{
AVPlayerItem *playerItem=object;
if ([keyPath isEqualToString:@"status"]) {
AVPlayerStatus status= [[change objectForKey:@"new"] intValue];
if(status==AVPlayerStatusReadyToPlay){
NSLog(@"正在播放...,视频总长度:%.2f",CMTimeGetSeconds(playerItem.duration));
}
}
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;//缓冲总长度
NSLog(@"共缓冲:%.2f",totalBuffer);
}
}

到此,我们就把 AVPlayer 视频播放的方法创建完毕了。

那么我们在视频录制完成的时候调用播放视频的方法了

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
NSLog(@"---- 录制结束 ----");
}
- (void)completeHandle
{
// 完成后不断播放
[_captureVideoPreviewLayer removeFromSuperlayer]; // 播放视频
// 1.创建播放层
// 这里为什么要调用延迟1.0秒呢,我们说过用 AVCaptureMovieFileOutput 来录制视频,是边录边写的,即使是录制完成了,真实的是视频还在写,大概时间是延迟1.2秒左右。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 在此方法调用创建 AVPlayer 播放视频的第二部
.通过AVPlayer 创建预览层(AVPlayerLayer)并添加到可视的图层上播放
[self addNotification];
});
}
添加视频播放完后的监控来循环播放视频
 /**
* 添加播放器通知
*/
-(void)addNotification{
//给AVPlayerItem添加播放完成通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
} -(void)removeNotification{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
/**
* 播放完成通知
*
* @param notification 通知对象
*/
-(void)playbackFinished:(NSNotification *)notification{
NSLog(@"视频播放完成."); // 播放完成后重复播放
// 跳到最新的时间点开始播放
[_player seekToTime:CMTimeMake(, )];
[_player play];
}

iOS - 视频循环播放的更多相关文章

  1. H5 多个视频 循环播放效果

    跟轮播效果差不多 页面HTML结构 <video id="myvideo" width="100%" height="auto" co ...

  2. 在wpf中如何让MediaElement的视频循环播放

    原文:在wpf中如何让MediaElement的视频循环播放 MediaElement原始的播放是只播放一遍:如何设置让MediaElement播放 的视频或者音频循环播放,解决如下: 修改Media ...

  3. 深入理解MVC C#+HtmlAgilityPack+Dapper走一波爬虫 StackExchange.Redis 二次封装 C# WPF 用MediaElement控件实现视频循环播放 net 异步与同步

    深入理解MVC   MVC无人不知,可很多程序员对MVC的概念的理解似乎有误,换言之他们一直在错用MVC,尽管即使如此软件也能被写出来,然而软件内部代码的组织方式却是不科学的,这会影响到软件的可维护性 ...

  4. ios 视频音乐播放

    IOS开发小技巧(视频和音乐播放).IOS视频播放代码(添加MediaPlayer.framework和#import) -(void)playMovie:(NSString *)fileName{ ...

  5. iOS scrollview循环播放加缩放

    前些日子一直在研究3d的框架没有时间写博客,不过最后需求改了,也没研究出个啥.这段时间出了新的需求,需要循环播放图片,并且滑动的时候中间的图片有缩放的效果.刚开始想在网上搜索,不过并没有找到合适的de ...

  6. C# WPF 用MediaElement控件实现视频循环播放

    在WPF里用MediaElement控件,实现一个循环播放单一视频的程序,同时可以控制视频的播放.暂停.停止. 一种方式,使用MediaElement.MediaEnded事件,在视频播放结束后,自动 ...

  7. video标签实现多个视频循环播放

    <head> <!-- If you'd like to support IE8 (for Video.js versions prior to v7) --> </he ...

  8. HTML5实现两个视频循环播放!

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. html5 css3 背景视频循环播放代码

    <div style ="position: absolute; z-index: -1; top: 0px; left: 0px; bottom: 0px; right: 0px; ...

随机推荐

  1. Android中的Shape使用总结

    参考:http://www.cnblogs.com/gzggyy/archive/2013/05/17/3083218.html 在Android程序开发中,我们经常会去用到Shape这个东西去定义各 ...

  2. HFSS学习(一)计划

    2015-11-28 21:05:33 基本概念 边界条件 激励源 建模 网格划分 变量设置与调谐优化 仿真结果 实例 微带线仿真 Ku波段微带线发夹线滤波器仿真 介质滤波器 腔体滤波器 微带一分四功 ...

  3. 【Ext.Net学习笔记】03:Ext.Net DirectEvents用法详解、DirectMethods用法详解

    Ext.Net通过DirectEvents进行服务器端异步的事件处理.[Ext.Net学习笔记]02:Ext.Net用法概览.Ext.Net MessageBus用法.Ext.Net布局 中已经简单的 ...

  4. OpenSSH后门获取root密码及防范

    OpenSSH后门获取root密码及防范 相对于Windows操作系统,Linux操作系统的密码较难获取.而很多Linux服务器都配置了Openssh服务,在获取root权限的情况下,可以通过修改或者 ...

  5. Django项目中model增加了新字段怎样更新?

    Django是不直接支持syncdb更新数据库的字段的,必须重新建立. 或者改一个表名新建一个表... 刚刚想出来一招: 自己在表上面先加一个字段,然后再在model上面改,貌似是可以的.

  6. 2014 Super Training #1 B Fix 状压DP

    原题: HDU 3362 http://acm.hdu.edu.cn/showproblem.php?pid=3362 开始准备贪心搞,结果发现太难了,一直都没做出来.后来才知道要用状压DP. 题意: ...

  7. Tsung测试openfire服务器

    环境准备 安装Tsung.安装openfire.安装Spark Tsung使用 要对openfire进行压力测试,因此我们主要讲解如何利用jabber_register.xml在openfire上面注 ...

  8. python playfair

    #########################Playfair密码######################### #约定1:若明文字母数量为奇数,在明文末尾添加一个'Z' #约定2:'I'作为 ...

  9. Android TextView中文字通过SpannableString来设置超链接、颜色、字体等属性

    在Android中,TextView是我们最常用的用来显示文本的控件. 一般情况下,TextView中的文本都是一个样式.那么如何对于TextView中各个部分的文本来设置字体,大小,颜色,样式,以及 ...

  10. C#综合揭秘——细说多线程(下)

    引言 本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发.其中委托的BeginInvoke方法以及回调函数最为常用.而 I/O线程可能 ...