视频播放器分析

视频播放器分析

 

       当我们进入到视频网页,点击视频播放或直接点击本地视频,会调起视频播放器。而调起的视频播放器,我们一般分为系统播放器和QB视频播放器。


    系统播放器                                                            QB播放器

 

播放器的基本功能有播放/暂停、快进/后退、音量和亮度控制、视频列表进度条等。我们对播放器的操作是如何实现的呢?答案是播放器内核。

       你可以看到系统播放器和QB播放器的界面明显不同,那是因为QB播放器采取的是自定义播放器样式。下面就针对这两种形式的播放器进行介绍。

 

一、系统播放器

       系统播放器是使用 MediaPlayer.framework中的MPMoviePlayerController 类实现的。该类实例对象可以播放本地或在线视频,使用MPMediaPlayback协议中的属性和方法实现视频的播放/暂停、快进/后退、拖动进度条操作等。下面简单描述一下播放器的实现逻辑。

1.创建播放器

 引入 MediaPlayer.framework.然后在使用到MPMoviePlayerController 的文件中导入相应的头文件。 MPMoviePlayerController 类通过一个NSURL来初始化,这个URL可以使本地的,也可以是远程的。初始化需要通过 initWithContentURL 方法来实现:   

MPMoviePlayerController *moviePlayer = [ [ MPMoviePlayerController alloc]initWithContentURL: [NSURL urlWithString:@"http://"] ];//远程 

 

NSString* path =[ NSString stringWithFormat:@"%@/Documents/video.3gp",NSHomeDirectory()];//地路径  

MPMoviePlayerController *moviePlayer = [ [ MPMoviePlayerController alloc]initWithContentURL: [NSURL fileURLWithPath:path]];//本地的 

2.设置播放器样式属性

UI实现这里不做过多描述,有兴趣的同学可以去官网查看UIViewController类。

moviePlayer.moviewControlMode = MPMovieControlModeDefault;

 

可以使用下列样式: 



 
屏幕宽高比例

moviePlayer.scallingMode = MPMovieScallingModeAspectFit;



 
3.添加通知监控媒体播放控制器状态

播放器通过使用通知来告知你的应用程序当前视频的播放状态。在何时候发送通知,如结束加载内容、技术播放、改变宽高比等。播放器会将事件发送到通知中心,你可以对其进行配置,指定将这些事件转发到你的应用程序的一个对象。要接收这些通知,需要使用 NSNotificationCenter 类,为播放器添加一个观察者(observer): 

NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];

[ notificationCenter addObserver:self selector:@selector(moviePlayerPreloadFinish:) name:MPMoviePlayerContentPreloadDidFinishNotification object:moviePlayer ];

通知会发到你指定的委托类和目标方法。通知参数让你可以知道是哪个事件触发了委托方法:

