I am using the ctAssetPickerController for Picking videos and images. After the user has finished picking videos and images I want to copy them to another folder. I am using the export session and requestAvAssetForVideo method but the problem is it copies only one file at a time and I am not able to get the name of the file that the user is selecting, and it is copying videos only. How do I copy the images also? Below is my code.
- (void)assetsPickerController:(CTAssetsPickerController *)picker didFinishPickingAssets:(NSArray *)assets
{
PHImageManager *manager = [PHImageManager defaultManager];
[manager requestAVAssetForVideo:obj options:PHVideoRequestOptionsDeliveryModeAutomatic resultHandler:^(AVAsset * asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
NSString *imageName = #"img_o462.mp4";
NSString *selectedFilesCopyPath = [[self getRootFolderPath] stringByAppendingString:#"/Photos"];
if (![[NSFileManager defaultManager]fileExistsAtPath:selectedFilesCopyPath]) {
[[NSFileManager defaultManager]createDirectoryAtPath:selectedFilesCopyPath withIntermediateDirectories:NO attributes:nil error:nil];
}
NSString *copyPath = [selectedFilesCopyPath stringByAppendingString:[NSString stringWithFormat:#"/%#",imageName]];
// NSError *copyError= nil;
exporter.outputURL = [NSURL fileURLWithPath:copyPath];
exporter.outputFileType = AVFileTypeMPEG4;
[exporter exportAsynchronouslyWithCompletionHandler:^{
// here your file will be saved into file system at specified exportUrl
NSLog(#"file copied");
if (exporter.status == AVAssetExportSessionStatusCompleted) {
NSLog(#"success");
[self showErrorAlert:#"Success"];
} else {
NSLog(#"error: %#", [exporter error]);
[self showErrorAlert:exporter.error];
}
}];
}];
}
Related
I recorded a video in 120FPS. It is SLOW_Mo video. IF I export that video in CameraRoll using PHImageManager. Everything is ok like as VIDEO Effect is slow_mo. I can play it using QuickPlayer and AVPlayer and effect is 120FPS.
This is my working code:
PHAsset *oneVideo = [[PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeVideo options:nil] lastObject];
PHVideoRequestOptions *options = [PHVideoRequestOptions new];
options.networkAccessAllowed = YES;
options.version = PHVideoRequestOptionsVersionCurrent;
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
[[PHImageManager defaultManager] requestAVAssetForVideo:oneVideo options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {
if(([asset isKindOfClass:[AVComposition class]])){
BOOL bResult = FALSE;
DebugLog(#"\navPlayer.outputFileURL.absoluteString:%#", URl);
bResult = [[NSFileManager defaultManager] removeItemAtURL:URl error:nil];
DebugLog(#"\nremoveItemAtPath:%d", bResult);
//Begin slow mo video export
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL = avPlayer.outputFileURL;
// exporter.outputURL = urlFirstVideoPath;
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
[exporter exportAsynchronouslyWithCompletionHandler:^{
NSLog(#"Video test run exported video into file: %#", exporter.outputURL);
NSLog(#"exportSession.status: %ld", (long)exporter.status);
dispatch_async(dispatch_get_main_queue(), ^{
if (exporter.status == AVAssetExportSessionStatusCompleted) {
NSLog(#"exportSession.status: okkkkkkk");
}
});
}];
}
}];
NOW I don't want to save that video in CAMERAROLL. I saved video in Document folder. and get AVAssets. But effect is not slow_mo 120FPS I READ about it and got i should use AVComposition for export slow_mo video. but i am unable to do it. Below is my NOT working code.
AVAsset *assetURL = [AVURLAsset URLAssetWithURL:URl options:nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = paths.firstObject;
NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"mergeSlowMoVideo-%d.mov",arc4random() % 1000]];
NSURL *_filePath = [NSURL fileURLWithPath:myPathDocs];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:assetURL presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL = _filePath;
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
[exporter exportAsynchronouslyWithCompletionHandler:^{ //start
NSLog(#"Export failed: %#", [[exporter error] localizedDescription]);
NSLog(#"Video test run exported video into file: %#", exporter.outputURL);
NSLog(#"export %ld", (long)exporter.status);
dispatch_async(dispatch_get_main_queue(), ^{
if (exporter.status == AVAssetExportSessionStatusCompleted) {
}
});
}];
Please any expert help me.
UPDATE: this is my actual problem.
This Question has my Actual problem explanation
I'm trying to write Metadata information inside a Video recorded inside my app. At the end of video taking i have:
NSMutableArray *metadata = [NSMutableArray array];
AVMutableMetadataItem *mi = [AVMutableMetadataItem metadataItem];
mi.key = AVMetadataCommonKeyTitle;
mi.keySpace = AVMetadataKeySpaceCommon;
mi.value = #"testmetadata";
[metadata addObject:mi];
AVMutableMetadataItem *mi2 = [AVMutableMetadataItem metadataItem];
mi2.key = AVMetadataCommonKeyIdentifier;
mi2.keySpace = AVMetadataKeySpaceCommon;
mi2.value = #"testmetadata";
[metadata addObject:mi2];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:self.outputURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *outputURL_nuovo = paths[0];
NSFileManager *manager = [NSFileManager defaultManager];
[manager createDirectoryAtPath:outputURL_nuovo withIntermediateDirectories:YES attributes:nil error:nil];
outputURL_nuovo = [outputURL_nuovo stringByAppendingPathComponent:#"output.mp4"];
// Remove Existing File
[manager removeItemAtPath:outputURL_nuovo error:nil];
exportSession.outputURL = [NSURL fileURLWithPath:outputURL_nuovo];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
exportSession.metadata=metadata;
CMTime start = CMTimeMakeWithSeconds(1.0, 600);
CMTime duration = CMTimeMakeWithSeconds(3.0, 600);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
[self writeVideoToPhotoLibrary:[NSURL fileURLWithPath:outputURL_nuovo]];
NSLog(#"Export Complete %d %#", exportSession.status, exportSession.error);
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Failed:%#",exportSession.error);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Canceled:%#",exportSession.error);
break;
default:
break;
}
}];
If the export end with success, i have this other method:
-(void)writeVideoToPhotoLibrary: (NSURL*)url{
ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary writeVideoAtPathToSavedPhotosAlbum:url
completionBlock:^(NSURL *assetURL, NSError *error)
{
[assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *assetRep = [asset defaultRepresentation];
NSLog(#"Image filename: %#", [assetRep filename]);
NSDate *date = [asset valueForProperty:ALAssetPropertyDate];
NSLog(#"DATA prima %#",date);
NSLog(#"TIMESTAMP %f",[date timeIntervalSince1970]);
//////////get info
[assetsLibrary assetForURL:url resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *assetRep = [asset defaultRepresentation];
NSLog(#"Image filename dopp: %#", [assetRep filename]);
NSLog(#"METADATA %#",[assetRep metadata]);
} failureBlock:^(NSError *error) {
NSLog(#"Error: %#", error.localizedDescription);
}];
///////////////get info
} failureBlock:^(NSError *error) {
NSLog(#"Error: %#", error.localizedDescription);
}];
}];
}
With this code i'm trying to save a video with some metadata in it, like a title, and then read the metadata i've just saved. The log returns a null value METADATA (null) , what i'm doing wrong?
I use the method (a the end of this question) to retrieve video from the device. What it does, it finds the first video in the library, creates export session and exports the video into MOV file.
After two runs of the application (stopping the app between method runs), two resulting files are being compared. Both files are different. I was expecting that both files would be the same, as the same asset is being exported.
One more remark: running the method twice in the same application run gives me two identical files as expected.
Is it possible to make PhotoKit to export the same file every time it runs?
- (void)testVideoRetrievalSO {
PHAsset *oneVideo = [[PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeVideo options:nil] firstObject];
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.networkAccessAllowed = YES;
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
options.version = PHVideoRequestOptionsVersionOriginal;
[[PHImageManager defaultManager] requestExportSessionForVideo:oneVideo
options:options
exportPreset:AVAssetExportPresetPassthrough
resultHandler:
^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
NSLog(#"Video test run on asset %#", oneVideo.localIdentifier);
NSString *folderPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *fileName = [[[NSUUID UUID] UUIDString] stringByAppendingPathExtension:#"mov"];
NSString *tempFile = [folderPath stringByAppendingPathComponent:fileName];
NSURL *tempFileUrl = [NSURL fileURLWithPath:tempFile];
[exportSession setOutputFileType:AVFileTypeQuickTimeMovie];
[exportSession setOutputURL:tempFileUrl];
[exportSession exportAsynchronouslyWithCompletionHandler:^{
NSLog(#"Video test run exported video into file: %#", tempFile);
}];
}];
}
UPDATED
It's not clear but I think exporting video from the camera roll does not guarantee fetching same video in every time. So I copied the video from camera roll to my document folder with url (avurlasset.URL) by [NSFileManager copyItemAtURL:toURL:error:] then it copies the same video file in every time. For now it is my final solution.
In this case you have to use requestAVAssetForVideo not requestExportSessionForVideo
So in your case,
PHVideoRequestOptions *options = [PHVideoRequestOptions new];
options.version = PHVideoRequestOptionsVersionOriginal;
[[PHImageManager defaultManager] requestAVAssetForVideo:asset
options:options
resultHandler:
^(AVAsset * _Nullable avasset,
AVAudioMix * _Nullable audioMix,
NSDictionary * _Nullable info)
{
NSError *error;
AVURLAsset *avurlasset = (AVURLAsset*) avasset;
// Write to documents folder
NSURL *fileURL = [NSURL fileURLWithPath:tmpShareFilePath];
if ([[NSFileManager defaultManager] copyItemAtURL:avurlasset.URL
toURL:fileURL
error:&error]) {
NSLog(#"Copied correctly");
}
}];
I'm developing an iOS app, which needs to convert a video downloaded using you tube APIs into .mov format. I've tried using AVExportSession output file type set to .mov.`
NSURL * mediaURL = [NSURL fileURLWithPath:outputURL];
AVAsset *video = [AVAsset assetWithURL:mediaURL];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPreset1920x1080];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
documentsPath=[documentsPath stringByAppendingString:#"/Youtube"];
BOOL isDir;
if (![[NSFileManager defaultManager] fileExistsAtPath:documentsPath isDirectory:&isDir]) {
NSError *createDirError;
if (![[NSFileManager defaultManager] createDirectoryAtPath:documentsPath withIntermediateDirectories:YES attributes:nil error:&createDirError]) {
if (createDirError) {
NSLog(#"eror while creating dir == %#", createDirError);
}
}
}
documentsPath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%d.mov",arc4random()%10000]];
exportSession.outputURL = [NSURL fileURLWithPath:documentsPath];
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
{
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:[NSURL fileURLWithPath:outputURL] completionBlock:^(NSURL *assetURL, NSError *error) {
if (error) {
NSLog(#"error>%#",error.description);
}
else{
if([[NSFileManager defaultManager] fileExistsAtPath:outputURL])
{
[[NSFileManager defaultManager]removeItemAtPath:outputURL error:nil];
}
NSLog(#"asseturl>%#",assetURL);
[[NSFileManager defaultManager] removeItemAtPath:outputURL error:nil];
[self addAssetURL:assetURL toAlbum:#"Fame" withCompletionBlock:^(NSError *error) {
if(error)
{
NSLog(#"Error in saving to Fame album : %#",error.description);
return;
}
}];
}
}];
}
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Error : %#",exportSession.error.description);
default:
break;
}
NSLog(#"done processing video!");
}];
`
This code saves the video to gallery, but when I fetch the video using asset library, I get mp4 in the url.
I need to create Folder in Cloud and save my .txt Text File into that Folder.
So i created folder with following codes in AppDelegate
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSError *error = nil;
if(ubiq)
{
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *rootURL = [fm URLForUbiquityContainerIdentifier:nil];
NSURL *newFolder = [NSURL URLWithString:#"Notes" relativeToURL:rootURL];
[fm createDirectoryAtURL:newFolder withIntermediateDirectories:YES attributes:nil error:&error];
if(error)
{
NSLog(#"Error");
}
else
{
NSLog(#"NO Error");
}
}
After i test it , It show No Error.
So i assumed that it created Notes Folder in iCloud.
However when i save my text document into that folder with following codes , it showing error and not save.
NSString *file = [NSString stringWithFormat:#"%#.txt",fileName];
NSURL *ubiq = [[NSFileManager defaultManager]
URLForUbiquityContainerIdentifier:nil];
NSURL *ubiquitousPackage =
[[[ubiq URLByAppendingPathComponent:#"Documents"] URLByAppendingPathComponent:#"Notes"]
URLByAppendingPathComponent:file];
Note *doc = [[Note alloc] initWithFileURL:ubiquitousPackage];
[doc saveToURL:[doc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
if (!success)
{
NSLog(#"Error");
}
else
{
doc.noteContent = self.txtView.text;
[doc updateChangeCount:UIDocumentChangeDone];
}
}];
And the error message is
Foundation called mkdir("/private/var/mobile/Library/Mobile Documents/35QNLTQU29~com~myapp~iCloudTest/Documents/Notes/(A Document Being Saved By iCloudTest)"), it didn't return 0, and errno was set to 2.
How can i solve it?