【问题标题】:Playing local video files in macOS SwiftUI application using AVPlayer使用 AVPlayer 在 macOS SwiftUI 应用程序中播放本地视频文件
【发布时间】:2020-09-17 15:28:06
【问题描述】:

我正在尝试使用 AVKit/AVFoundation 在 macOS 10.15.4 上使用 XCode 11.5 创建一个简单的 SwiftUI 应用程序,以播放存储在本地文件系统上的视频。我希望能够根据用户操作(例如从一系列菜单选项中选择)确定的文件路径来选择电影。

我正在使用此处找到的代码 sn-p:https://qiita.com/croquette0212/items/eb97e970d1dcfa2932fd

import SwiftUI
import AVKit
import AVFoundation

class VideoItem: ObservableObject {
    @Published var player: AVPlayer = AVPlayer()
    @Published var playerItem: AVPlayerItem?

    func open(_ url: URL) {
        let asset = AVAsset(url: url)
        let playerItem = AVPlayerItem(asset: asset)
        self.playerItem = playerItem
        player.replaceCurrentItem(with: playerItem)
    }
}

struct PlayerView: NSViewRepresentable {
    @Binding var player: AVPlayer

    func updateNSView(_ NSView: NSView, context: NSViewRepresentableContext<PlayerView>) {
        guard let view = NSView as? AVPlayerView else {
            debugPrint("unexpected view")
            return
        }

        view.player = player
    }

    func makeNSView(context: Context) -> NSView {
        return AVPlayerView(frame: .zero)
    }
}


struct ContentView: View {
    @ObservedObject var videoItem: VideoItem = VideoItem()

    var body: some View {
        VStack {
            if videoItem.playerItem != nil {
                PlayerView(player: $videoItem.player)
            }
            Button(action: {
                let panel = NSOpenPanel()
                panel.allowedFileTypes = [kUTTypeMovie as String]
                DispatchQueue.main.async {
                    if panel.runModal() == .OK {
                        guard let url = panel.url else {
                            return
                        }
                        self.videoItem.open(url)
                    }
                }
            }) {
                Text("Open")
            }
        }.frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

这非常适合使用“面板”对象选择文件,但我无法弄清楚将我自己的“url”值传递给 videoItem.open() 的简单更改。

我已经尝试替换块:

let panel = NSOpenPanel()
panel.allowedFileTypes = [kUTTypeMovie as String]
DispatchQueue.main.async {
    if panel.runModal() == .OK {
        guard let url = panel.url else {
           return
        }
        self.videoItem.open(url)
    }
}

,使用 URL(string:) 或 Bundle.main.url(forResource:, withExtension: ) 或其他选项定义我的“url”值,但没有成功。应用程序编译并运行没有错误,但它不显示视频,只显示一个占位符图像,指示未找到文件。

我不明白从 panel.url 返回的“url”值与我手动分配的值之间有什么区别。我已经使用 .absoluteString 检查了 panel.url 的内容,这与我手动分配的值完全匹配。

我肯定遗漏了一些非常明显的东西,但我看不出它是什么。请问,有人可以帮忙吗?

【问题讨论】:

    标签: xcode macos swiftui avplayer avkit


    【解决方案1】:

    此问题的简单解决方案:确保视频文件与目标应用程序捆绑在一起。

    我以为我这样做了,但显然不是,检查(XCode 11)的方法是:

    • 在 Project Navigator 窗口中单击视频文件,然后,

    • 勾选文件中目标应用程序旁边的目标成员资格框
      检查窗口

    就是这样。这个答案的功劳属于https://github.com/SergioEstevao/,他有一个适用于 SwiftUI 应用程序的 AVPlayer 解决方案:https://github.com/SergioEstevao/SVEVideoUI 这正是我想要的。

    【讨论】:

    • 继续并接受您自己的答案。它发生在我们所有人身上。一个工作应用程序有很多移动部件!很高兴你明白了。