getting error when i trying to convert AVAssetURL to Data - ios

Error Domain=NSCocoaErrorDomain Code=257 "The file “IMG_9807.MOV” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/var/mobile/Media/DCIM/109APPLE/IMG_9807.MOV, NSUnderlyingError=0x1c1e5fe00 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"
i am sending asset URL to other controller and try to convert into data
PHImageManager.default().requestAVAsset(forVideo: self.albumView.phAsset, options: options) { (video, audioMix, info) in
DispatchQueue.main.async {
let urlAsset = video as! AVURLAsset
self.dismiss(animated: false, completion: {
self.delegate?.fusumaVideoCompleted(withFileURL: urlAsset.url)
})
}
}
here below methods for convert AVAssetUrl to data
do {
let data = try Data(contentsOf: product.videoURL, options: .mappedIfSafe)
return .upload(.multipart([MultipartFormData(provider: .data(data), name: "post[video]", fileName: "video.\(pathExtension)", mimeType: "video/\(pathExtension)")]))
} catch {
debugPrint(error)
}

As the error tells you, you cannot access the video file in the user's photo library by way of its URL for purposes of uploading it. You should obtain the video data and upload that. A video is very big, so you should not get the data directly and hold it in memory; instead, export the data to a file in a place that you are allowed to access, such as the Temporary folder.
To do that, you might (for example) use this method:
https://developer.apple.com/documentation/photos/phassetresourcemanager/1616280-writedata
Or this one:
https://developer.apple.com/documentation/photos/phimagemanager/1616981-requestexportsession
If you use the Mail app to email a video from your own device's photo library, you will actually see that happening; there is a pause with a progress bar while the video is exported, and then the email is constructed.

Related

How to get apple music items size downloaded from apple music library without exporting the music items?

I am trying to retrieve the size of apple music items downloaded from the apple music library as iPod-library URL (ex. ipod-library://item/item.m4a?id=8536687568586472929) but without exporting to the document directory, I am unable to get the size.
I tried the below code.
Code:
do {
let resources = try url.resourceValues(forKeys:[.fileSizeKey])
let fileSize = resources.fileSize ?? 0
print ("size \(fileSize)")
} catch {
print("Error: \(error)")
}
}
Output:
Couldn't fetch size for file The file “item.m4a” couldn’t be opened because there is no such file.
Size: 0

Swift - generating image thumbnail from a local video

I'm trying to create a Thumbnail image from a video:
func getImageFromUrl(url:URL) -> UIImage?{
print(url)
let video = AVURLAsset(url: url)
let thumbnailGenerator = AVAssetImageGenerator(asset: video)
do
{
let cgImage = try thumbnailGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
let UiImage = UIImage(cgImage: cgImage)
return UiImage
}
catch
{ print(error) }
return nil
}
and I'm getting this Error:
Error Domain=AVFoundationErrorDomain Code=-11850 "Operation Stopped" UserInfo={NSLocalizedFailureReason=The server is not correctly configured., NSLocalizedDescription=Operation Stopped, NSUnderlyingError=0x2804c50b0 {Error Domain=NSOSStatusErrorDomain Code=-12939 "(null)"}}
HELP ANYONE ?
That error tells us that this is an HTTP, not local issue. The Apple Developer Documentation says "This error might indicate that the HTTP server doesn’t support byte range requests." and or that "The HTTP server sending the media resource is not configured as expected." Check to make sure the HTTP server is configured properly and allows this type of query.
It looks like a server issue as peer apple documentation
case serverIncorrectlyConfigured = -11850
This error might indicate that the server doesn’t support byte-range requests.
You can try this video URL to check if your code actually works:
https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
Will you be able to share the video URL to check?
Also, copyCGImage is Deprecated
Try using image(at:) instead.

Share PHAsset stored in camera roll using UIActivityViewController

