BiliBili(簡稱B站),想必大家都不陌生。Ijkplayer 架構是B站提供了一個開源的流媒體解決方案,整合了 ffmpeg,還支援硬解碼(需 iOS8 以上版本)。使用 Ijkplayer 架構我們可以很方便地實現ApsaraVideo for Live功能(Http/RTMP/RTSP 這幾種直播源都支援)。
本文主要介紹如何使用 Ijkplayer 架構播放線上直播視頻(當然其本地播放能力也很強大)。對於幾種直播流不太清楚地,可以參考我前面寫的這篇文章:RTMP、RTSP、HTTP視頻協議詳解(附:直播流地址、播放軟體)
一,環境部署
在使用 Ijkplayer 前,我們需要先搭建運行環境。
1,在“終端”中運行如下命令,安裝homebrew, git, yasm等環境。
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install git
brew install yasm
2,將Ijkplayer項目下載到本地
GitHub地址:https://github.com/Bilibili/ijkplayer
或者在“終端”中使用 git 命令下載到本地:
1
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-ios
3,將ffmpeg整合到ijkplayer中
運行如下命令,進入專案檔夾並整合 ffmpeg。
cd ijkplayer-ios
git checkout -B latest k0.6.0
./init-ios.sh
cd ios
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
二、運行範例
Ijkplayer 工程目錄中內建了一個 demo 範例,我們可以先運行下看看效果。
1,開啟ios檔案夾下的IJKMediaDemo工程
2,運行後介面如下
可以選擇播放本地檔案,或者輸入視頻地址來播放。同時 demo 中還內建了一些視頻源,可以直接點擊播放。
3,在Input URL頁面中輸入視頻地址即可播放
不過程式預設做了限制,只能播放 http/https 視頻流。
我們這裡可以修改下,放開限制。讓其也能支援其它協議視頻播放(比如 RTMP 協議)。
將 IJKDemoInputURLViewController.m 中的相關判斷給注釋掉即可。
1
//if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
[IJKVideoViewController presentFromViewController:self withTitle:[NSString stringWithFormat:@"URL: %@", url] URL:url completion:^{
// [self.navigationController popViewControllerAnimated:NO];
}];
//}
三、將Ijkplayer整合到我們的項目中來
下面我們通過一個範例示範在我們項目中如何通過 ijkplayer 來播放視頻流。官方提供的 demo 用的是 OC,這裡我使用 Swift 來實現。
1,製作framework
首先我們要將 IJKMediaPlayer 編譯成 framework,這樣不僅體積小,而且使用起來也更加方便。
(1)開啟 IJKMediaPlayer.xcodeproj(ios/IJKMediaPlayer 檔案夾下)
(2)點擊 IJKMediaFramework 出現選擇框,選擇 edit scheme
(3)將 build configuration 改為 Release
(4)分別在模擬器和真機(Generic iOS Device 也可以)上編譯
(5)我們開啟產生 framework 的目錄
(6)可以看到這裡產生了兩個 framework。看名字就知道一個是給模擬器使用,一個是給真機使用。這個根據個人的運行需求選擇對應的 framework。
原文:Swift - 使用ijkplayer架構播放直播視頻1(RTMP/HTTP視頻流播放)
(7)當然如果在開發階段,真機模擬器都需要調試這樣切來切去就太麻煩了。我們將兩個 framework 合并,這樣就可以同時在真機和模擬器上調試了。
我們進入 Products 目錄,輸入如下 lipo 命令將二者合并輸出:
1
lipo -create Release-iphoneos/IJKMediaFramework.framework/IJKMediaFramework Release-iphonesimulator/IJKMediaFramework.framework/IJKMediaFramework -output IJKMediaFramework
(8)接著將合并後的 framework 拷貝到 Release-iphoneos/IJKMediaFramework.framework 中
1
cp IJKMediaFramework Release-iphoneos/IJKMediaFramework.framework/
(9)我們可以通過 lipo -info IJKMediaFramework 命令查看 framework 支援情況。可看到現在這個真機、模擬器都是支援的。
原文:Swift - 使用ijkplayer架構播放直播視頻1(RTMP/HTTP視頻流播放)
2,項目配置
(1)我們將前面製作好的 framework(Release-iphoneos/IJKMediaFramework.framework)添加到我們項目中來。
(2)接著添加一些依賴的動態庫。
AudioToolbox.framework
AVFoundation.framework
CoreGraphics.framework
CoreMedia.framework
CoreVideo.framework
libbz2.tbd
libz.tbd
MediaPlayer.framework
MobileCoreServices.framework
OpenGLES.framework
QuartzCore.framework
UIKit.framework
VideoToolbox.framework
原文:Swift - 使用ijkplayer架構播放直播視頻1(RTMP/HTTP視頻流播放)
四、測試範例
項目配置完畢後,接下來寫一個簡單的範例示範如何使用 ijkplayer。
1,範例效果圖
程式啟動後會自動播放一個採用 RTMP 協議的直播,並全螢幕顯示。
原文:Swift - 使用ijkplayer架構播放直播視頻1(RTMP/HTTP視頻流播放)
同時播放視圖會自適應手機橫、豎兩種狀態。
原文:Swift - 使用ijkplayer架構播放直播視頻1(RTMP/HTTP視頻流播放)
2,範例代碼
import UIKit
import IJKMediaFramework
class ViewController: UIViewController {
var player:IJKFFMoviePlayerController!
override func viewDidLoad() {
super.viewDidLoad()
let options = IJKFFOptions.optionsByDefault()
//視頻源地址
let url = NSURL(string: "rtmp://live.hkstv.hk.lxdns.com/live/hks")
//let url = NSURL(string: "http://live.hkstv.hk.lxdns.com/live/hks/playlist.m3u8")
//初始化播放器,播放線上視頻或直播(RTMP)
let player = IJKFFMoviePlayerController(contentURL: url, withOptions: options)
//播放整頁模式寬高自適應
let autoresize = UIViewAutoresizing.FlexibleWidth.rawValue |
UIViewAutoresizing.FlexibleHeight.rawValue
player.view.autoresizingMask = UIViewAutoresizing(rawValue: autoresize)
player.view.frame = self.view.bounds
player.scalingMode = .AspectFit //縮放模式
player.shouldAutoplay = true //開啟自動播放
self.view.autoresizesSubviews = true
self.view.addSubview(player.view)
self.player = player
}
override func viewWillAppear(animated: Bool) {
//開始播放
self.player.prepareToPlay()
}
override func viewWillDisappear(animated: Bool) {
//關閉播放器
self.player.shutdown()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}