I’m showing the complete code to copy and paste:
import SwiftUI
import PhotosUI
import AVKit
struct VidPlay: View {
@State private var selectedItem: PhotosPickerItem? = nil
@State var videoURL: URL? = nil
@State var videoHeight: CGFloat = 160
@State private var player: AVPlayer = AVPlayer()
var body: some View {
VStack(spacing: 20){
PhotosPicker(selection: $selectedItem, matching: .videos){
Image(systemName: "camera.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 20)
.foregroundColor(Color.white)
.padding(2)
}
.task(id: selectedItem) {
if(selectedItem != nil){
videoURL = nil
do {
if let data = try await selectedItem?.loadTransferable(type: Data.self) {
let bytes = Double(data.count)
let megabytes = bytes / (1024 * 1024)
if (megabytes > 64) {
print("too big")
} else {
let tempFile = TemporaryMediaFile(withData: data)
let asset = tempFile.avAsset
let size = try await asset?.load(.tracks).first?.load(.naturalSize)
if let duration = try? await asset!.load(.duration){
let durationTime = CMTimeGetSeconds(duration)
print(durationTime)
if(durationTime < 3 || durationTime > 300){
print("too short or too long")
}else{
videoHeight = 160 * (size!.height / size!.width)
print(videoHeight)
videoURL = tempFile.url
print("video should play")
}
//tempFile.deleteFile()
}else{
print("picking failed 2")
}
}
} else {
print("picking failed")
}
} catch {
print(error)
}
}
}
ZStack{
if(videoURL != nil){
VideoPlayer(player: player)
.frame(width: 160, height: self.$videoHeight.wrappedValue)
}
}
.onChange(of: videoURL) { _ in
if(videoURL != nil){
//player = nil
player = AVPlayer(url: videoURL!)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
player.play()
}
}else{
player.pause()
}
}
.frame(width: 240, height: 240)
.background(Color.blue)
}
}
}
class TemporaryMediaFile {
var url: URL?
init(withData: Data) {
let directory = FileManager.default.temporaryDirectory
//let fileName = "(NSUUID().uuidString).mp4"
let fileName = "temp.mp4"
let url = directory.appendingPathComponent(fileName)
do {
try withData.write(to: url)
self.url = url
} catch {
print("Error creating temporary file: (error)")
}
}
public var avAsset: AVAsset? {
if let url = self.url {
return AVAsset(url: url)
}
return nil
}
public func deleteFile() {
if let url = self.url {
do {
try FileManager.default.removeItem(at: url)
self.url = nil
} catch {
print("Error deleting temporary file: (error)")
}
}
}
deinit {
self.deleteFile()
}
}
The durationTime
and videoHeight
are correct and “video should play” gets printed out, but the video isn’t playing. How to fix this?