利用 SwiftUI Video Player 在影片實時套用 Core Image 濾鏡!


本篇原文(標題:SwiftUI Video Player Real-Time Processing With Core Image)刊登於作者 Medium,由 Anupam Chugh 所著,並授權翻譯及轉載。

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 的影片:

swiftui-video-player-1

你可以添加更多濾鏡,並設定 Slider 控件來控制濾鏡強度。如果網絡連接良好的話,添加遠程影片 URL 與使用本地視頻 URL 一樣流暢。

總結

你可以在 GitHub 儲存庫 下載這個 SwiftUI App 的完整程式碼。

有了 SwiftUI Video Player,我們可以應用很多很酷的效果,像是套用風格轉換。

本篇文章到此為止,謝謝你的閱讀。

本篇原文(標題:SwiftUI Video Player Real-Time Processing With Core Image)刊登於作者 Medium,由 Anupam Chugh 所著,並授權翻譯及轉載。

作者簡介:Anupam Chugh,深入探索 ML 及 AR 的 iOS Developer。喜愛撰寫關於想法、科技、與程式碼的文章。歡迎到我的 Blog 閱讀更多文章,或在 LinkedIn 上關注我。

譯者簡介:Kelly Chan-AppCoda 編輯小姐。


此文章為客座或轉載文章,由作者授權刊登,AppCoda編輯團隊編輯。有關文章詳情,請參考文首或文末的簡介。

blog comments powered by Disqus
Shares
Share This