I am new to Swift and have been using the new PhotosPicker in SwiftUI 4.0 . I am able to display selected images but not video . When I select a video I can get a few pieces of information like this below
PhotosPickerItem(_itemIdentifier: Optional("40F724uF-24M7-4523-9B2B-AD43FB2C7D71/L0/001"), _shouldExposeItemIdentifier: false, _supportedContentTypes: [<_UTCoreType 0x106c4cd60> com.apple.quicktime-movie (not dynamic, declared)], _itemProvider: <PUPhotosFileProviderItemProvider: 0x600003ea05a0> {types = ( "com.apple.quicktime-movie" )})
I am wondering if there is somehow that I can use that item identifier to load the video selected . I am been looking at different examples but none of them show videos for PhotosPicker . I have a very small project that I am testing this on, any suggestions would be great
import SwiftUI
import Combine
import PhotosUI
import AVKit
struct PlayVideoView: View {
@State private var selectedItem: [PhotosPickerItem] = []
@State private var data: Data?
@State var player = AVPlayer(url: URL(string: "https://swiftanytime-content.s3.ap-south-1.amazonaws.com/SwiftUI-Beginner/Video-Player/iMacAdvertisement.mp4")!)
var body: some View {
PhotosPicker(selection: $selectedItem,
maxSelectionCount: 1,
matching: .any(of: [.images,.videos])) {
Image(systemName: "photo")
.resizable()
.foregroundColor(.blue)
.frame(width: 24, height: 24)
.padding(.top, 5.0)
}.onChange(of: selectedItem) { newMedia in
Task {
guard let item = selectedItem.first else {
return
}
item.loadTransferable(type: Data.self) { result in
switch result {
case .success(let data):
if let data = data {
print(item) // get video url here and display in videoplayer
self.data = data
} else {
print("data is nil")
}
case .failure(let failure):
fatalError("\(failure)")
}
}
}
}
VideoPlayer(player: player) // selected video url should go here
.frame(width: 400, height: 300, alignment: .center)
}
}
struct PlayVideoView_Previews: PreviewProvider {
static var previews: some View {
PlayVideoView()
}
}
CodePudding user response:
You could try this approach, using the code from https://github.com/zunda-pixel/SamplePhotosPicker.
The Movie
code replicated here, uses the TransferRepresentation
to represent
a url from the temp file.
import Foundation
import SwiftUI
import PhotosUI
import AVKit
import CoreTransferable
// from: https://github.com/zunda-pixel/SamplePhotosPicker
struct Movie: Transferable {
let url: URL
static var transferRepresentation: some TransferRepresentation {
FileRepresentation(contentType: .movie) { movie in
SentTransferredFile(movie.url)
} importing: { receivedData in
let fileName = receivedData.file.lastPathComponent
let copy: URL = FileManager.default.temporaryDirectory.appendingPathComponent(fileName)
if FileManager.default.fileExists(atPath: copy.path) {
try FileManager.default.removeItem(at: copy)
}
try FileManager.default.copyItem(at: receivedData.file, to: copy)
return .init(url: copy)
}
}
}
struct ContentView: View {
var body: some View {
PlayVideoView()
}
}
struct PlayVideoView: View {
@State private var selectedItem: [PhotosPickerItem] = []
@State var player = AVPlayer(url: URL(string: "https://swiftanytime-content.s3.ap-south-1.amazonaws.com/SwiftUI-Beginner/Video-Player/iMacAdvertisement.mp4")!)
var body: some View {
PhotosPicker(selection: $selectedItem,
maxSelectionCount: 1,
matching: .any(of: [.images,.videos])) {
Image(systemName: "photo")
.resizable()
.foregroundColor(.blue)
.frame(width: 24, height: 24)
.padding(.top, 5.0)
}.onChange(of: selectedItem) { newMedia in
Task {
guard let item = selectedItem.first else { return }
item.loadTransferable(type: Movie.self) { result in // <-- here
switch result {
case .success(let movie):
if let movie = movie {
player = AVPlayer(url: movie.url) // <-- here
} else {
print("movie is nil")
}
case .failure(let failure):
fatalError("\(failure)")
}
}
}
}
VideoPlayer(player: player)
.frame(width: 400, height: 300, alignment: .center)
}
}