簡體   English   中英

如何使用Swift Concurrency加載AVQueuePlayer?

[英]How to use Swift Concurrency to load AVQueuePlayer?

我有大約 200 個音頻資產,每個資產大約 5 秒,它們被加載到AVQueuePlayer中。 我這樣做是為了將所有資產作為一首完整的歌曲播放,但允許用戶查看或跳轉到特定的詩句。

問題是當我像這樣加載它們時主線程被鎖定:

let items = urls
    .map(AVAsset.init)
    .map(AVPlayerItem.init)

let player = AVQueuePlayer(items: items)

然后我發現我必須將它們異步加載到播放器中,所以嘗試了這樣的事情:

let items = urls
    .map(AVAsset.init)
    .map(AVPlayerItem.init)

let player = AVQueuePlayer()

// Below does NOT compile!!
await withThrowingTaskGroup(of: Void.self) { group in
    for var item in items {
        group.addTask { _ = try await item.asset.load(.duration) }
        for try await result in group {
            player?.insert(item, after: nil)
        }
    }
}

我只支持 iOS 16+,所以我正在嘗試使用AVFoundation中可用的新 Swift 並發 API。 我試着按照這個文件,但有很多我無法完全理解的差距。 在不鎖定主線程的情況下將那么多資產加載到隊列播放器中的正確方法是什么?

這樣的事情怎么樣?

import AVFoundation

let items = [URL(string: "https://google.com")!]

let player = AVQueuePlayer()

try await withThrowingTaskGroup(of: AVPlayerItem.self) { group in
    for item in items {
        group.addTask {
            AVPlayerItem(asset: AVAsset(url: item))
        }
    }
    
    for try await item in group {
        player.insert(item, after: nil)
        print(item)
    }
}

由於您似乎正試圖直接影響itemsplayer ,所以我會使用actor 將所有內容保持在一起並保持同步。

要繞過captured var 'item' in concurrently-executing code您可以使用.enumerated()

actor PlayerLoader{
    let items = [URL(string: "https://v.ftcdn.net/01/53/82/41/700_F_153824165_dN7n9QftImnClb7z1IJIjbLgLlkHyYDS_ST.mp4")!]
        .map(AVAsset.init)
        .map(AVPlayerItem.init)
    
    let player = AVQueuePlayer()
    
    func loadItems() async throws{
        try await withThrowingTaskGroup(of: Void.self) { group in
            for (idx, _) in items.enumerated() {
                group.addTask { [weak self] in
                    _ = try await self?.items[idx].asset.load(.duration)
                }
                for try await _ in group {
                    player.insert(items[idx], after: nil)
                }
            }
        }
    }
}

然后只需使用TaskTask.detached調用loadItems

let loader = PlayerLoader()

let task = Task{ //or Task.detached   depending on where you will be calling this line of code
    do{
        try await loader.loadItems()
        print("total number of items loaded \(loader.player.items().count)")
    }catch{
        print(error)
        throw error
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM