Chris
Chris

Reputation: 312

Playing and Storing Videos From/To Firebase

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...

  1. Delay in playing a fetched video
  2. Delay in uploading a recorded video, especially long here

Ideally...

  1. 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.
  2. 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
}

Upvotes: 1

Views: 172

Answers (1)

Chris
Chris

Reputation: 312

As a temporary workaround, I looked into compressing the file.

The upload is much faster, but the quality is worse, which ideally should not have to be compromised.

If anyone has a better solution, would really appreciate and love to hear it!

Upvotes: 0

Related Questions