iOS 14 的 SwiftUI 引入了播放影像檔案的原生支援。我們可以利用
新的 VideoPlayer
控件,從 URLs 或本地資源中播放影像檔案。
你只需要 import AVKit
,並如此傳遞 AVPlayer
實例即可:
VideoPlayer(player: AVPlayer(url: enter_url_here)
雖然 Video Player 在裝置上運作得很好,但在模擬器上可能會出問題,尤其是從網站 URL 載入中的時候。
你也可以添加客製化的疊加 (Overlay) SwiftUI 視圖到 Video Player 中。在寫這篇文章的時候,我們一定要使用預設的 Playback 控件來添加。
請注意,YouTube 的 URLs 無法在 AVPlayer
上運作,因為它們本來就是影像檔案。
Video Player 讓我們可以在純 SwiftUI App 中做影片處理,也就是說,你只需要少於 50 行程式碼,就可以寫出一個以 AI 為基礎的智能 Video Player。
在下一個部分,我們會看看如何在 Video Player 套用濾鏡,並實作一組 Core Image 濾鏡,以實時套用於影像檔案中。
如何在 SwiftUI 的 Video Player 存取影片幀
要從 AV Player 存取影片幀,最常見的方法是利用 AVPlayerItemVideoOutput
。為此,我們通常會利用 CADisplayLink
計時器,以在一定的時間間隔後獲取影片幀。
但 CADisplayLink
並不支援 SwiftUI 的原生監聽器 (listener)。而且,如果不將 UIKit 引入,用於監聽更改的選擇器就無法操作。
因此,我們唯有選擇另一個選項:AVVideoComposition
。
AVVideoComposition
包含每張幀的像素緩衝 (pixel buffer)。我們在 AVPlayerItem
屬性上設定好後,就可以檢索幀並套用 CIFilter
,來賦予影片一個完全不同的外觀。
在 SwiftUI 套用CIFilter 到影片串流
讓我們來建立一個新的 SwiftUI 專案,並加入以下的內容:
import SwiftUI
import AVKit
import CoreImage
import CoreImage.CIFilterBuiltins
struct ContentView: View {
@State private var currentFilter = 0
var filters : [CIFilter?] = [nil, CIFilter.sepiaTone(), CIFilter.pixellate(), CIFilter.comicEffect()]
let player = AVPlayer(url: Bundle.main.url(forResource: "tennis", withExtension: "mp4")!)
var body: some View {
VStack{
VideoPlayer(player: player)
.onAppear{
player.currentItem!.videoComposition = AVVideoComposition(asset: player.currentItem!.asset, applyingCIFiltersWithHandler: { request in
if let filter = self.filters[currentFilter]{
let source = request.sourceImage.clampedToExtent()
filter.setValue(source, forKey: kCIInputImageKey)
if filter.inputKeys.contains(kCIInputScaleKey){
filter.setValue(30, forKey: kCIInputScaleKey)
}
let output = filter.outputImage!.cropped(to: request.sourceImage.extent)
request.finish(with: output, context: nil)
}
else{
request.finish(with: request.sourceImage, context: nil)
}
})
}
Picker(selection: $currentFilter, label: Text("Select Filter")) {
ForEach(0..<filters.count) { index in
Text(self.filters[index]?.name ?? "None").tag(index)
}
}.pickerStyle(SegmentedPickerStyle())
Text("Value: \(self.filters[currentFilter]?.name ?? "None")")
}
}
}
以上這段程式碼主要有兩件事情發生:
AVPlayerItem
包含videoComposition
屬性,我們利用這個屬性設定AVVideoComposition
的實例。在AVVideoComposition
中,我們會傳遞AVAsset
型別的media
屬性。applyingCIFiltersWithHandler
是對每張幀進行圖像處理的地方。我們設定把sourceImage
傳遞到現時選擇了的CIFilter
(從SegmentedControl
中選取)。
在本地 Video player 執行這個 App 後,就會得到套用了 4 個 CIFilters
的影片:
你可以添加更多濾鏡,並設定 Slider 控件來控制濾鏡強度。如果網絡連接良好的話,添加遠程影片 URL 與使用本地視頻 URL 一樣流暢。
總結
你可以在 GitHub 儲存庫 下載這個 SwiftUI App 的完整程式碼。
有了 SwiftUI Video Player,我們可以應用很多很酷的效果,像是套用風格轉換。
本篇文章到此為止,謝謝你的閱讀。