I have a video chat messaging app using AVFoundation
and Firebase
to record, store, and playback 1 minute-length videos.
Everything works accordingly, but there is a...
- Delay in playing a fetched video
- Delay in uploading a recorded video, especially long here
Ideally...
- It'd be nice to "pre-load" a fetched video to play immediately on command, but it doesn't seem possible with
AVPlayer
where the loading and play happen only when the method.play()
is invoked. - Would simultaneously uploading while the actual recording is taking place be something that's even possible? Or, does
Firebase Storage
work where once the network call to upload the video is first triggered, the app can enter the background and still complete?
I am admittedly a complete beginner in managing videos and I haven't found any concrete guides on how to eliminate or optimize the reduction of the delay for a better UX (i.e. Instagram playing and uploading an Instagram video story). Any help would be appreciated..
func playVideo(with outputFileURL: URL) {
DispatchQueue.main.async {
self.setView(view: self.progressBar, hidden: true)
self.progressBar.progress = 0
let asset = AVAsset(url: outputFileURL)
let item = AVPlayerItem(asset: asset)
self.avPlayer.replaceCurrentItem(with: item)
let previewLayer = AVPlayerLayer(player: self.avPlayer)
previewLayer.frame = self.view.bounds
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.previewView.layer.addSublayer(previewLayer)
self.view.layoutIfNeeded()
self.avPlayer.play()
}
}
func uploadVideo(_ url: URL) {
let filename = "x"
let ref = Storage.storage().reference().child("videos").child("xyz").child(filename)
let uploadTask = ref.putFile(from: url, metadata: nil, completion: { (_, err) in
if let err = err {
print("Failed to upload movie:", err)
return
}
ref.downloadURL(completion: { (downloadUrl, err) in
if let err = err {
print("Failed to get download url:", err)
return
}
guard let downloadUrl = downloadUrl else { return }
if let thumbnailImage = self.thumbnailImageForFileUrl(url) {
self.uploadToFirebaseStorageUsingImage(thumbnailImage, completion: { (imageUrl) in
print("saved video url: \(downloadUrl) and saved image url: \(imageUrl)")
})
}
})
})
uploadTask.observe(.progress) { (snapshot) in
print("In Progress")
}
uploadTask.observe(.success) { (snapshot) in
print("Done")
}
}
func thumbnailImageForFileUrl(_ fileUrl: URL) -> UIImage? {
let asset = AVAsset(url: fileUrl)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
do {
let thumbnailCGImage = try imageGenerator.copyCGImage(at: CMTimeMake(value: 2, timescale: 60), actualTime: nil)
return UIImage(cgImage: thumbnailCGImage)
} catch let err {
print(err)
}
return nil
}