I am trying to create a simple SwiftUI application using XCode 11.5 on macOS 10.15.4 using AVKit/AVFoundation to play videos stored on the local file system. I would like to be able to select the movie based on a file path determined by the user's actions (e.g. selecting from a series of menu options).
I am working from a code snippet found here: 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)
}
}
This works perfectly well for selecting a file using the "panel" object, but I can't figure out the simple change of passing my own value of "url" to videoItem.open().
I have tried replacing the block:
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)
}
}
, defining my value of "url" using URL(string:) or Bundle.main.url(forResource:, withExtension: ) or other options without any success. The application compiles and runs without error, but it does not display the video, only a placeholder image indicating that the file was not found.
I don't understand what the difference is between the value of "url" returned from panel.url and the values that I am manually assigning. I've checked the contents of panel.url using .absoluteString and this matches exactly the values which I am manually assigning.
I am surely missing something very obvious but I can't see what it is. Please, can anybody provide some help?