I want to trim a video:
-(void)trimVideo:(NSURL*)outputURL
{
//[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:outputURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
NSString * outputFilePath = NSHomeDirectory();
outputFilePath = [outputFilePath stringByAppendingPathComponent:#"Library"];
outputFilePath = [outputFilePath stringByAppendingPathComponent:#"temp.mov"];
NSURL * outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
exportSession.outputURL = outputFileUrl;
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeMPEG4;
CMTime start = CMTimeMakeWithSeconds(1.0, 600);
CMTime duration = CMTimeMakeWithSeconds(3.0, 600);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
NSLog(#"Export Complete %d %#", exportSession.status, exportSession.error);
//[exportSession release];
}];
}
But I get the error:
Export Complete 4 Error Domain=AVFoundationErrorDomain Code=-11823 "Cannot Save" UserInfo=0x2008f420 {NSLocalizedRecoverySuggestion=Try saving again., NSLocalizedDescription=Cannot Save}
Not exactly sure how to resolve.
This did the trick:
-(void)trimVideo:(NSURL*)videoToTrimURL
{
//[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:videoToTrimURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *outputURL = paths[0];
NSFileManager *manager = [NSFileManager defaultManager];
[manager createDirectoryAtPath:outputURL withIntermediateDirectories:YES attributes:nil error:nil];
outputURL = [outputURL stringByAppendingPathComponent:#"output.mp4"];
// Remove Existing File
[manager removeItemAtPath:outputURL error:nil];
exportSession.outputURL = [NSURL fileURLWithPath:outputURL];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
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]];
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;
}
//[exportSession release];
}];
}
Related
i have to split the video into two parts.i am using with this trim function twicely is that good approach i have read the AVFoundation frame work but didn't found any direct solution to split the video.but there are some iPhone Apps which are splitting the video very smoothly.are they using the trim function ? need suggestion
-(void)splitSecondVideo{
NSString *deleteVideo = [_videoPath path];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:_videoPath options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
NSString *outputURL = nil;
NSString *videoFileName = nil;
videoFileName = [SPUtility getDefaultVideoName];
outputURL = [NSString stringWithFormat:#"%#/%#.mov", _clipFolderPath, videoFileName];
NSFileManager *manager = [NSFileManager defaultManager];
[manager createDirectoryAtPath:outputURL withIntermediateDirectories:YES attributes:nil error:nil];
[manager removeItemAtPath:outputURL error:nil] ;
exportSession.outputURL = [NSURL fileURLWithPath:outputURL];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
// Trim to half duration
double halfDuration = CMTimeGetSeconds([asset duration])/2.0;
double fullDuration = CMTimeGetSeconds([asset duration]);
CMTime firsthalfDuration = CMTimeMakeWithSeconds(halfDuration, 1);
CMTime secondhalfDuration = CMTimeMakeWithSeconds(fullDuration, 1);
CMTimeRange secondrange = CMTimeRangeMake(firsthalfDuration, secondhalfDuration);
exportSession.timeRange = secondrange;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
[manager removeItemAtPath:deleteVideo error:nil];
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;
}
}];
}
I wanna merge a .caf file and a .mp3 file to a .mp3 file on iPhone,or I can convert them to .aac and then merge them.How can I do this ?
(Just Like Kala OK,I wanna merge my voice and the music together)
You need to decode both files to LPCM (plain old ints), add/mix them together then re-encode. The iPhone SDK does not support MP3 encoding, so you should re-encode to AAC.
The Apple sample code iPhoneExtAudioFileConvertTest would be a good place to start.
You can use this method
- (BOOL) combineVoices1
{
NSError *error = nil;
BOOL ok = NO;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
CMTime nextClipStartTime = kCMTimeZero;
//Create AVMutableComposition Object.This object will hold our multiple AVMutableCompositionTrack.
AVMutableComposition *composition = [[AVMutableComposition alloc] init];
AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack setPreferredVolume:0.8];
NSString *soundOne =[[NSBundle mainBundle]pathForResource:#"test1" ofType:#"caf"];
NSURL *url = [NSURL fileURLWithPath:soundOne];
AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *clipAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack atTime:kCMTimeZero error:nil];
AVMutableCompositionTrack *compositionAudioTrack1 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack setPreferredVolume:0.3];
NSString *soundOne1 =[[NSBundle mainBundle]pathForResource:#"test" ofType:#"caf"];
NSURL *url1 = [NSURL fileURLWithPath:soundOne1];
AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:url1 options:nil];
NSArray *tracks1 = [avAsset1 tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *clipAudioTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack1 atTime:kCMTimeZero error:nil];
AVMutableCompositionTrack *compositionAudioTrack2 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack2 setPreferredVolume:1.0];
NSString *soundOne2 =[[NSBundle mainBundle]pathForResource:#"song" ofType:#"caf"];
NSURL *url2 = [NSURL fileURLWithPath:soundOne2];
AVAsset *avAsset2 = [AVURLAsset URLAssetWithURL:url2 options:nil];
NSArray *tracks2 = [avAsset2 tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *clipAudioTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset2.duration) ofTrack:clipAudioTrack2 atTime:kCMTimeZero error:nil];
AVAssetExportSession *exportSession = [AVAssetExportSession
exportSessionWithAsset:composition
presetName:AVAssetExportPresetAppleM4A];
if (nil == exportSession) return NO;
NSString *soundOneNew = [documentsDirectory stringByAppendingPathComponent:#"combined10.m4a"];
//NSLog(#"Output file path - %#",soundOneNew);
// configure export session output with all our parameters
exportSession.outputURL = [NSURL fileURLWithPath:soundOneNew]; // output path
exportSession.outputFileType = AVFileTypeAppleM4A; // output file type
// perform the export
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (AVAssetExportSessionStatusCompleted == exportSession.status) {
NSLog(#"AVAssetExportSessionStatusCompleted");
} else if (AVAssetExportSessionStatusFailed == exportSession.status) {
// a failure may happen because of an event out of your control
// for example, an interruption like a phone call comming in
// make sure and handle this case appropriately
NSLog(#"AVAssetExportSessionStatusFailed");
} else {
NSLog(#"Export Session Status: %d", exportSession.status);
}
}];
return YES;
}
you can use the this SDAVAssetExportSession with the following code to export many files to AAC:
-(void)mergeAudioFiles
{
NSFileManager * fm = [[NSFileManager alloc] init];
NSError * error;
NSArray * filesNames = **NSArray of File Names;
NSString * filePath = #"Dest File Name";
NSString * pathToSave =[NSString stringWithFormat:#"%#%#",filePath,#".m4a"];
CMTime startTime = kCMTimeZero;
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionAudioTrack =[AVMutableCompositionTrack alloc];
compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
float audioEndTime=0;
for (NSString *fileName in filesNames) {
NSURL *audioUrl = [NSURL fileURLWithPath:fileName];
AVURLAsset *audioasset = [[AVURLAsset alloc]initWithURL:audioUrl options:nil];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, audioasset.duration);
AVAssetTrack *audioAssetTrack= [[audioasset tracksWithMediaType:AVMediaTypeAudio] lastObject];
[compositionAudioTrack insertTimeRange:timeRange ofTrack:audioAssetTrack atTime:startTime error:&error];
startTime = CMTimeAdd(startTime, timeRange.duration);
CMTime assetTime2 = [audioasset duration];
Float64 duration2 = CMTimeGetSeconds(assetTime2);
audioEndTime+=duration2;
}
NSURL *exportUrl = [NSURL fileURLWithPath:pathToSave];
float audioStartTime=0;
CMTime startTime1 = CMTimeMake((int)(floor(audioStartTime * 100)), 100);
CMTime stopTime = CMTimeMake((int)(ceil(audioEndTime * 100)), 100);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime1, stopTime);
SDAVAssetExportSession *encoder = [SDAVAssetExportSession.alloc initWithAsset:composition];
encoder.outputFileType = AVFileTypeAppleM4A;
encoder.outputURL = exportUrl;
encoder.audioSettings = #
{
AVFormatIDKey: #(kAudioFormatMPEG4AAC),
AVNumberOfChannelsKey: #2,
AVSampleRateKey: #44100,
AVEncoderBitRateKey: #128000,
};
encoder.timeRange = exportTimeRange;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSLog(#"Starting Audio Marge");
[encoder exportAsynchronouslyWithCompletionHandler:^
{
if (encoder.status == AVAssetExportSessionStatusCompleted)
{
NSLog(#"Audio Marge succeeded");
NSError * err = NULL;
BOOL result = [fm moveItemAtPath:pathToSave toPath:filePath error:&err];
if(!result) {
NSLog(#"Error: %#", err);
}
NSLog(#"Audio Copied");
} else if (encoder.status == AVAssetExportSessionStatusCancelled) {
NSLog(#"Audio export cancelled");
} else {
NSLog(#"Audio export failed with error: %# (%ld)", encoder.error.localizedDescription, encoder.error.code);
}
dispatch_semaphore_signal(semaphore);
}];
NSLog(#"Audio Wait to Finish");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//cleanup
for (NSString *fileName in filesNames) {
[fm removeItemAtPath:fileName error:&error];
}
NSLog(#"Audio Marge Finished");
}
merging two audio files code
-(void)mergeTwoAudioFile
{
NSError * error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Music_Directory"];
//first audio path
NSString *firstPath= [documentsDirectory stringByAppendingPathComponent:#"audio01.m4a"];
NSURL *audioUrl1 = [NSURL fileURLWithPath:firstPath];
AVMutableComposition *mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *audioCompositionTrack1 =[[AVMutableCompositionTrack alloc]init];
AVURLAsset *audioasset1 = [[AVURLAsset alloc]initWithURL:audioUrl1 options:nil];
AVAssetTrack *audioAssetTrack1= [[audioasset1 tracksWithMediaType:AVMediaTypeAudio] lastObject];
audioCompositionTrack1 = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
CMTime tempTime1= mixComposition.duration;
[audioCompositionTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioasset1.duration) ofTrack:audioAssetTrack1 atTime:tempTime1 error:&error];
//========second audio
NSString *secondPath= [documentsDirectory stringByAppendingPathComponent:#"audio02.m4a"];
NSURL *audioUrl2 = [NSURL fileURLWithPath:secondPath];
AVMutableCompositionTrack *audioCompositionTrack2 =[[AVMutableCompositionTrack alloc]init];
AVURLAsset *audioasset2 = [[AVURLAsset alloc]initWithURL:audioUrl2 options:nil];
AVAssetTrack *audioAssetTrack2= [[audioasset2 tracksWithMediaType:AVMediaTypeAudio] lastObject];
audioCompositionTrack2 = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
CMTime tempTime2 = mixComposition.duration;
[audioCompositionTrack2 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioasset2.duration) ofTrack:audioAssetTrack2 atTime:tempTime2 error:&error];
NSString * pathToSave = [NSString stringWithFormat:#"finalTest.m4a"];
pathToSave =[documentsDirectory stringByAppendingPathComponent:pathToSave];
NSURL *movieUrl = [NSURL fileURLWithPath:pathToSave];
AVAssetExportSession *exporter =[[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetAppleM4A];
exporter.shouldOptimizeForNetworkUse = YES;
exporter.outputURL = movieUrl;
exporter.outputFileType = AVFileTypeAppleM4A;
//====================================================================
float audioStartTime=0;
CMTime assetTime1 = [audioasset1 duration];
Float64 duration1 = CMTimeGetSeconds(assetTime1);
CMTime assetTime2 = [audioasset2 duration];
Float64 duration2 = CMTimeGetSeconds(assetTime2);
float audioEndTime=duration1+duration2;
CMTime startTime = CMTimeMake((int)(floor(audioStartTime * 100)), 100);
CMTime stopTime = CMTimeMake((int)(ceil(audioEndTime * 100)), 100);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exporter.timeRange =exportTimeRange;
//====================================================================
[exporter exportAsynchronouslyWithCompletionHandler:^(void) {
NSString* message;
switch (exporter.status) {
case AVAssetExportSessionStatusFailed:
message = [NSString stringWithFormat:#"Export failed. Error: %#", exporter.error.description];
NSLog(#"%#", message);
break;
case AVAssetExportSessionStatusCompleted:
message = [NSString stringWithFormat:#"Export completed"];
NSLog(#"%#", message);
break;
case AVAssetExportSessionStatusCancelled:
message = [NSString stringWithFormat:#"Export cancelled!"];
NSLog(#"%#", message);
break;
default:
NSLog(#"Export unhandled status: %ld", (long)exporter.status);
break;
}
}];
}
I used the following code to generate the video from array of images and audio (pre recorded)..
- (void)viewDidLoad
{
imagearray=[[NSMutableArray alloc]initWithObjects:#"Quiz pic1.jpg",#"Quiz pic2.jpg",#"Quiz pic3.jpg",#"Quiz pic6.jpg",#"Quiz pic7.jpg",nil];
image1array=[[NSMutableArray alloc]init];
for (int i=0; i<[imagearray count]; i++)
{
UIImage *aimage=[UIImage imageNamed:[imagearray objectAtIndex:i]];
[image1array addObject:aimage];
}
NSLog(#"%#",image1array);
ImageVideoPath=#"/Users/image/Library/Application Support/iPhone Simulator/4.3/Applications/6CC91208-5819-4BFF-B868-6605887861EB/Output";
FinalVideoPath=#"/Users/image/Library/Application Support/iPhone Simulator/4.3/Applications/6CC91208-5819-4BFF-B868-6605887861EB/VideoOutput";
CGSize size;
UIImage *image=[UIImage imageNamed:[imagearray objectAtIndex:0]];
size=image.size;
NSString *audioFilePath;
int duration=10;
//[self pixelBufferFromCGImage:[[image1array objectAtIndex:0] CGImage]];
[self writeImageAndAudioAsMovie:image andAudio:audioFilePath duration:duration];
//[self pixelBufferFromCGImage:[image CGImage] andSize:size];
[super viewDidLoad];
}
- (void)writeImageAndAudioAsMovie:(UIImage*)image andAudio:(NSString *)audioFilePath duration:(int)duration {
NSLog(#"start make movie: length:%d",duration);
NSError *error = nil;
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:ImageVideoPath] fileType:AVFileTypeQuickTimeMovie
error:&error];
NSParameterAssert(videoWriter);
if ([[NSFileManager defaultManager] fileExistsAtPath:ImageVideoPath])
[[NSFileManager defaultManager] removeItemAtPath:ImageVideoPath error:nil];
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:image.size.width],AVVideoWidthKey,[NSNumber numberWithInt:image.size.height], AVVideoHeightKey,nil];
AVAssetWriterInput* writerInput = [[AVAssetWriterInput
assetWriterInputWithMediaType:AVMediaTypeVideo
outputSettings:videoSettings] retain];
AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:nil];
NSParameterAssert(writerInput);
NSParameterAssert([videoWriter canAddInput:writerInput]);
writerInput.expectsMediaDataInRealTime = YES;
[videoWriter setShouldOptimizeForNetworkUse:YES];
[videoWriter addInput:writerInput];
//Start a session:
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
//Write samples:
CVPixelBufferRef buffer = [self pixelBufferFromCGImage:image.CGImage];
[adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];
//Finish the session:
[videoWriter endSessionAtSourceTime:CMTimeMake(duration, 1)];
[writerInput markAsFinished];
[videoWriter finishWriting];
CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
[videoWriter release];
[writerInput release];
audioFilePath=[[NSBundle mainBundle]pathForResource:#"Video" ofType:#"mp3"];
NSLog(#"%#",audioFilePath);
[self addAudioToFileAtPath:ImageVideoPath andAudioPath:audioFilePath];
}
-(CVPixelBufferRef)pixelBufferFromCGImage: (CGImageRef) image{
float width = CGImageGetWidth(image);
float height = CGImageGetHeight(image);
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
nil];
CVPixelBufferRef pxbuffer = NULL;
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, width,height, kCVPixelFormatType_32ARGB,(CFDictionaryRef)options,&pxbuffer);
NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
CVPixelBufferLockBaseAddress(pxbuffer, 0);
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
NSParameterAssert(pxdata != NULL);
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pxdata,width,height,8,4*width,rgbColorSpace,kCGImageAlphaNoneSkipFirst);
NSParameterAssert(context);
CGContextDrawImage(context, CGRectMake(0, 0,width, height), image);
CGColorSpaceRelease(rgbColorSpace);
CGContextRelease(context);
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
return pxbuffer;
}
-(void) addAudioToFileAtPath:(NSString *)vidoPath andAudioPath:(NSString *)audioFilePath{
AVMutableComposition* mixComposition = [AVMutableComposition composition];
NSLog(#"%# %#",ImageVideoPath,audioFilePath);
NSURL* audio_inputFileUrl = [NSURL fileURLWithPath:audioFilePath];
NSURL* video_inputFileUrl = [NSURL fileURLWithPath:ImageVideoPath];
NSLog(#"%#",video_inputFileUrl);
NSString *outputFilePath = FinalVideoPath;
NSURL* outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
[[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];
AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audio_inputFileUrl options:nil];
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:video_inputFileUrl options:nil];
NSLog(#"asset:%#",videoAsset);
NSArray *tracks1=[videoAsset tracksWithMediaType:AVMediaTypeVideo];
if ([tracks1 count]>0)
{
//CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
AVAssetTrack *videoAssetTrack=[tracks1 objectAtIndex:0];
AVMutableCompositionTrack *a_compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[a_compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,videoAsset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:nil];
}
NSArray *tracks = [audioAsset tracksWithMediaType:AVMediaTypeAudio];
if([tracks count]>0)
{
AVAssetTrack * audioAssetTrack = [tracks objectAtIndex:0];
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID: kCMPersistentTrackID_Invalid];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,audioAsset.duration) ofTrack:audioAssetTrack atTime:kCMTimeZero error:nil];
//nextClipStartTime = CMTimeAdd(nextClipStartTime, a_timeRange.duration);
[audioAsset release];audioAsset = nil;
}
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
_assetExport.outputFileType = AVFileTypeMPEG4;
_assetExport.outputURL = outputFileUrl;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
switch (_assetExport.status)
{
case AVAssetExportSessionStatusCompleted:
//export complete
NSLog(#"Export Complete");
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Export Failed");
NSLog(#"ExportSessionError: %#", [_assetExport.error localizedDescription]);
//export error (see exportSession.error)
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export Failed");
NSLog(#"ExportSessionError: %#", [_assetExport.error localizedDescription]);
//export cancelled
break;
}
}];
}
I found that one of the video file is created from the method writeImageAndAudioAsMovie but itz nt supporting any player in my machine...
I don't knw wat I'm missing? Any suggestions plz....
The problem lies at two places :
1.The path you are providing should be something where you are allowed to write like documents directory. And it must have some specific extenstion. As you are creating HighestQualityVideo so it should be .mov.
2.You should provide proper outputFileType should be as per extension and presetType. so in your case it should be _assetExport.outputFileType = AVFileTypeQuickTimeMovie;.
Try with these changes.
Update:
To remove the crash you need to replace code for AVAssetTrack with following code in addAudioToFileAtPath method:
NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeAudio];
if([tracks count]>0)
{
AVAssetTrack * audioAssetTrack = [tracks objectAtIndex:0];
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID: kCMPersistentTrackID_Invalid];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,videoAsset.duration) ofTrack:audioAssetTrack atTime:kCMTimeZero error:nil];
//nextClipStartTime = CMTimeAdd(nextClipStartTime, a_timeRange.duration);
[audioAsset release];audioAsset = nil;
}
Regarding video types:
Facebook supports QuickTimeVideo(mov/qt) see http://www.facebook.com/help/?faq=218673814818907
To support other type of videos you will need to change the presetName while creating AVAssetExportSession object and extension of output file for this please go through this document.
http://www.google.co.in/url?sa=t&rct=j&q=AVAssetExportSession++class&source=web&cd=1&ved=0CCYQFjAA&url=http%3A%2F%2Fdeveloper.apple.com%2Flibrary%2Fios%2FDOCUMENTATION%2FAVFoundation%2FReference%2FAVAssetExportSession_Class%2FReference%2FReference.html&ei=xXxPT5akDsG8rAeck5XUDQ&usg=AFQjCNH1HqxIiT1kYJom6kZ82NS-qjVSyQ&cad=rja
Update 1:
Here we are accessing each image and appending it to buffer after displaying some time(I have divided duration.
for (int i=0; i<[image1array count]; i++)
{
int time = (int)i*(duration/[image1array count]);
CVPixelBufferRef buffer = [self pixelBufferFromCGImage:[[image1array objectAtIndex:i] CGImage]];
[adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(time, 1)];
}
Update 2:
Here is the code that I in which I have made few changes to compose a mixed asset.
-(void) addAudioToFileAtPath:(NSString *)vidoPath andAudioPath:(NSString *)audioFilePath{
NSURL* audio_inputFileUrl = [NSURL fileURLWithPath:audioFilePath];
NSURL* video_inputFileUrl = [NSURL fileURLWithPath:ImageVideoPath];
NSURL* outputFileUrl = [NSURL fileURLWithPath:FinalVideoPath];
AVMutableComposition *composition = [AVMutableComposition composition];
AVAsset * audioAsset = [AVURLAsset URLAssetWithURL:audio_inputFileUrl options:nil];;
AVAsset * videoAsset = [AVURLAsset URLAssetWithURL:video_inputFileUrl options:nil];
AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *error = nil;
BOOL ok = NO;
CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
AVAssetTrack *sourceVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
ok = [compositionVideoTrack insertTimeRange:video_timeRange ofTrack:sourceVideoTrack atTime:kCMTimeZero error:&error];
if (!ok) {
// Deal with the error.
NSLog(#"Error : %# : %d",error,videoAsset.duration.value);
}
CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, audioAsset.duration);
AVAssetTrack *sourceAudioTrack = [[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
ok = [compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:sourceAudioTrack atTime:kCMTimeZero error:&error];
if (!ok) {
// Deal with the error.
NSLog(#"Error : %# : %d",error,audioAsset.duration.value);
}
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetHighestQuality];
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
_assetExport.outputURL = outputFileUrl;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
switch (_assetExport.status)
{
case AVAssetExportSessionStatusCompleted:
//export complete
NSLog(#"Export Complete");
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Export Failed");
NSLog(#"ExportSessionError: %#", [_assetExport.error localizedDescription]);
//export error (see exportSession.error)
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export Failed");
NSLog(#"ExportSessionError: %#", [_assetExport.error localizedDescription]);
//export cancelled
break;
}
NSLog(#"Error : %#",_assetExport.error);
}];
}
Thanks,
One thing that caught my eye was that you're calling CVPixelBufferPoolRelease(adaptor.pixelBufferPool); in your writeImageAndAudioAsMovie:andAudio:duration: method but since you didn't create adaptor.pixelBufferPool, you don't own it and therefore shouldn't be releasing it, right? Seems suspect to me.
Im syncing the audio and video files using AVURLAsset.Im getting the exported file but only audio is exported and not the video.How to solve this issue.please help me.Thanks in advance.
Im using the code below:
moviePlayer = [[VideoPlay alloc]initWithNibName:#"VideoPlay" bundle:nil];
if(sp==1){
NSURL *VUrl = [NSURL URLWithString:elements.videoUrl];
NSURL *AUrl = [NSURL URLWithString:elements.audioUrl1 ];
NSLog(#"%#--%#",AUrl,VUrl);
AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:AUrl options:nil];
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:VUrl options:nil];
AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionCommentaryTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration)
ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]
atTime:kCMTimeZero error:nil];
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
atTime:kCMTimeZero error:nil];
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition
presetName:AVAssetExportPresetPassthrough];
NSString *videoName = #"export.m4v";
NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
{
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
NSLog(#"Export Status %d-- ", _assetExport.status);
_assetExport.outputFileType = #"com.apple.quicktime-movie";
NSLog(#"file type %#",_assetExport.outputFileType);
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
NSLog(#"hello");
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:
{
// // [self performSelectorOnMainThread:#selector (saveVideoToAlbum:)
// withObject:exportPath
// waitUntilDone:NO];
break;
}
case AVAssetExportSessionStatusCancelled:
{
NSLog (#"CANCELED");
break;
}
}
NSLog(#"Export Status %d-- %#", _assetExport.status, _assetExport.outputURL);
if(_assetExport.status==3){
moviePlayer.videolink = _assetExport.outputURL;
[self presentModalViewController:moviePlayer animated:YES];
[moviePlayer readyPlayer];
}
}
];
}
Simplify your code to the smallest working sample that shows the problem.
Check the return errors.
Try a different export preset instead of AVAssetExportPresetPassthrough.
Try a different export preset instead of AVAssetExportPresetPassthrough
and NSString *videoName = #"export.mp4" instead of NSString *videoName = #"export.m4v";
I wanna merge a .caf file and a .mp3 file to a .mp3 file on iPhone,or I can convert them to .aac and then merge them.How can I do this ?
(Just Like Kala OK,I wanna merge my voice and the music together)
You need to decode both files to LPCM (plain old ints), add/mix them together then re-encode. The iPhone SDK does not support MP3 encoding, so you should re-encode to AAC.
The Apple sample code iPhoneExtAudioFileConvertTest would be a good place to start.
You can use this method
- (BOOL) combineVoices1
{
NSError *error = nil;
BOOL ok = NO;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
CMTime nextClipStartTime = kCMTimeZero;
//Create AVMutableComposition Object.This object will hold our multiple AVMutableCompositionTrack.
AVMutableComposition *composition = [[AVMutableComposition alloc] init];
AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack setPreferredVolume:0.8];
NSString *soundOne =[[NSBundle mainBundle]pathForResource:#"test1" ofType:#"caf"];
NSURL *url = [NSURL fileURLWithPath:soundOne];
AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
NSArray *tracks = [avAsset tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *clipAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack atTime:kCMTimeZero error:nil];
AVMutableCompositionTrack *compositionAudioTrack1 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack setPreferredVolume:0.3];
NSString *soundOne1 =[[NSBundle mainBundle]pathForResource:#"test" ofType:#"caf"];
NSURL *url1 = [NSURL fileURLWithPath:soundOne1];
AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:url1 options:nil];
NSArray *tracks1 = [avAsset1 tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *clipAudioTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) ofTrack:clipAudioTrack1 atTime:kCMTimeZero error:nil];
AVMutableCompositionTrack *compositionAudioTrack2 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack2 setPreferredVolume:1.0];
NSString *soundOne2 =[[NSBundle mainBundle]pathForResource:#"song" ofType:#"caf"];
NSURL *url2 = [NSURL fileURLWithPath:soundOne2];
AVAsset *avAsset2 = [AVURLAsset URLAssetWithURL:url2 options:nil];
NSArray *tracks2 = [avAsset2 tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *clipAudioTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionAudioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset2.duration) ofTrack:clipAudioTrack2 atTime:kCMTimeZero error:nil];
AVAssetExportSession *exportSession = [AVAssetExportSession
exportSessionWithAsset:composition
presetName:AVAssetExportPresetAppleM4A];
if (nil == exportSession) return NO;
NSString *soundOneNew = [documentsDirectory stringByAppendingPathComponent:#"combined10.m4a"];
//NSLog(#"Output file path - %#",soundOneNew);
// configure export session output with all our parameters
exportSession.outputURL = [NSURL fileURLWithPath:soundOneNew]; // output path
exportSession.outputFileType = AVFileTypeAppleM4A; // output file type
// perform the export
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (AVAssetExportSessionStatusCompleted == exportSession.status) {
NSLog(#"AVAssetExportSessionStatusCompleted");
} else if (AVAssetExportSessionStatusFailed == exportSession.status) {
// a failure may happen because of an event out of your control
// for example, an interruption like a phone call comming in
// make sure and handle this case appropriately
NSLog(#"AVAssetExportSessionStatusFailed");
} else {
NSLog(#"Export Session Status: %d", exportSession.status);
}
}];
return YES;
}
you can use the this SDAVAssetExportSession with the following code to export many files to AAC:
-(void)mergeAudioFiles
{
NSFileManager * fm = [[NSFileManager alloc] init];
NSError * error;
NSArray * filesNames = **NSArray of File Names;
NSString * filePath = #"Dest File Name";
NSString * pathToSave =[NSString stringWithFormat:#"%#%#",filePath,#".m4a"];
CMTime startTime = kCMTimeZero;
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionAudioTrack =[AVMutableCompositionTrack alloc];
compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
float audioEndTime=0;
for (NSString *fileName in filesNames) {
NSURL *audioUrl = [NSURL fileURLWithPath:fileName];
AVURLAsset *audioasset = [[AVURLAsset alloc]initWithURL:audioUrl options:nil];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, audioasset.duration);
AVAssetTrack *audioAssetTrack= [[audioasset tracksWithMediaType:AVMediaTypeAudio] lastObject];
[compositionAudioTrack insertTimeRange:timeRange ofTrack:audioAssetTrack atTime:startTime error:&error];
startTime = CMTimeAdd(startTime, timeRange.duration);
CMTime assetTime2 = [audioasset duration];
Float64 duration2 = CMTimeGetSeconds(assetTime2);
audioEndTime+=duration2;
}
NSURL *exportUrl = [NSURL fileURLWithPath:pathToSave];
float audioStartTime=0;
CMTime startTime1 = CMTimeMake((int)(floor(audioStartTime * 100)), 100);
CMTime stopTime = CMTimeMake((int)(ceil(audioEndTime * 100)), 100);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime1, stopTime);
SDAVAssetExportSession *encoder = [SDAVAssetExportSession.alloc initWithAsset:composition];
encoder.outputFileType = AVFileTypeAppleM4A;
encoder.outputURL = exportUrl;
encoder.audioSettings = #
{
AVFormatIDKey: #(kAudioFormatMPEG4AAC),
AVNumberOfChannelsKey: #2,
AVSampleRateKey: #44100,
AVEncoderBitRateKey: #128000,
};
encoder.timeRange = exportTimeRange;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSLog(#"Starting Audio Marge");
[encoder exportAsynchronouslyWithCompletionHandler:^
{
if (encoder.status == AVAssetExportSessionStatusCompleted)
{
NSLog(#"Audio Marge succeeded");
NSError * err = NULL;
BOOL result = [fm moveItemAtPath:pathToSave toPath:filePath error:&err];
if(!result) {
NSLog(#"Error: %#", err);
}
NSLog(#"Audio Copied");
} else if (encoder.status == AVAssetExportSessionStatusCancelled) {
NSLog(#"Audio export cancelled");
} else {
NSLog(#"Audio export failed with error: %# (%ld)", encoder.error.localizedDescription, encoder.error.code);
}
dispatch_semaphore_signal(semaphore);
}];
NSLog(#"Audio Wait to Finish");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//cleanup
for (NSString *fileName in filesNames) {
[fm removeItemAtPath:fileName error:&error];
}
NSLog(#"Audio Marge Finished");
}
merging two audio files code
-(void)mergeTwoAudioFile
{
NSError * error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Music_Directory"];
//first audio path
NSString *firstPath= [documentsDirectory stringByAppendingPathComponent:#"audio01.m4a"];
NSURL *audioUrl1 = [NSURL fileURLWithPath:firstPath];
AVMutableComposition *mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *audioCompositionTrack1 =[[AVMutableCompositionTrack alloc]init];
AVURLAsset *audioasset1 = [[AVURLAsset alloc]initWithURL:audioUrl1 options:nil];
AVAssetTrack *audioAssetTrack1= [[audioasset1 tracksWithMediaType:AVMediaTypeAudio] lastObject];
audioCompositionTrack1 = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
CMTime tempTime1= mixComposition.duration;
[audioCompositionTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioasset1.duration) ofTrack:audioAssetTrack1 atTime:tempTime1 error:&error];
//========second audio
NSString *secondPath= [documentsDirectory stringByAppendingPathComponent:#"audio02.m4a"];
NSURL *audioUrl2 = [NSURL fileURLWithPath:secondPath];
AVMutableCompositionTrack *audioCompositionTrack2 =[[AVMutableCompositionTrack alloc]init];
AVURLAsset *audioasset2 = [[AVURLAsset alloc]initWithURL:audioUrl2 options:nil];
AVAssetTrack *audioAssetTrack2= [[audioasset2 tracksWithMediaType:AVMediaTypeAudio] lastObject];
audioCompositionTrack2 = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
CMTime tempTime2 = mixComposition.duration;
[audioCompositionTrack2 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioasset2.duration) ofTrack:audioAssetTrack2 atTime:tempTime2 error:&error];
NSString * pathToSave = [NSString stringWithFormat:#"finalTest.m4a"];
pathToSave =[documentsDirectory stringByAppendingPathComponent:pathToSave];
NSURL *movieUrl = [NSURL fileURLWithPath:pathToSave];
AVAssetExportSession *exporter =[[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetAppleM4A];
exporter.shouldOptimizeForNetworkUse = YES;
exporter.outputURL = movieUrl;
exporter.outputFileType = AVFileTypeAppleM4A;
//====================================================================
float audioStartTime=0;
CMTime assetTime1 = [audioasset1 duration];
Float64 duration1 = CMTimeGetSeconds(assetTime1);
CMTime assetTime2 = [audioasset2 duration];
Float64 duration2 = CMTimeGetSeconds(assetTime2);
float audioEndTime=duration1+duration2;
CMTime startTime = CMTimeMake((int)(floor(audioStartTime * 100)), 100);
CMTime stopTime = CMTimeMake((int)(ceil(audioEndTime * 100)), 100);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exporter.timeRange =exportTimeRange;
//====================================================================
[exporter exportAsynchronouslyWithCompletionHandler:^(void) {
NSString* message;
switch (exporter.status) {
case AVAssetExportSessionStatusFailed:
message = [NSString stringWithFormat:#"Export failed. Error: %#", exporter.error.description];
NSLog(#"%#", message);
break;
case AVAssetExportSessionStatusCompleted:
message = [NSString stringWithFormat:#"Export completed"];
NSLog(#"%#", message);
break;
case AVAssetExportSessionStatusCancelled:
message = [NSString stringWithFormat:#"Export cancelled!"];
NSLog(#"%#", message);
break;
default:
NSLog(#"Export unhandled status: %ld", (long)exporter.status);
break;
}
}];
}