Reputation: 780
I'm retrieving the URL (file:///var/mobile/Media/DCIM/100APPLE/IMG_0840.MOV) from PHAsset object and am able to replay the video fine on the device. However, when it comes time to upload/putfile on Firebase Storage, I don't even get my completionHandler back.
//requesting url from asset
PHImageManager.default().requestAVAsset(forVideo: asset, options: options, resultHandler: { (videoAsset, audioMix, info) in
if let assetURL = videoAsset as? AVURLAsset {
let url = assetURL.url
//upload from url
let storageRef = Storage.storage().reference().child("videos").child("\(memory.ID!)")
let uploadMetaData = StorageMetadata()
uploadMetaData.contentType = "video/quicktime"
self.storageRef.putFile(from: url, metadata: uploadMetaData) { (metaData, error) in
if error != nil {
print(error!.localizedDescription)
}
}
If I'm uploading an .mp4 file from AVFoundation capture with a local url like this, (file:///var/mobile/Containers/Data/Application/209BB017-13C7-4432-AFE4-EC3A13469900/Documents/ff49bbc9ac794ed28d6f25944f128933.mp4), it works fine.
I've also tried uploading an .MOV file on the Firebase Storage console and that also works.
Thanks
Upvotes: 0
Views: 999
Reputation: 278
Sometimes PHAssets does not returns us with a URLAsset so we must check whether the given Asset is an AVURLAsset and if not we must save this asset in our documents directory and then obtain the url from documents directory.
func uploadVideoToFirebase(content: PHAsset) {
let options = PHVideoRequestOptions()
options.isNetworkAccessAllowed = true
PHImageManager.default().requestAVAsset(forVideo: content, options: options) { (asset, mix, args) in
if let asset = asset as? AVURLAsset {
let url = asset.url
// URL OF THE VIDEO IS GOT HERE
} else {
guard let asset = asset else {return}
self.startAnimating(message: "Processing.")
self.saveVideoInDocumentsDirectory(withAsset: asset, completion: { (url, error) in
if let error = error {
print(error.localizedDescription)
}
if let url = url {
// SAVED IN DOCUMENTS DIRECTORY AND URL IS GOT HERE
}
})
}
}
}
Saving into Documents Directory:
func saveVideoInDocumentsDirectory(withAsset asset: AVAsset, completion: @escaping (_ url: URL?,_ error: Error?) -> Void) {
let manager = FileManager.default
guard let documentDirectory = try? manager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) else {return}
var outputURL = documentDirectory.appendingPathComponent("output")
do {
try manager.createDirectory(at: outputURL, withIntermediateDirectories: true, attributes: nil)
let name = NSUUID().uuidString
outputURL = outputURL.appendingPathComponent("\(name).mp4")
}catch let error {
print(error.localizedDescription)
}
//Remove existing file
_ = try? manager.removeItem(at: outputURL)
guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality) else {return}
exportSession.outputURL = outputURL
exportSession.outputFileType = AVFileTypeMPEG4
exportSession.exportAsynchronously {
switch exportSession.status {
case .completed:
print("exported at \(outputURL)")
completion(outputURL, exportSession.error)
case .failed:
print("failed \(exportSession.error?.localizedDescription ?? "")")
completion(nil, exportSession.error)
case .cancelled:
print("cancelled \(exportSession.error?.localizedDescription ?? "")")
completion(nil, exportSession.error)
default: break
}
}
}
We have to clear this unwanted video after successfull upload or clear it during the next app launch. I cleared it at the next app Launch using this method.
func clearDocumentsDirectory() {
let manager = FileManager.default
guard let documentDirectory = try? manager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) else {return}
let outputURL = documentDirectory.appendingPathComponent("output")
//Remove existing file
_ = try? manager.removeItem(at: outputURL)
}
Hope this helps.
Upvotes: 1