I'm storing images and videos in a Camera Roll album using PhotoKit, and want to allow the user to share them using UIActivityViewController. If I pass UIActivityViewController a UIImage instance, it works as expected, probably because the image data is passed in memory. However, videos need to be passed by URL because there's no video analogue to UIImage. When I pass a URL to a video, I get an error "Could not create sandbox extension". If I pass a URL to an image, I get a similar error.
Based on this, it seems as though I might be able to get around this error by exporting the assets to the Documents directory, and passing UIActivityViewController the URL to the asset in Documents. However, I've read elsewhere that the Camera Roll can serve a similar purpose, and it goes to reason that the Camera Roll would be one of the few places that can hold data for sharing between apps.
Is there a way to pass UIActivityViewController URLs to Camera Roll assets without copying them to Documents? Is there a better way to be sharing images and video that are already in Camera Roll?
Implementation Details:
I'm generating URLs for assets using this:
func videoFor(asset: PHAsset, resultHander: #escaping (AVAsset?, AVAudioMix?, [AnyHashable : Any]?) -> Void) {
imageManager.requestAVAsset(forVideo: asset, options: nil, resultHandler: resultHander)
}
func urlFor(asset: PHAsset, resultHandler: #escaping (URL?) -> Void) {
if ( asset.mediaType == .video ) {
videoFor(asset: asset) { (asset, audioMix, info) in
let asset = asset as! AVURLAsset
resultHandler(asset.url)
}
}
else if ( asset.mediaType == .image ) {
let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
asset.requestContentEditingInput(with: options, completionHandler: {(contentEditingInput: PHContentEditingInput?, info: [AnyHashable : Any]) -> Void in
resultHandler(contentEditingInput!.fullSizeImageURL as URL?)
})
}
else {
resultHandler(nil)
}
}
Here is the full error I get in console when trying to share an image by URL:
Failed to determine whether URL /var/mobile/Media/DCIM/100APPLE/IMG_0201.JPG (n) is managed by a file provider
Could not create sandbox extension. Error: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedDescription=Could not create sandbox extension of type com.apple.app-sandbox.read for URL /var/mobile/Media/DCIM/100APPLE/IMG_0201.JPG. Error: No such file or directory}
... and for a video:
Failed to determine whether URL /var/mobile/Media/DCIM/100APPLE/IMG_0202.M4V (n) is managed by a file provider
Could not create sandbox extension. Error: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedDescription=Could not create sandbox extension of type com.apple.app-sandbox.read for URL /var/mobile/Media/DCIM/100APPLE/IMG_0202.M4V. Error: Operation not permitted}
I was stuck on the same problem today. Here is my solution. Hope this helps or guides you to the right path.
PHImageManager.default().requestExportSession(forVideo: video, options: nil, exportPreset: AVAssetExportPresetPassthrough) { (exportSession, nil) in
if let exportSession = exportSession {
exportSession.outputURL = destinationURLForFile
exportSession.outputFileType = AVFileType.m4v
exportSession.exportAsynchronously() {
// Load the share sheet using destinationURLForFile
}
}
}
What this does is export the video to the provided location destinationURLForFile (i used the Documents directory. Make sure you delete the file if its already there otherwise the export MAY not work cause it may not override the file).
You can set the type based on available types. I needed m4v.
Then, export async and just call the share sheet or whatever sharing mechanism you have.

PHAsset copy video completion

I wish to copy video file from Photo Library to my app's Documents directory and wish to be notified about completion. Here is what I do:
let videoAsset = fetchResult.object(at: indexPath.item)
print(videoAsset.description)
let options = PHVideoRequestOptions()
options.version = .original
PHImageManager.default().requestAVAsset(forVideo: videoAsset, options: options) { [weak self] (avAsset, audioMix, info) in
if let avurlAsset = avAsset as? AVURLAsset {
let url = avurlAsset.url
let toUrl = //some Url
let fileManager = FileManager.default
do {
try fileManager.copyItem(at: url, to: toUrl)
} catch {
NSLog("Unable to copy file from \(url) to \(toUrl)")
}
}
}
Only problem with this approach is I have no way to be notified of completion of copyItem. What is the alternative to copyItem method (or altogether a different approach to above) that is atleast blocking till copy finishes? Is it possible to use FileHandle & read consecutive bytes and write to another file? Will that be synchronous enough?
EDIT: As pointed by Alex, copyItem is actually synchronous routine. On closer inspection, I see I sometimes get errors on copying. Not sure why the permission errors show up when it is app's Documents folder where I copy.
2018-08-27 20:30:07.485841+0530 MyProject[3577:1288452] Copying file...
2018-08-27 20:30:07.487880+0530 MyProject[3577:1288452] stat on /var/mobile/Media/DCIM/107APPLE/IMG_7915.MP4: Operation not permitted
2018-08-27 20:30:07.512994+0530
MyProject[3577:1288452] Unable to copy file from file:///var/mobile/Media/DCIM/107APPLE/IMG_7915.MP4 to file:///var/mobile/Containers/Data/Application/CC13FD5A-E4CF-42A1-931F-2F1FFE799C15/Documents/IMG-0027.mov, Error Domain=NSCocoaErrorDomain Code=513 "“IMG_7915.MP4” couldn’t be copied because you don’t have permission to access “Documents”." UserInfo=
{NSSourceFilePathErrorKey=/var/mobile/Media/DCIM/107APPLE/IMG_7915.MP4, NSUserStringVariant=(
Copy
),
NSDestinationFilePath=/var/mobile/Containers/Data/Application/CC13FD5A-E4CF-42A1-931F-2F1FFE799C15/Documents/IMG-0027.mov, NSFilePath=/var/mobile/Media/DCIM/107APPLE/IMG_7915.MP4, NSUnderlyingError=0x111c441c0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
Copyitem: Copies the item at the specified path to a new location synchronously.
Returns true if the item was copied successfully or the file manager’s delegate stopped the operation deliberately. Returns false if an error occurred.
This is a sync method so after it executed after catch without error then it means successful copied.
https://developer.apple.com/documentation/foundation/filemanager/1407903-copyitem

UIImagePickerController - Save Recorded Video to Camera Roll Error

I'm trying to save a video recorded with camera using the UIImagePickerController. I've tried two different ways, and both are not working at all.
First attempt:
if let pathURL = info["UIImagePickerControllerMediaURL"] as! URL?, mediaType == kUTTypeMovie {
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: pathURL)
}, completionHandler: { (isSuccessfull, error) in
if error != nil {
// ERROR
// error.localizedDescription value below
// "The operation couldn’t be completed. (Cocoa error -1.)"
} else if isSuccessfull {
// SUCCESS
}
})
}
On that attempt, I'm always getting the error "The operation couldn’t be completed. (Cocoa error -1.)"
Second attempt:
if let filePath = info["UIImagePickerControllerMediaURL"] as! NSURL,
let stringPath = filePath.path {
UISaveVideoAtPathToSavedPhotosAlbum(stringPath, self, #selector(Controller.videoSaved(videoPath:didFinishSavingWithError:contextInfo:)), nil)
}
This is not working either... The callback, the error is nil, but the video is not saved into the camera roll. Also, when I use the UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(stringPath), this method also returning me false all the time. I'm not able to understand why the video recorded would be incompatible to save.
I really don't know what I'm doing wrong. What am I missing? A configuration in plist?
Here's how look like the value of info["UIImagePickerControllerMediaURL"]:
file:///private/var/mobile/Containers/Data/Application/2B9BE04A-17B3-49CE-B4BA-C45F183E9A64/tmp/837294779101__C4825AFE-8140-420F-ACD0-64623C7A4753.MOV
For pictures taken with camera, PHPhotoLibrary method works very fine... It's only videos that is not able to be saved.
Not sure in 100% but I believe that it wasn't working for me because I was saving the video only after a request to my API was successful. My assumption is that the path URL is temporary and has a very short time of life. When I pass it to another controller, and make API call, it doesn't work. But if I save the video directly in the delegate method of UIImagePickerViewController, then it works fine.

Resources