In One of my application i need to add some image in video. so i cut break video in two part and also make one video from that image. now i want to combine this three video file and make one video file. but i am not get any idea to combine this three video. i see some code over here. but that is not helpful to me. for break video and for make video from image i used below code now i want code to merge this all video.
Any other idea for put current view screen in video file in between.
For break video file
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Affagogato" ofType:#"mp4"]];
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
for(int i = 0; i < 2; i++) {
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
initWithAsset:anAsset presetName:AVAssetExportPresetLowQuality];
NSString *filePath = nil;
NSUInteger count = 0;
do {
filePath = NSTemporaryDirectory();
NSString *numberString = count > 0 ? [NSString stringWithFormat:#"-%i", count] : #"";
filePath = [filePath stringByAppendingPathComponent:[NSString stringWithFormat:#"Output-%#.mov", numberString]];
count++;
} while([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
exportSession.outputURL = [NSURL fileURLWithPath:filePath];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTimeRange range;
if(i == 0){
CMTime start = CMTimeMakeWithSeconds(0.0, 600);
CMTime duration = CMTimeMakeWithSeconds(10.0, 600);
range = CMTimeRangeMake(start, duration);
}else{
CMTime start = CMTimeMakeWithSeconds(10.0, 600);
range = CMTimeRangeMake(start, anAsset.duration);
}
exportSession.timeRange = range;
[exportSession exportAsynchronouslyWithCompletionHandler:^
{
dispatch_async(dispatch_get_main_queue(), ^{
[self exportDidFinish:exportSession Tag:i];
});
}];
}
Get video from Images
CGRect rect=CGRectMake(0, 0, 320, 480);
view = [[UIView alloc]initWithFrame:rect];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *path = [documentsDirectory stringByAppendingPathComponent:[#"video2" stringByAppendingString:#".mov"]];
CGSize size = self.view.frame.size;
NSMutableDictionary *attributes = [[NSMutableDictionary alloc]init];
[attributes setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32ARGB] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:320] forKey:(NSString*)kCVPixelBufferWidthKey];
[attributes setObject:[NSNumber numberWithUnsignedInt:480] forKey:(NSString*)kCVPixelBufferHeightKey];
NSError *error = nil;
AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:
[NSURL fileURLWithPath:path] fileType:AVFileTypeQuickTimeMovie
error:&error];
NSParameterAssert(videoWriter);
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264, AVVideoCodecKey,
[NSNumber numberWithInt:size.width], AVVideoWidthKey,
[NSNumber numberWithInt: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]);
[videoWriter addInput:writerInput];
//Start a session:
[videoWriter startWriting];
[videoWriter startSessionAtSourceTime:kCMTimeZero];
CVPixelBufferRef buffer = NULL;
//convert uiimage to CGImage.
xPixel=0;
yPixel=250;
buffer = [self pixelBufferFromCGImage:[[UIImage imageNamed:#"1.jpeg"] CGImage]];
CVPixelBufferPoolCreatePixelBuffer (NULL, adaptor.pixelBufferPool, &buffer);
[adaptor appendPixelBuffer:buffer withPresentationTime:kCMTimeZero];
for (int i = 0;i<2; i++)
{
if([writerInput isReadyForMoreMediaData])
{
//NSLog(#"inside for loop %d",i);
for(int pframetime=1;pframetime<=2;pframetime++)
{
CMTime frameTime = CMTimeMake(pframetime,25);
CMTime lastTime=CMTimeMake(i,1); //i is from 0 to 19 of the loop above
CMTime presentTime=CMTimeAdd(lastTime, frameTime);
if(i==0)
buffer = [self pixelBufferFromCGImage:[[UIImage imageNamed:#"1.jpeg"] CGImage]];
else
buffer = [self pixelBufferFromCGImage:[[UIImage imageNamed:#"2.jpeg"] CGImage]];
while ( ![writerInput isReadyForMoreMediaData] )
{
[NSThread sleepForTimeInterval:0.05];
}
[adaptor appendPixelBuffer:buffer withPresentationTime:presentTime];
i++;
}
if(buffer)
CVBufferRelease(buffer);
//[NSThread sleepForTimeInterval:0.1];
}
}
[writerInput markAsFinished];
[videoWriter finishWriting];
[videoPathArray addObject:path];
//Finish the session:
[videoWriter release];
[writerInput release];
CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
For Merge video files i try this code but not useful here is some blank screen between video
AVMutableComposition* mixComposition = [AVMutableComposition composition];
NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* video_inputFilePath1 = [videoPathArray objectAtIndex:1];
NSURL* video_inputFileUrl1 = [NSURL fileURLWithPath:video_inputFilePath1];
NSString* video_inputFilePath2 = [videoPathArray objectAtIndex:0];
NSURL* video_inputFileUrl2 = [NSURL fileURLWithPath:video_inputFilePath2];
NSString* video_inputFilePath3 = [videoPathArray objectAtIndex:2];
NSURL* video_inputFileUrl3 = [NSURL fileURLWithPath:video_inputFilePath3];
NSString* outputFileName = #"outputFile.mov";
NSString* outputFilePath = [NSString stringWithFormat:#"%#/%#",documentsDirectoryPath,outputFileName];
NSURL* outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
[[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];
CMTime nextClipStartTime = kCMTimeZero;
AVURLAsset* videoAsset1 = [[AVURLAsset alloc]initWithURL:video_inputFileUrl1 options:nil];
AVURLAsset* videoAsset2 = [[AVURLAsset alloc]initWithURL:video_inputFileUrl2 options:nil];
AVURLAsset* videoAsset3 = [[AVURLAsset alloc]initWithURL:video_inputFileUrl3 options:nil];
CMTimeRange video_timeRange1 = CMTimeRangeMake(kCMTimeZero,videoAsset1.duration);
AVMutableCompositionTrack *a_compositionVideoTrack1 = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[a_compositionVideoTrack1 insertTimeRange:video_timeRange1 ofTrack:[[videoAsset1 tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:nextClipStartTime error:nil];
CMTimeRange video_timeRange3 = CMTimeRangeMake(nextClipStartTime,videoAsset3.duration);
[a_compositionVideoTrack1 insertTimeRange:video_timeRange3 ofTrack:[[videoAsset3 tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:videoAsset1.duration error:nil];
CMTimeRange video_timeRange2 = CMTimeRangeMake(nextClipStartTime,videoAsset1.duration);
[a_compositionVideoTrack1 insertTimeRange:video_timeRange2 ofTrack:[[videoAsset2 tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:videoAsset1.duration error:nil];
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetLowQuality];
_assetExport.shouldOptimizeForNetworkUse = YES;
_assetExport.outputFileType = #"com.apple.quicktime-movie";
_assetExport.outputURL = outputFileUrl;
Try watching the video called "Working with Media in AV Foundation" in the apple developers portal. It tells you how to do what you are describing.
https://developer.apple.com/videos/wwdc/2011/
Related
I am recording video and saving it in application's document folder.I want to flip the frames of video and save it so that video play in flipped mode like mirrored video.I am not getting how to achieve this. I tried to flip the video but it is saving as blank video.
Here is code to flip video
NSURL *assetURL = self.outPutUrl;
AVAsset *movieAsset = [AVAsset assetWithURL:assetURL];
NSLog(#"Asset: %0.1f",CMTimeGetSeconds(movieAsset.duration));
NSLog(#"Asset Preferred Transform %#", NSStringFromCGAffineTransform(movieAsset.preferredTransform));
//Output Composition
AVMutableComposition *outputComposition = [[AVMutableComposition alloc] init];
AVMutableCompositionTrack *videoTrack = [outputComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, movieAsset.duration)
ofTrack:[[movieAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
atTime:kCMTimeZero
error:nil];
[videoTrack setPreferredTransform:CGAffineTransformMakeScale(1, -1)];
AVMutableVideoCompositionLayerInstruction *videoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[videoLayerInstruction setTransform:CGAffineTransformMakeScale(1, -1) atTime:kCMTimeZero];
AVMutableVideoCompositionInstruction *videoInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
videoInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, movieAsset.duration);
videoInstruction.layerInstructions = [NSArray arrayWithObjects:videoLayerInstruction, nil];
AVMutableVideoComposition *outputVideoComposition = [AVMutableVideoComposition videoComposition];
outputVideoComposition.instructions = [NSArray arrayWithObjects:videoInstruction, nil];
outputVideoComposition.frameDuration = CMTimeMake(1, 30);
outputVideoComposition.renderSize = CGSizeMake(480, 640);
//Export
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:outputComposition presetName:AVAssetExportPresetHighestQuality] ;
exporter.videoComposition = outputVideoComposition;
NSArray *filePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [filePath objectAtIndex:0];
NSString *newPath = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"FinalVideo-%d.mov",arc4random() % 1000]];
[[NSFileManager defaultManager] removeItemAtPath:newPath error:nil];
exporter.outputURL = [NSURL fileURLWithPath:newPath];
exporter.outputFileType = AVFileTypeQuickTimeMovie;
NSLog(#"Starting export%#",exporter.outputURL);
[exporter exportAsynchronouslyWithCompletionHandler:^(void){
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Video exported");
NSLog(#"%#", newPath);
NSURL *newAssetURL = [NSURL fileURLWithPath:newPath];
AVAsset *newMovieAsset = [AVAsset assetWithURL:newAssetURL];
NSLog(#"New Asset %#",newMovieAsset);
NSLog(#"New Asset Duration: %0.1f",CMTimeGetSeconds(newMovieAsset.duration));
NSLog(#"New Asset Preferred Transform %#", NSStringFromCGAffineTransform(newMovieAsset.preferredTransform));
UISaveVideoAtPathToSavedPhotosAlbum(newPath, nil, nil, nil);
});
}];
Please help!
Thanks!
Check this link.. I think you want to reverse the video clip.. It worked for me..
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];
}];
}
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.
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;
}
}];
}