前言
在高仿网易新闻遇到视频播放的问题,以前很少做多媒体这一块,我一向的逻辑就是想弄清楚就从零开始写。所以出于学习的目的,自己又制造了一个轮子。项目地址WLVideoPlayer-MP-, 花很大的心思加强复用性。具体效果如下。
准备
为了方便新同学学习多媒体视频播放的相关内容,已经把每一个步骤都打包成一个单独的工程
当然,你也完全可以从Github上clone整个项目。
WLVideoPlayer的使用
playingPlayerView = WLVideoPlayerView(url: NSURL(string: urlStr)!)
playingPlayerView?.customControlView = controlView //你需要的控制面板
playingPlayerView?.placeholderView = UIImageView(image: UIImage(named: "placeholder")) // 视频加载时的等待图片
playingPlayerView?.playInView(inView) // 播放
WLVideoPlayer提供了默认的视频控制面板,如果你想使用自己的,只需要继承自WLBasePlayerControlView并根据WLPlayerControlViewDelegate协议调用你想实现功能的相应代理方法即可。你所做的只有布局你的自定义控制面板。
功能分析
苹果提供的MPMoviePlayerController功能已经很完善了,那为什么还要要自定义视频播放器?弄清这一点,我们才能知道我们自定义视频播放器的的目的。
- 最直接的无非就是控制面板的问题,视频控制面板太丑,上面很多控件是用不着的。
- 支持的播放格式少
而又因为播放格式的问题涉及到视频文件的解码,这个对于不是学习视频算法的我们太过于牵强(虽然有VLC)。所以我们自定义视频播放器的的任务已经很明显了。
- 能支持自定义视频控制面板
- 视频播放\停止\拖拽快进等基本功能
- 视频全屏与屏幕旋转问题的解决
其中我认为最重要的便是能支持自定义视频控制面板,它决定了你的这个小播放器能不能重复使用
代码简析
这是播放器主体代码,其他的部分都是测试用的数据源,是从作者另外一个开源项目高仿网易新闻中分离出来。具体实现不需要太过于关心。因为代码中加了大量的注释,所以只简单介绍一下重要的一些代码片段。
WLVideoPlayerView.swift
外接都是通过直接操作这个类来控制视频播放器的行为。
var contentURL: NSURL?
var placeholderView: UIView?
/// 用户自定义控制界面
var customControlView: WLBasePlayerControlView?
/// 用户自定义视频控制面板自动隐藏的时间
var customControlViewAutoHiddenInterval: NSTimeInterval
/// 进入全屏的模式
var fullscreenModel: WLVideoPlayerViewFullscreenModel
这些都是暴露出来提供外部来设置播放器的一些属性,其中值得一提的便是customControlView这个的属性。这便是我们的视频控制器视图了,当初在设计的时候十分头疼,原本应该是这样,这个customControlView必须是UIView的子类,而且他也必须遵守我设置的一系列协议规范。但是很可惜我没有发现swift中有类似于oc这样的写法
UIView<someProtocol> *customControlView
于是我在妥协之下,只能使用继承这种不太优雅的方式解决。设计了一个类似于抽象类的WLBasePlayerControlView
接下来是一堆私有属性,其中需要主要的是
lazy var playerControlHandler: WLPlayerHandler = WLPlayerHandler()
这个对象的功能是处理视频控制器的事件,比如暂停、快进、全屏等事件。设计这样一个对象的目的是为了将视频控制器的事件于播放事件进行分离,减少WLVideoPlayerView.swift的代码量。
然后值得一提的便是几个全屏\旋转的控制方法
func toLandscape(angle: CGFloat)
func toPortrait()
func enterFullscreen
func exitFullscreen()
func changePlayerScreenState
因为iPhone手机应用一般都会禁止项目的旋转,一般只会支持Portrait这一个方向,然而我们往往是希望当手机横屏播放视频的时候,视频内容能够铺满全屏。在这样的需求下,系统自带的setFullscreen方法是不好使的。所以只能自己实现放大、缩小、旋转的方法。当发生全屏、退出全屏、旋转等事件时,对播放器视图、控制面板视图进行处理。因为视频控制面板又是用户自定义的,几乎都是使用autolayout进行布局,所以在必须更新相应的约束。
WLPlayerHandler.swift
这个文件主要是WLPlayerHandler类的实现,之间也解释了,WLPlayerHandler是为了将视频控制面板的逻辑与视频播放本身逻辑进行分离而设计的一个类。WLPlayerHandler主要处理用户自定义控制面板的一些事件,比如:暂停按钮点击、全屏按钮的点击、进度条拖拽等
weak var player: MPMoviePlayerController!
weak var customControlView: WLBasePlayerControlView!
这里使用weak关键字是为了防止WLVideoPlayerView的实例对象与WLPlayerHandler实例对象造成循环引用。
WLBasePlayerControlView.swift
这个文件里面定义了WLPlayerControlViewDelegate代理协议与WLBasePlayerControlView类,这样是妥协的设计办法,暂时因为作者能力有限没找到更加优雅实现方式。WLBasePlayerControlView类是所有自定义视频控制面板的基类,如果想实现你自己的播放面板,你得继承自这个类,并通过delegate属性调用WLPlayerControlViewDelegate协议提供的方法来处理你面板上的事件。
PlayerControlView.swift和PlayerDemoControlView.swift
这两个文件是提供给大家参考的视频控制面板的实现方式,PlayerControlView是用xib进行布局,而PlayerDemoControlView.swift是使用SnapKit进行布局。参照这两个的实现方式,完全可以自定义你专属的视频控制面板。
PlayerControlViewAuxiliary.swift
这里面定义的是UpdateProgressProtocol协议以及提供的默认实现,也是提供给自定义视频控制面板使用的
总结
在实现WLVideoPlayer这个轮子的过程中,发现如果不涉及对视频的解码,自定义一个播放器的过程也就是自定义它的视频控制面板的过程。而对于视频播放的逻辑处理(如快进、全屏等)各个播放器基本都是一样的。不同的仅仅在于视频控制面板的样式不同。正因为这一特征,我才将视频控制面板逻辑处理与视图布局分离。这样,我只需要写一次通用的逻辑处理方式,以后再根据不同的需求设计不同控制面板即可。这样这个轮子造的才有意义。如果你是新手,您根据我开发工程的步骤,对代码重构的过程,应该会有理解。如果您有更好的建议或者意见,欢迎您的指出。
后续工作
这个轮子已经具备的一个简单播放器的基本功能,但任然有很多的功能可以添加,日后将不断对这个项目进行完善、对代码质量进行提高。不过MPMoviePlayerController这个类苹果已经不建议我们使用了,所以以后应该还会使用AVPlayer开发一个类似的播放器。最后再次附上本项目地址WLVideoPlayer-MP-