In my application I am combining two audio files using AVAssetExportSession and it works fine in earlier ios versions.But in ios5 device its not working. What i am getting is an error
AVAssetExportSessionStatusFailed: Error Domain=AVFoundationErrorDomain Code=-11820 "Cannot Complete Export" UserInfo=0x1df1c0 {NSLocalizedRecoverySuggestion=Try exporting again., NSLocalizedDescription=Cannot Complete Export}
The code that I use for exporting is given below
Did anyone experience the same issue? Please provide your valuable suggestions.
I am in an urgent need to fix this issue..
//Export function to export the combined audios as one.
-(void)exportAudioFile:(AVComposition*)combinedComposition
{
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:combinedComposition
presetName:AVAssetExportPresetPassthrough];
NSArray *presets =[AVAssetExportSession exportPresetsCompatibleWithAsset:combinedComposition];
NSLog(#"presets======%#",presets);
NSLog (#"can export: %#", exportSession.supportedFileTypes);
NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [dirs objectAtIndex:0];
exportPath = [documentsDirectoryPath stringByAppendingPathComponent:#"CombinedNew.m4a"];
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
exportURL = [NSURL fileURLWithPath:exportPath];
exportSession.outputURL = exportURL;
exportSession.outputFileType = #"com.apple.m4a-audio";
exportSession.shouldOptimizeForNetworkUse = YES;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
NSLog (#"i is in your block, exportin. status is %d",
exportSession.status);
switch (exportSession.status)
{
case AVAssetExportSessionStatusFailed:
{
// log error to text view
NSError *exportError = exportSession.error;
DEBUG_LOG(#"AVAssetExportSessionStatusFailed: %#", exportError);
[self enableUI];
break;
}
case AVAssetExportSessionStatusCompleted:
{
DEBUG_LOG(#"AVAssetExportSessionStatusCompleted");
DEBUG_LOG(#"Completed export");
exportSuccess = YES;
if (recorderFilePath)
{
NSError *finalurlError;
[[NSFileManager defaultManager]removeItemAtPath:recorderFilePath error:&finalurlError];
finalurlError = nil;
[[NSFileManager defaultManager]copyItemAtPath:[exportURL path] toPath:recorderFilePath error:&finalurlError];
}
isExported = YES;
fileUrl = [NSURL fileURLWithPath:recorderFilePath];
[self performSelectorInBackground:#selector(updatePlayerForUrl:) withObject:fileUrl];
break;
}
case AVAssetExportSessionStatusUnknown:
{
DEBUG_LOG(#"AVAssetExportSessionStatusUnknown");
break;
}
case AVAssetExportSessionStatusExporting:
{
DEBUG_LOG(#"AVAssetExportSessionStatusExporting");
break;
}
case AVAssetExportSessionStatusCancelled:
{
DEBUG_LOG(#"AVAssetExportSessionStatusCancelled");
break;
}
case AVAssetExportSessionStatusWaiting:
{
DEBUG_LOG(#"AVAssetExportSessionStatusWaiting");
break;
}
default:
{
DEBUG_LOG(#"didn't get export status");
break;
}
};
}];
[exportSession release];
}
I sorted out the answer for myself and would like to share it with others who experience the same problem.
The problem is that for some reason the AVAssetExportPresetPassthrough is not working properly in ios5. Substituting it with AVAssetExportPresetAppleM4A solved the issue.
But it takes longer to export now.
Perhaps a way around it is to use AVAssetWriter directly and not use AVAssetExportSession. Please please please, file a bug at http://bugreport.apple.com so that maybe it gets fixed in the next rev of iOS5. (I filed one of my own, but the more the merrier.)
As a workaround, I found that using .mov as the file extension, then renaming it back to mp3 seems to work. I dont need to do this for m4a files.
Related
Even though it looks like a simple procedure, it's by now 3 hours I'm trying without success. I am probably missing something really stupid.
So, I have this app downloading videos from the Internet. The videos are correctly stored locally because I can play them providing the local url. But, I can't succeed in copying the videos to the camera roll. Here is what I do:
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryWriteVideoCompletionBlock videoWriteCompletionBlock =
^(NSURL *newURL, NSError *error) {
if (error) {
NSLog( #"Error writing image with metadata to Photo Library: %#", error );
} else {
NSLog( #"Wrote image with metadata to Photo Library %#", newURL.absoluteString);
}
};
NSLog(#"file %#", localPath);
NSURL *url = [NSURL fileURLWithPath:localPath isDirectory:NO];
[library writeVideoAtPathToSavedPhotosAlbum:url
completionBlock:videoWriteCompletionBlock];
But the output I get is:
2013-07-24 00:13:32.094 App[1716:907] file /var/mobile/Applications/70C18C4E-9F97-4A6A-B63E-1BD19961F010/Documents/downloaded_video.mp4
2013-07-24 00:13:32.374 App[1716:907] Wrote image with metadata to Photo Library (null)
And of course the file is not saved in the camera roll. It's a simple mp4, compatible with the device I'm using (i.e. it should be possible to save it).
I honestly have no idea what to do. Any hint will be highly appreciated. Thanks
I may have found a workaround for you. Have you tried an AVAssetExportSession?
In the sample below, I built a simple app that has two buttons on the screen. One calls onSaveBtn:, which simply grabs the URL of a video I have in my app's resource bundle and saves it to the user's saved photos album. (Though, in my case my videos do return YES from videoAtPathIsCompatibleWithSavedPhotosAlbum:. I didn't have any videos that don't return otherwise.)
The second button is wired to onExportBtn:, which takes the video we want to save, creates an AVAssetExportSession, exports the video to a temp directory, and then copies the exported video to the saved photos album. Due to the export time, this method does take longer than a simple copy, but maybe this could be an alternate path - check the results of videoAtPathIsCompatibleWithSavedPhotosAlbum:, and if YES, copy directly to the album. Otherwise, export the video, then copy.
Without having a video file that doesn't return NO to the compatibility call, I'm not 100% sure this would work for you, but it's worth a shot.
You may also want to check out this question, which explores what video formats are compatible on the device you may be using.
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
- (IBAction)onSaveBtn:(id)sender
{
NSURL *srcURL = [[NSBundle mainBundle] URLForResource:#"WP_20121214_001" withExtension:#"mp4"];
[self saveToCameraRoll:srcURL];
}
- (IBAction)onExportBtn:(id)sender
{
NSURL *srcURL = [[NSBundle mainBundle] URLForResource:#"WP_20121214_001" withExtension:#"mp4"];
AVAsset *srcAsset = [AVAsset assetWithURL:srcURL];
// create an export session
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:srcAsset presetName:AVAssetExportPresetHighestQuality];
// Export the file to a tmp dir
NSString *fileName = [srcURL lastPathComponent];
NSString *tmpDir = NSTemporaryDirectory();
NSURL *tmpURL = [NSURL fileURLWithPath:[tmpDir stringByAppendingPathComponent:fileName]];
exportSession.outputURL = tmpURL;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
// now copy the tmp file to the camera roll
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %#", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(#"Export successful");
[self saveToCameraRoll:exportSession.outputURL];
break;
default:
break;
}
}];
}
- (void) saveToCameraRoll:(NSURL *)srcURL
{
NSLog(#"srcURL: %#", srcURL);
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
ALAssetsLibraryWriteVideoCompletionBlock videoWriteCompletionBlock =
^(NSURL *newURL, NSError *error) {
if (error) {
NSLog( #"Error writing image with metadata to Photo Library: %#", error );
} else {
NSLog( #"Wrote image with metadata to Photo Library %#", newURL.absoluteString);
}
};
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:srcURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:srcURL
completionBlock:videoWriteCompletionBlock];
}
}
Where are you providing the URL to the block.
I think you need to do this way..
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:videoURL completionBlock:^(NSURL *assetURL, NSError *error){
/*notify of completion*/
NSLog(#"AssetURL: %#",assetURL);
NSLog(#"Error: %#",error);
if (!error) {
//video saved
}else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:error.domain delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}];
You can change the url here, I have used for the imagePickerController..
See if its helps you..
Here's a shorter answer.
In my case, I've used AFNetworking to download a video from a URL and in the downloadCompletedBlock of the download operation, responseObject returns the download file. Logging responseObject returns me the full file path of the downloaded video.
If you are using another method to download videos, simply replace responseObject with the full file path of your video, probably with the usual NSSearchPathForDirectoriesInDomains method.
Here's the snippet I use to export videos in the application's local file directory to the Camera Roll:
NSURL *responseObjectPath = [NSURL URLWithString:responseObject];
// If video is compatible with Camera Roll
if ([[ALAssetsLibrary new] videoAtPathIsCompatibleWithSavedPhotosAlbum:responseObjectPath])
{
// Export to Camera Roll
[[ALAssetsLibrary new] writeVideoAtPathToSavedPhotosAlbum:responseObjectPath completionBlock:nil];
}
else
{
NSLog(#"Incompatible File Type");
}
Cheers!
I am attempting to trim a video using the following code:
AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#/%#.mp4",documentsDirectory,name]] options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:AVAssetExportPresetHighestQuality];
NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"%#/finalOutput.mp4",documentsDirectory]];
exportSession.outputURL = url;
NSLog(#"outputting to: %#", [NSString stringWithFormat:#"%#/finalOutput.mp4",documentsDirectory,name]);
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTimeRange timeRange = CMTimeRangeMake(flashbackStart, CMTimeSubtract(flashbackEnd, flashbackStart));
exportSession.timeRange = timeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
// Custom method to import the Exported Video
//[self loadAssetFromFile:exportSession.outputURL];
NSLog(#"completed!!!");
break;
case AVAssetExportSessionStatusFailed:
//
NSLog(#"Failed:%#",exportSession.error);
break;
case AVAssetExportSessionStatusCancelled:
//
NSLog(#"Canceled:%#",exportSession.error);
break;
default:
break;
}
}];
However, I'm getting a bad access error for this line:
[exportSession exportAsynchronouslyWithCompletionHandler:^{
Even with NSZombie enabled, I'm not getting any details about the error. Can anyone explain what's going on here? The input video file does exist, and the output video file does not exist before I attempt to write to it.
Thanks,
James
It turns out the problem was with the NSURLs I used. All I had to do was use initFileURLWithPath and the problem was solved!
You might be running into a problem with the storage type. Try adding __block to your exportSession.
__block AVAssetExportSession *exportSession...
You can read more here:
http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Blocks/Articles/bxGettingStarted.html#//apple_ref/doc/uid/TP40007502-CH7-SW5
I have simple video compression code in low quality conversion.I am testing my code in iphone 4 with IOS-4.2.1.The problem is when I test my code on device without break points the code failed to create video(it just a zero kb file or empty file created) but when I use breakpoint checking line by line this code slowly it will make a perfect compressed video which also runs on quicktime player in mac.After compression I make zip of this video file.
NSURL *videoURL=[[self.videourlarray objectAtIndex:i] valueForKey:UIImagePickerControllerReferenceURL];
NSURL *outputURL = [NSURL fileURLWithPath:videoFile];
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
exportSession.outputURL = outputURL;
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
NSLog(#"Export Complete %d %#", exportSession.status, exportSession.error);
[exportSession release];
}];
thanx for any help...
I think you need to make sure you're not messing with the threads.. (AVFoundation guide says that the exporter is not guaranteed to run on any particular thread).
Use a block like this.
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Export Complete %d %#", exportSession.status, exportSession.error);
});
}];
I would personally call a delegate from the block, but I presume your simple log statement is just for this example and you already know that :)
I had the same problem. After hours of debuging, I found out that my extension of the audio file was .M4A all uppercase. Lowercasing the letters will fix the problem
I have implemented an overlay view when calling camera view before recording the video.
pickerController.cameraOverlayView =myOverlay;
Video recording and saving the video into Album after recording the video and sharing via email etc. all works fine.
If i use video quality as "High quality", then the recorded video has become huge size. For example, if i record video for 30 seconds with high quality, recorded video has become around 30 - 40 mb.
pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
How do i program to compress the high quality recorded video before sharing it, like how Apple does with built-in Video recorder?
Please guide me to resolve this.
Thanks!
UPDATED:
This is what i'm trying recently, but still no success: I want to compress the recorded video taken which comes to didFinishPickingMediaWithInfo and store in same photo album actual video path itself, not anywhere else. I tested the same video is compressed to very small size when i pick from photo library, but the same video taken from camera and came via didFinishPickingMediaWithInfo is not compressed, though i used the AVAssetExportSession code below.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSString *urlPath = [videoURL path];
if ([[urlPath lastPathComponent] isEqualToString:#"capturedvideo.MOV"])
{
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum (urlPath))
{
[self copyTempVideoToMediaLibrary :urlPath];
}
else
{
NSLog(#"Video Capture Error: Captured video cannot be saved...didFinishPickingMediaWithInfo()");
}
}
else
{
NSLog(#"Processing soon to saved photos album...else loop of lastPathComponent..didFinishPickingMediaWithInfo()");
}
}
[self dismissModalViewControllerAnimated:YES];
}
- (void)copyTempVideoToMediaLibrary :(NSString *)videoURL {
dispatch_queue_t mainQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(mainQueue, ^{
ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease];
ALAssetsLibraryWriteVideoCompletionBlock completionBlock = ^(NSURL *assetURL, NSError *error) {
NSLog(#"Saved URL: %#", assetURL);
NSLog(#"Error: %#", error);
if (assetURL != nil) {
AVURLAsset *theAsset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:videoURL] options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:theAsset];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:theAsset presetName:AVAssetExportPresetLowQuality];
[exportSession setOutputURL:[NSURL URLWithString:videoURL]];
[exportSession setOutputFileType:AVFileTypeQuickTimeMovie];
[exportSession exportAsynchronouslyWithCompletionHandler:^ {
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(#"Export session faied with error: %#", [exportSession error]);
break;
default:
//[self mediaIsReady];
break;
}
}];
}
};
[library writeVideoAtPathToSavedPhotosAlbum:[NSURL URLWithString:videoURL] completionBlock:completionBlock];
});
}
If you want to compress the video for remote sharing and keep the original quality for local storage on the iPhone, you should look into AVAssetExportSession or AVAssetWriter.
Also read up on how iOS manages Assets.
- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL
outputURL:(NSURL*)outputURL
handler:(void (^)(AVAssetExportSession*))handler
{
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
exportSession.outputURL = outputURL;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
handler(exportSession);
[exportSession release];
}];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSURL *outputURL = [NSURL fileURLWithPath:#"/Users/josh/Desktop/output.mov"];
[self convertVideoToLowQuailtyWithInputURL:videoURL outputURL:outputURL handler:^(AVAssetExportSession *exportSession)
{
if (exportSession.status == AVAssetExportSessionStatusCompleted)
{
printf("completed\n");
}
else
{
printf("error\n");
}
}];
}
I guess the video is already compressed by the h264 codec. But you can try to use AVFoundation to capture the video files from camera. But I suspect you'll end up with the same file sizes.
Here is some statistics for the 10 seconds video file recorded on the iPhone 4 with different quality pressets.
high (1280х720) = ~14MB = ~11Mbit/s
640 (640х480) = ~4MB = ~3.2Mbit/s
medium (360х480) = ~1MB = ~820Kbit/s
low (144х192) = ~208KB = ~170Kbit/s
pickerController.videoQuality = UIImagePickerControllerQualityTypeMedium;
These are all the values you can pick from.
UIImagePickerControllerQualityTypeHigh = 0,
UIImagePickerControllerQualityType640x480 = 3,
UIImagePickerControllerQualityTypeMedium = 1, // default value
UIImagePickerControllerQualityTypeLow = 2
Programmatically compressing video with using swift
And don't forgot to add - import AssetsLibrary
func convertVideoWithMediumQuality(inputURL : NSURL){
let VideoFilePath = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("mergeVideo\(arc4random()%1000)d").URLByAppendingPathExtension("mp4").absoluteString
if NSFileManager.defaultManager().fileExistsAtPath(VideoFilePath) {
do {
try NSFileManager.defaultManager().removeItemAtPath(VideoFilePath)
} catch { }
}
let savePathUrl = NSURL(string: VideoFilePath)!
let sourceAsset = AVURLAsset(URL: inputURL, options: nil)
let assetExport: AVAssetExportSession = AVAssetExportSession(asset: sourceAsset, presetName: AVAssetExportPresetMediumQuality)!
assetExport.outputFileType = AVFileTypeQuickTimeMovie
assetExport.outputURL = savePathUrl
assetExport.exportAsynchronouslyWithCompletionHandler { () -> Void in
switch assetExport.status {
case AVAssetExportSessionStatus.Completed:
dispatch_async(dispatch_get_main_queue(), {
do {
let videoData = try NSData(contentsOfURL: savePathUrl, options: NSDataReadingOptions())
print("MB - \(videoData.length / (1024 * 1024))")
} catch {
print(error)
}
})
case AVAssetExportSessionStatus.Failed:
self.hideActivityIndicator(self.view)
print("failed \(assetExport.error)")
case AVAssetExportSessionStatus.Cancelled:
self.hideActivityIndicator(self.view)
print("cancelled \(assetExport.error)")
default:
self.hideActivityIndicator(self.view)
print("complete")
}
}
}
Try this few lines :
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset: urlAsset presetName:AVAssetExportPresetLowQuality];
session.outputURL = outputURL;
session.outputFileType = AVFileTypeQuickTimeMovie;
[session exportAsynchronouslyWithCompletionHandler:^(void)
{
handler(session);
}];
I found an excellent custom class(SDAVAssetExportSession) to do the video compression. You can download it from this link.
After downloading add SDAVAssetExportSession.h and SDAVAssetExportSession.m files into your project, Then the below code will help to do the compression. In below code you can compress video by specifying resolution and bitrate
#import "SDAVAssetExportSession.h"
- (void)compressVideoWithInputVideoUrl:(NSURL *) inputVideoUrl
{
/* Create Output File Url */
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *finalVideoURLString = [documentsDirectory stringByAppendingPathComponent:#"compressedVideo.mp4"];
NSURL *outputVideoUrl = ([[NSURL URLWithString:finalVideoURLString] isFileURL] == 1)?([NSURL URLWithString:finalVideoURLString]):([NSURL fileURLWithPath:finalVideoURLString]); // Url Should be a file Url, so here we check and convert it into a file Url
SDAVAssetExportSession *compressionEncoder = [SDAVAssetExportSession.alloc initWithAsset:[AVAsset assetWithURL:inputVideoUrl]]; // provide inputVideo Url Here
compressionEncoder.outputFileType = AVFileTypeMPEG4;
compressionEncoder.outputURL = outputVideoUrl; //Provide output video Url here
compressionEncoder.videoSettings = #
{
AVVideoCodecKey: AVVideoCodecH264,
AVVideoWidthKey: #800, //Set your resolution width here
AVVideoHeightKey: #600, //set your resolution height here
AVVideoCompressionPropertiesKey: #
{
AVVideoAverageBitRateKey: #45000, // Give your bitrate here for lower size give low values
AVVideoProfileLevelKey: AVVideoProfileLevelH264High40,
},
};
compressionEncoder.audioSettings = #
{
AVFormatIDKey: #(kAudioFormatMPEG4AAC),
AVNumberOfChannelsKey: #2,
AVSampleRateKey: #44100,
AVEncoderBitRateKey: #128000,
};
[compressionEncoder exportAsynchronouslyWithCompletionHandler:^
{
if (compressionEncoder.status == AVAssetExportSessionStatusCompleted)
{
NSLog(#"Compression Export Completed Successfully");
}
else if (compressionEncoder.status == AVAssetExportSessionStatusCancelled)
{
NSLog(#"Compression Export Canceled");
}
else
{
NSLog(#"Compression Failed");
}
}];
}
To Cancel Compression Use Below Line Of code
[compressionEncoder cancelExport]; //Video compression cancel
I cracked this.
Use exportSession.fileLengthLimit = 1048576 * 10 //10 MB
10MB is hard coded number. Use according to your required bitrate.
I'm writing an application that works with video using AVFoundation.
The behaviour of my application is simple: I take a video from the camera roll, then I create an AVMutableComposition with some audio tracks. With the mix composition i initialize an AVAssetExportSession that stores the video file in the documents directory of my app.
Until this point everything it's ok: my video is stored and I'm able to play it in another controller. If I take the video that i have just stored in my documents folder to make some editing (in the same way of the first time AVmutableComposition, AVAssetExportSession) it's ok again.
But the third time I do this process to editing a video the AVAssetExportSession status becomes "Fail" and with this error:
"Domain=AVFoundationErrorDomain Code=-11820 "Cannot Complete Export" UserInfo=0x1a9260 {NSLocalizedRecoverySuggestion=Try exporting again., NSLocalizedDescription=Cannot Complete Export}"
I have read that is a general error where the session couldn't be exported. What is the sense of this? Why only the third time that i made the editing process? Could it be a memory management mistake? A bug?. This is the code of my AVAssetExportSession:
_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
_assetExport.shouldOptimizeForNetworkUse = YES;
///data odierna
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"ddMMyyyyHHmmss"];
NSDate *now = [[NSDate alloc] init];
NSString *dateString = [format stringFromDate:now];
[now release];
[format release];
NSString* ext = #".MOV";
NSString* videoName=[NSString stringWithFormat:#"%#%#", dateString, ext];
///data odierna
NSString *exportPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:videoName];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
{
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
[_assetExport setTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath] ;
_assetExport.outputURL = exportUrl ;
[_assetExport exportAsynchronouslyWithCompletionHandler:^
{
switch (_assetExport.status)
{
case AVAssetExportSessionStatusFailed:
{
NSLog (#"FAIL %#",_assetExport.error);
if ([[NSFileManager defaultManager] fileExistsAtPath:[_assetExport.outputURL path]])
{
[[NSFileManager defaultManager] removeItemAtPath:[_assetExport.outputURL path] error:nil];
}
[self performSelectorOnMainThread:#selector (ritenta)
withObject:nil
waitUntilDone:NO];
break;
}
case AVAssetExportSessionStatusCompleted:
{
NSLog (#"SUCCESS");
[self performSelectorOnMainThread:#selector (saveVideoToAlbum:)
withObject:exportPath
waitUntilDone:NO];
break;
}
case AVAssetExportSessionStatusCancelled:
{
NSLog (#"CANCELED");
break;
}
};
}];
I have done many searches on the web, some people have had a problem in the outputURL of the session, but I have tried and seems all ok in my code. To assign a unique name to the file I use a NSDate. For debugging purposes I have tried to restore a standard string name but the problem remains. Any ideas? Can someone suggest to me an alternative method to export to the documents folder an asset with AssetWriter insted the AVassetExportSession?
The problem is _assetExport.outputFileType you have set the type AVFileTypeQuickTimeMovie. Which is not likely to be supported type.
Try to find out what output file types are supported by the _assetExport using the following code and use the suitable one.
NSLog (#"created exporter. supportedFileTypes: %#", exporter.supportedFileTypes);
OR
just change the
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
TO
exporter.outputFileType = #"com.apple.m4a-audio";
Also dont forget to change the extension from
NSString* ext = #".MOV"; to #".m4a"
This should work. It worked for me.