-(void)moviePlayerPreloadDidFinish:(NSNotification*)notification{ 

//添加你的处理代码}  

4.播放和停止视频

播放视频调用play 方法,播放器会自动将视图切换到电影播放器并开始播放:

[ moviePlayer play ]; 

当用户点击完成按钮,或者 stop 方法被调用都会停止:

[ moviePlayer stop ];

当电影停止播放后会自动切回播放前应用程序所在的视图。 

上述只是系统播放器的简单逻辑,想了解更多,可以去官网查看MPMoviePlayerController的常用属性和方法。

 

二、QB播放器

MPMoviePlayerController足够强大,几乎不用写几行代码就能完成一个播放器,但是正是由于它的高度封装使得要自定义这个播放器变得很复杂,甚至是不可能完成。如QB需要自定义播放器的样式,那么如果要使用MPMoviePlayerController就不合适了,而要对视频有自由的控制则AVFoundation框架是更好的选择。它更加接近于底层,所以灵活性也更强:



 
而要理解AVFoundation框架就得说到AVAssetAVAssetAVFoundation框架的主类, 是一个抽象类,理解了它的框架就理解了AVFoundation框架。

1.AVAsset

AVAsset是基于时间的视听数据(视频、音频)的抽象类。下图列出了其子类,当具体实现一个对象时,就是用到它的子类。



 

一个asset对象包含如下内容。每个AVAssetTrack分别对应asset要展示或处理的内容:音频、视频、文本、字幕。所以asset对象提供了多媒体的所有信息:字幕、时长、画面比例等。在简单的asset实例中,一个track对应音频,一个track对应视频。在复杂的asset实例中,则可能有多个音频与视频叠加的track

 

track有多个属性:类型(音频/视频)、音频/视频的特性、元数据、时间轴、格式描述数组。

 

 

2. AVPlayer

若要播放asset内容,则必须用到AVPlayer。用这个类的对象来控制asset(音频/视频)的播放,如:播放/暂停,定点播放等。使用AVPlayerItem管理asset状态,AVPlayerItemTrack管理track状态,使用AVPlayerLayer进行展示。这几个类的关系可以这么去形容。Asset可以被视为影盘、AVPlayer是放映机、AVPlayerLayer是荧幕。



 
3.播放

总的来说,asset主要有两种类型,一种是基于文件的(本地文件、媒体库),另一种是基于流媒体的(HTTP流媒体格式的在线文件)。

本地文件播放的步骤如下。

1.先通过AVPlayerLayerAVPlayer创建播放器对象包括它的UI

2. 使用 AVURLAsset创建asset对象后,创建AVPlayerItem对象并将它与AVPlayer对象联系起来。

3.当接收到AVPlayerItem的状态改变的通知时,就变为就绪播放状态了。

4.接下来的播放操作,通过SynUI来响应对应的事件。

 

在线视频的播放步骤如下。

1.利用URL来创建AVPlayerItem 对象,将实例与播放器联系起来,准备播放。

2.当准备播放时,会创建AVAsset  AVAssetTrack 对象。

3.创建监控。用来监控播放器和AVPlayerItem 对象的状态。当状态发生改变时,监控器会发送键值进行通知。此时必须通过主线程调用相关的函数来更新播放器的展示。

4.对视频进行播放操作,响应UI事件。关于视频的播放,可以查看这篇资料https://developer.apple.com/library/prerelease/ios/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html#//apple_ref/doc/uid/TP40010188-CH3-SW8

 

下面简单的说一下自定义浏览器里面的某些功能的是如何实现的。

1.播放/暂停

AVPlayer对应着两个方法playpause来实现。但是关键问题是如何判断当前视频是否在播放,通常情况下可以通过判断播放器的播放速度来获得播放状态。如果rate0说明是停止状态,1是则是正常播放状态。

2.视频的切换

AVPlayer提供了- (void)replaceCurrentItemWithPlayerItem:(AVPlayerItem *)item方法用于在不同的视频之间切换(AVFoundation内部还有一个AVQueuePlayer专门处理播放列表切换,有兴趣的朋友可以自行研究)。

3.定点播放

拖动视频时,通过手势监控,告知时间的变化。因为视频播放,播放内核会有定时器在时间发生变化的时候通知外层做进度更新。拖动完成时程序会告诉内核需要定位的时间点,实现进度条和画面同步。

 

针对下面这个bug进行分析。



 
播放进度原理

播放进度在退出播放器时会把当前的播放时间点保存到本地的数据库中,达到记录当前播放进度的目的。

 

产生原因:

因为qqv格式播放时切前后台时是会重新播放的,这时应该是读取上次播放的历史记录,然后跳到该历史播放时间点。但是原来的逻辑里面没有存这个历史记录,所以就从头开始播放了。

 

播放器原理学习后的思考:

1、该文只是简单的描述了一下播放器大概的框架,细枝末节还未弄清楚

2、此文中还存有一些描述不恰当的地方,还需要后期学习更正

3、我们在测试中发现的问题,牵扯到的是各个类中的属性或方法,每次开发的改动,相同的操作都有可能传递不同的值导致逻辑错误。

4、播放器的功能其实也就界面中看到的那些,但是这些按钮响应的事件有着多个不同的值,若要真正最大范围覆盖到播放器的所有功能,就需要了解到函数参数的意义,通过不同的操作达到传递不同的参数值。


 
 
 
 

猜你喜欢

转载自317324406.iteye.com/blog/2279060