前言
在高仿網易新聞遇到視頻播放的問題,以前很少做多媒體這一塊,我一向的邏輯就是想弄清楚就從零開始寫。所以出于學習的目的,自己又制造了一個輪子。項目地址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-