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.
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 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];
}
}];
}];
}
I have download the .mp4 file from sever to document directory and called the
writeVideoAtPathToSavedPhotosAlbum method to save to gallery but its nor working.its throwing asset url nil.Can anyone plz help me with this issue
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"test.mp4"];
NSURL *movieURL = [NSURL fileURLWithPath:path];
ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
NSLog(#"Moview URL:%#",movieURL);
NSURL *url = [movieURL copy];
[library writeVideoAtPathToSavedPhotosAlbum:url
completionBlock:^(NSURL *assetURL, NSError *error)
{
NSLog(#"Asset Url:%#",assetURL);
if(!error) {
NSLog(#"\t ! Error");
NSLog(#"\t Error: %#", [error localizedDescription]);
NSLog(#"\t Error code %d", [error code]);
}
if(error != nil) {
NSLog(#"\t ERROR != NIL");
NSLog(#"\t Error - Image Failed To Save With Error: %#", [error localizedDescription]);
NSLog(#"\t Error code %d", [error code]);
}
if(error == nil) {
NSLog(#"\t ERROR == NIL");
}
}];
Check this below methods:
-(void)ButtonAction:(id)sender
{
NSURL *video = [NSURL URLWithString:YOURURL];
NSData *data = [NSData dataWithContentsOfURL:video];
NSString *docDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/myvideo_%#.mp4",docDirPath,CURRENT_TIMESTAMP];
[data writeToFile:filePath atomically:YES];
NSURL *urlPath = [[NSURL alloc] initFileURLWithPath:filePath];
[self saveToCameraRoll:urlPath dict:(NSDictionary *)sender];
}
-(void) saveToCameraRoll:(NSURL *)srcURL dict:(NSDictionary *)dictValues
{
NSLog(#"srcURL: %#", srcURL);
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:srcURL completionBlock:^(NSURL *assetURL, NSError *error)
{
NSURL *savedAssetURL = assetURL;
NSLog(#"asset url %#",assetURL);
if(error)
{
error handling
}
else
{
[library assetForURL:savedAssetURL resultBlock:^(ALAsset * alAsset)
{
NSLog(#"Saved");
}failureBlock:^(NSError *error)
{
NSLog(#"Not Saved");
}];
}
}];
}
Try assetURL.absoluteString in completionBlock
I have tried to export audio file from the iPod-Library. My objective is to create new file in app Document folder with this iPod-Library file .Its fails to create files for some items only . Below is my code snippet.
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL: url options:nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc]
initWithAsset: songAsset
presetName: AVAssetExportPresetAppleM4A];
exporter.outputFileType = #"com.apple.m4a-audio";
NSString *songName = [filename stringByAppendingString:#".m4a"];
NSString *musicfilepath = [documentsDirectory stringByAppendingPathComponent:#"musics/"];
[[NSFileManager defaultManager] createDirectoryAtPath:musicfilepath withIntermediateDirectories:YES attributes:nil error:nil];
NSString *exportFile = [musicfilepath stringByAppendingPathComponent:songName];
NSError *error1;
if([[NSFileManager defaultManager] fileExistsAtPath:exportFile])
{
[[NSFileManager defaultManager] removeItemAtPath:exportFile error:&error1];
}
NSURL* exportURL = [[NSURL fileURLWithPath:exportFile] retain];
exporter.outputURL = exportURL;
Am getting Error as shown below when tried with the error handler block :
[exporter exportAsynchronouslyWithCompletionHandler:^{
int exportStatus = exporter.status;
switch (exportStatus) {
case AVAssetExportSessionStatusFailed: {
NSError *exportError = exporter.error;
NSLog (#"AVAssetExportSessionStatusFailed: %#", exportError);
break;
}
}
}];
AVAssetExportSessionStatusFailed: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=0x214f20 {NSLocalizedFailureReason=An unknown error occurred (-12124), NSUnderlyingError=0x218270 "The operation couldn’t be completed. (OSStatus error -12124.)", NSLocalizedDescription=The operation could not be completed}
Having played a lot with this myself, some of the answers may be relevant and correct. One other thing to watch out for is that I often used to get similar AVFoundation errors if trying to combine videos that had different frame-rates. Check the source files frame rate and check your CMTime's too. You may have to pre-process some files before adding them into a AVMutableComposition.
If you have iTunes match on and the file is not downloaded to the device, this can happen. Can you check to see if that is the case for you? If so I can give code to detect it.
+ (BOOL)isDownloadedFromiCloud:(MPMediaItem *)item {
if ([item valueForProperty:MPMediaItemPropertyAssetURL] != nil) {
AVURLAsset *asset = [AVURLAsset assetWithURL:[item valueForProperty:MPMediaItemPropertyAssetURL]];
if (asset.exportable)
return YES;
}
return NO;
}
I've experienced this too. Are you using iTunes match? It may be that the file is not on the actual device. You can check this on the AVAsset by checking the properties such as hasProtectedContent or ensuring exportable is YES.
Also, I notice you are using the AVExportSession preset AVAssetExportPresetAppleM4A'. This will re-encode the file you are exporting. It may be easier (and much faster) to just pass-though instead usingAVAssetExportPresetPassthrough`. This assumes you are happy with the existing file format, which maybe .m4a, .mp3, .wav etc...
The the music file path your are using might be wrong. Try this
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
documentsDirectory = [documentsDirectory stringByAppendingPathComponent:#"Music"];
NSError* error;
if (![[NSFileManager defaultManager] fileExistsAtPath:documentsDirectory])
[[NSFileManager defaultManager] createDirectoryAtPath:documentsDirectory withIntermediateDirectories:NO attributes:nil error:&error];
NSString *exportFile = [documentsDirectory stringByAppendingPathComponent:songName];
if([[NSFileManager defaultManager] fileExistsAtPath:exportFile])
{
[[NSFileManager defaultManager] removeItemAtPath:exportFile error:&error1];
}
if (error != nil) {
NSURL* exportURL = [[NSURL fileURLWithPath:exportFile] retain];
exporter.outputURL = exportURL;
[exporter exportAsynchronouslyWithCompletionHandler:^{
int exportStatus = exporter.status;
switch (exportStatus) {
case AVAssetExportSessionStatusFailed: {
NSError *exportError = exporter.error;
NSLog (#"AVAssetExportSessionStatusFailed: %#", exportError);
break;
}
}
}
];
}