I want to convert a MP4-file from the apps Document folder into an Audio-file (mp3 or m4a).
I already tried, but i can not play the converted MP3-file with AVPlayer.
Here is my code:
-(void)convertMP4toMP3withFile:(NSString*)dstPath
{
NSURL *dstURL = [NSURL fileURLWithPath:dstPath];
AVMutableComposition* newAudioAsset = [AVMutableComposition composition];
AVMutableCompositionTrack* dstCompositionTrack;
dstCompositionTrack = [newAudioAsset addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
AVAsset* srcAsset = [AVURLAsset URLAssetWithURL:dstURL options:nil];
AVAssetTrack* srcTrack = [[srcAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
CMTimeRange timeRange = srcTrack.timeRange;
NSError* error;
if(NO == [dstCompositionTrack insertTimeRange:timeRange ofTrack:srcTrack atTime:kCMTimeZero error:&error]) {
NSLog(#"track insert failed: %#\n", error);
return;
}
AVAssetExportSession* exportSesh = [[AVAssetExportSession alloc] initWithAsset:newAudioAsset presetName:AVAssetExportPresetPassthrough];
exportSesh.outputFileType = AVFileTypeAppleM4A;
exportSesh.outputURL = dstURL;
[[NSFileManager defaultManager] removeItemAtURL:dstURL error:nil];
[exportSesh exportAsynchronouslyWithCompletionHandler:^{
AVAssetExportSessionStatus status = exportSesh.status;
NSLog(#"exportAsynchronouslyWithCompletionHandler: %i\n", status);
if(AVAssetExportSessionStatusFailed == status) {
NSLog(#"FAILURE: %#\n", exportSesh.error);
} else if(AVAssetExportSessionStatusCompleted == status) {
NSLog(#"SUCCESS!\n");
NSError *error;
//append the name of the file in jpg form
//check if the file exists (completely unnecessary).
NSString *onlyPath = [dstPath stringByDeletingLastPathComponent];
NSString *toPathString = [NSString stringWithFormat:#"%#/testfile.m4a", onlyPath];
[[NSFileManager defaultManager] moveItemAtPath:dstPath toPath:toPathString error:&error];
[self loadFiles];
}
}];
}
Has anyone a solution for my problem or can improve my code?
replace this line:
exportSesh.outputFileType = AVFileTypeAppleM4A;
with:
exportSesh.outputFileType = AVFileTypeCoreAudioFormat;
& this:
NSString *toPathString = [NSString stringWithFormat:#"%#/testfile.m4a", onlyPath];
with:
NSString *toPathString = [NSString stringWithFormat:#"%#/testfile.mp3", onlyPath];
Worked for me :)
The code does work on converting mp4 to m4a. Maybe your play audio file code is wrong. Following questions may be helpful to you.
No sound coming from AVPlayer
iOS Extracting Audio from .mov file
Related
How do I save slideshow created in camera roll?
(NSString *))handler;
{
AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:videoPath] options:nil];
NSError * error = nil;
for (int i=0;i<[arrayOfSounds count];i++)
{
NSString *pathString = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%#", [arrayOfSounds objectAtIndex:i]] ofType:#"mp3"];
NSLog(#"pathString = %#",pathString);
AVURLAsset * urlAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:pathString] options:nil];
AVAssetTrack * audioAssetTrack = [[urlAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID: kCMPersistentTrackID_Invalid];
CMTime audioDuration = videoAsset.duration;
audioDurationSeconds = CMTimeGetSeconds(audioDuration);
int startDur= [[arrayOfTime objectAtIndex:i] intValue];
NSLog(#"startDur = %d",startDur);
CMTime audioStartTime = CMTimeMake(i,1);
CMTime presentTime = CMTimeMake(1, 1);
CMTime EndTime = CMTimeMake(audioDurationSeconds, 1);
CMTime audioEndTime = CMTimeAdd(presentTime, EndTime);
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(presentTime,audioEndTime) ofTrack:audioAssetTrack atTime:audioStartTime error:&error];
}
NSString* movPath = [NSString stringWithFormat:#"%#/%#",documentsDirectory,#"Export.mov"];
//AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:movPath] options:nil];
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
NSError* vidError;
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:([videoAsset tracksWithMediaType:AVMediaTypeVideo].count >0)? [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]:nil atTime:kCMTimeZero error:&vidError];
NSLog(#"Vid error = %#",vidError);
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetPassthrough];
NSString* videoName = #"exportFinal.mov";
NSString *exportPath = [NSString stringWithFormat:#"%#/%#",documentsDirectory,videoName];
NSLog(#"exportPath = %#",exportPath);
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
{
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
_assetExport.outputFileType = #"com.apple.quicktime-movie";
NSLog(#"file type %#",_assetExport.outputFileType);
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
switch (_assetExport.status)
{
case AVAssetExportSessionStatusCompleted:
//export complete
NSLog(#"Export Complete");
//[self uploadToYouTube];
[self cleanUpProcess];
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;
}
}];
}
- (void)cleanUpProcess{
NSError* error;
NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:&error];
for(NSString* myFiles in files){
if([[myFiles pathExtension] isEqualToString:#"mov"]){
continue;
}
NSString* filePath = [NSString stringWithFormat:#"%#/%#",documentsDirectory,myFiles];
if(![[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]){
NSLog(#"Error Deleting");
}
}
}
It is saved in this path:
"Users/devendrasingh/Library/Developer/CoreSimulator/Devices/394AD1C9-E950-422E-BDA1-083CDCEE83F6/data/Containers/Data/Application/98BEC162-C686-4BC1-B698-567B45D65F27/Documents/exportFinal.mov
"
It's not saving in camera roll
Try this:
[[[ALAssetsLibrary alloc] init] writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
if (error)
NSLog(#"%#", error);
[[NSFileManager defaultManager] removeItemAtURL:outputFileURL error:nil];
}];
i have using this code which is working perfectly fine on previous version of IOS 9. but on IOS 9 version it is always going AVAssetExportSessionStatusFailed
AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/firstPart.caf",docsDir]] options:nil];
AVAsset *avAsset2 = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/New-Recording.caf",docsDir]] options:nil];
AVMutableComposition *composition = [[AVMutableComposition alloc] init];
[composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack *assetTrack1;
AVAssetTrack *assetTrack2;
if ([avAsset1 tracksWithMediaType:AVMediaTypeAudio].count > 0) {
assetTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
assetTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
}
CMTime insertionPoint = kCMTimeZero;
[track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset1.duration) ofTrack:assetTrack1 atTime:insertionPoint error:nil];
insertionPoint = CMTimeAdd(insertionPoint, avAsset1.duration);
[track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset2.duration) ofTrack:assetTrack2 atTime:insertionPoint error:nil];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/mergedFilePart1.caf",documentsDirectory]];
exportSession.outputFileType = AVFileTypeAppleM4A;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (AVAssetExportSessionStatusCompleted == exportSession.status) {
NSLog(#"AVAssetExportSessionStatusCompleted");
[self mergeAudioPart2];
} else if (AVAssetExportSessionStatusFailed == exportSession.status) {
NSLog(#"AVAssetExportSessionStatusFailed");
} else {
NSLog(#"Export Session Status: %ld", (long)exportSession.status);
}
}];
i searched all over internet but, i didn't find any solution any help will be appreciated.
Your code should work, but without seeing your input files it's hard to tell. However it can still be improved.
You've got an unused mutable track for some reason. You can delete it:
AVMutableComposition *composition = [[AVMutableComposition alloc] init];
// This track is unused. Delete it!
// [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
When the export fails (AVAssetExportSessionStatusFailed == exportSession.status) check exportSession.error for more information. AVFoundation error messages often leave much to be desired, but you could be lucky.
You're exporting an m4a file, but the file suffix is .caf. Change it to .m4a (AVAssetExportSession doesn't appear to support exporting to AVFileTypeCoreAudioFormat).
Make sure to always remove the output URL before exporting, you've forgotten to do this:
NSURL *ouputURL = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/mergedFilePart1.m4a",documentsDirectory]];
[[NSFileManager defaultManager] removeItemAtURL:ouputURL error:nil];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = ouputURL;
exportSession.outputFileType = AVFileTypeAppleM4A;
insertTimeRange:ofTrack:error: returns a success flag and an error! Consult them! They might point to a problem with your code!
NSError *error;
if (![track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset1.duration) ofTrack:assetTrack1 atTime:insertionPoint error:&error]) {
NSLog(#"ERROR 1: %#", error);
}
This condition is strange. You check the existence of audio tracks in one asset, then use the other as well:
if ([avAsset1 tracksWithMediaType:AVMediaTypeAudio].count > 0) {
assetTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
assetTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
}
the issue was here :
// [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; this line was adding extra track. now this code is working perfect on IOS 9 as well.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path1 = [NSString stringWithFormat:#"%#/firstPart.caf",documentsDirectory];
NSString *path2 = [NSString stringWithFormat:#"%#/New-Recording.caf",documentsDirectory];
AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:path1] options:nil];
AVAsset *avAsset2 = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:path2] options:nil];
AVMutableComposition *composition = [[AVMutableComposition alloc] init];
// [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack *assetTrack1;
AVAssetTrack *assetTrack2;
if ([avAsset1 tracksWithMediaType:AVMediaTypeAudio].count > 0) {
assetTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
assetTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
}
NSError *error;
CMTime insertionPoint = kCMTimeZero;
[track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset1.duration) ofTrack:assetTrack1 atTime:insertionPoint error:nil];
insertionPoint = CMTimeAdd(insertionPoint, avAsset1.duration);
[track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset2.duration) ofTrack:assetTrack2 atTime:insertionPoint error:nil];
NSURL *outPutUrl = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/mergedFilePart1.caf",documentsDirectory]];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = outPutUrl;
exportSession.outputFileType = AVFileTypeAppleM4A;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (AVAssetExportSessionStatusCompleted == exportSession.status) {
NSLog(#"AVAssetExportSessionStatusCompleted");
[self mergeAudioPart2];
} else if (AVAssetExportSessionStatusFailed == exportSession.status) {
NSLog(#"%ld",(long)exportSession.status);
NSLog(#"AVAssetExportSessionStatusFailed");
} else {
NSLog(#"Export Session Status: %ld", (long)exportSession.status);
}
}];
I have implemented the scenario of converting audio from video but it is taking about 10 to 15 second, I want it to b much quicker than this as it is not user friendly in my app.
Please suggest me a solution
-(void)extractAudioFromVideo{
//Create a audia composition and add audio track
AVMutableComposition *newAudioAsset = [AVMutableComposition composition];
AVMutableCompositionTrack *dstCompositionTrack = [newAudioAsset addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
//Get video asset from which the audio should be extracted
NSURL *url = outputMainUrl;
AVAsset *srcAsset = [AVAsset assetWithURL:url];
NSArray *trackArray = [srcAsset tracksWithMediaType:AVMediaTypeAudio];
if(!trackArray.count){
NSLog(#"Track returns empty array for mediatype AVMediaTypeAudio");
return;
}
AVAssetTrack *srcAssetTrack = [trackArray objectAtIndex:0];
//Extract time range
CMTimeRange timeRange = srcAssetTrack.timeRange;
//Insert audio from the video to mutable avcomposition track
NSError *err = nil;
if(NO == [dstCompositionTrack insertTimeRange:timeRange ofTrack:srcAssetTrack atTime:kCMTimeZero error:&err]){
NSLog(#"Failed to insert audio from the video to mutable avcomposition track");
return;
}
//Export the avcompostion track to destination path
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0];
NSString *dstPath = [documentsDirectory stringByAppendingString:#"/sample_audio.mp4"];
NSURL *dstURL = [NSURL fileURLWithPath:dstPath];
urlOrigionalAudio = dstURL;
//Remove if any file already exists
[[NSFileManager defaultManager] removeItemAtURL:dstURL error:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:newAudioAsset presetName:AVAssetExportPresetPassthrough];
NSLog(#"support file types= %#", [exportSession supportedFileTypes]);
exportSession.outputFileType = #"public.mpeg-4";
exportSession.outputURL = dstURL;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
AVAssetExportSessionStatus status = exportSession.status;
if(status == AVAssetExportSessionStatusCompleted){
urlOrigionalAudio = exportSession.outputURL;
[SVProgressHUD dismiss];
}
else if (status == AVAssetExportSessionStatusFailed){
[SVProgressHUD showErrorWithStatus:#"Failled!"];
NSLog(#"Export status not yet completed");
}
}];
}
I have a weird problem. In my app I am combining multiple audio and video files using the code below. The resulted video seems to work fine once I downloaded it from the device to the computer and play with Quick Time, but whenever I am trying to play the newly composed video using either UIWebView or AVPLayer I can only see first part of merged video files.
Furthermore when I tried to use MPMoviePlayerController to play it hangs on "Loading".
I can hear audio for all composition. To make it clear I have two arrays:
1- audioPieces with paths to audio files [song1, song2, song3];
2- moviePieces with paths to video files [movie1,movie2,movie3];
After merging those files I can see only movie1 but I can hear song1 + song2 + song3.
P.S. songs and movies have different lengths (Less than 0.2s difference).
Any help will be appreciated.
Thank you in advance,
Janusz
-(void)putFilesTogether{
AVMutableComposition *mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *videoCompositionTrack =[[AVMutableCompositionTrack alloc]init];
AVMutableCompositionTrack *audioCompositionTrack =[[AVMutableCompositionTrack alloc]init];
NSLog(#" movie %# audio %# ", moviePieces, audioPieces);
NSError * error;
for(int i=0;i<moviePieces.count;i++)
{
NSFileManager * fm = [NSFileManager defaultManager];
NSString * movieFilePath;
NSString * audioFilePath;
movieFilePath = [moviePieces objectAtIndex:i];
audioFilePath = [audioPieces objectAtIndex:i];
if(![fm fileExistsAtPath:movieFilePath]){
NSLog(#"Movie doesn't exist %# ",movieFilePath);
}
else{
NSLog(#"Movie exist %# ",movieFilePath);
}
if(![fm fileExistsAtPath:audioFilePath]){
NSLog(#"Audio doesn't exist %# ",audioFilePath);
}
else{
NSLog(#"Audio exists %# ",audioFilePath);
}
NSURL *videoUrl = [NSURL fileURLWithPath:movieFilePath];
NSURL *audioUrl = [NSURL fileURLWithPath:audioFilePath];
AVURLAsset *videoasset = [[AVURLAsset alloc]initWithURL:videoUrl options:nil];
AVAssetTrack *videoAssetTrack= [[videoasset tracksWithMediaType:AVMediaTypeVideo] lastObject];
AVURLAsset *audioasset = [[AVURLAsset alloc]initWithURL:audioUrl options:nil];
AVAssetTrack *audioAssetTrack= [[audioasset tracksWithMediaType:AVMediaTypeAudio] lastObject];
videoCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
audioCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
CMTime tempTime = mixComposition.duration;
[audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioasset.duration) ofTrack:audioAssetTrack atTime:tempTime error:&error];
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoasset.duration) ofTrack:videoAssetTrack atTime:tempTime error:&error];
if(error)
{
NSLog(#"Ups. Something went wrong! %#", [error debugDescription]);
}
}
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *caldate = [now description];
float ran = arc4random()%1000;
NSString * pathToSave = [NSString stringWithFormat:#"Output%#%f.mp4",caldate,ran];
pathToSave =[DOCUMENTS_FOLDER stringByAppendingPathComponent:pathToSave];
NSURL *movieUrl = [NSURL fileURLWithPath:pathToSave];
AVAssetExportSession *exporter =[[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetPassthrough];
exporter.outputFileType=AVFileTypeQuickTimeMovie;
exporter.outputURL=movieUrl;
exporter.shouldOptimizeForNetworkUse=YES;
CMTimeValue val = mixComposition.duration.value;
CMTime start=CMTimeMake(0, 600);
CMTime duration=CMTimeMake(val, 600);
CMTimeRange range=CMTimeRangeMake(start, duration);
exporter.timeRange=range;
[exporter exportAsynchronouslyWithCompletionHandler:^{
switch ([exporter status]) {
case AVAssetExportSessionStatusFailed:{
NSLog(#"Export failed: %# %#", [[exporter error] localizedDescription],[[exporter error]debugDescription]);
NSString * message = #"Movie wasn't created. Try again later.";
[self performSelectorOnMainThread:#selector(dismissMe:) withObject:message waitUntilDone:NO];
break;}
case AVAssetExportSessionStatusCancelled:{ NSLog(#"Export canceled");
NSString * message1 = #"Movie wasn't created. Try again later.";
[self performSelectorOnMainThread:#selector(dismissMe:) withObject:message1 waitUntilDone:NO];
break;}
case AVAssetExportSessionStatusCompleted:
{
NSString * message = #"Movie was successfully created.";
CMTime duration = mixComposition.duration;
[self saveData:duration ofPath:pathToSave];
[self cleanFiles];
[self performSelectorOnMainThread:#selector(dismissMe:) withObject:message waitUntilDone:NO];
}
}}];
}
The problem lays in:
videoCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
audioCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
They need to be moved outside the for loop body.
I'm using an AVComposition to merge two .m4a audio files together. One has to be inserted in the other one at a specific time. I then use an AVAssetExportSession to save the merge audio.
I'm getting this error during the Export Session Completion Handler:
Error Domain=AVFoundationErrorDomain Code=-11820 "Cannot Complete Export" UserInfo=0x1c3760 {NSLocalizedRecoverySuggestion=Try exporting again., NSLocalizedDescription=Cannot Complete Export}
Code - Merging the two assets:
AVAsset *originalAsset = [AVAsset assetWithURL:url];
NSURL *recordingAssetUrl = [[NSURL fileURLWithPath: NSTemporaryDirectory()] URLByAppendingPathComponent:kRecordTemp];
AVAsset *recordingAsset = [AVAsset assetWithURL:recordingAssetUrl];
AVMutableComposition *composition = [AVMutableComposition new];
AVMutableCompositionTrack *audioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
//Add the original audio asset to the composition
AVAssetTrack *sourceAudioTrack = [[originalAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
NSError *error = nil;
CMTimeRange sourceRange = CMTimeRangeMake(CMTimeMakeWithSeconds(0, 1), originalAsset.duration);
[audioTrack insertTimeRange:sourceRange ofTrack:sourceAudioTrack atTime:CMTimeMakeWithSeconds(0, 1) error:&error];
if (error) [self showError:error];
//Remove the portion of the original audio asset that will be replaced by the recording
CMTimeRange overwrittenRange = CMTimeRangeMake(self.currentTime, recordingAsset.duration);
[audioTrack removeTimeRange:overwrittenRange];
//Add the recording asset to the composition
AVAssetTrack *recordAudioTrack = [[recordingAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
error = nil;
CMTimeRange recordRange = CMTimeRangeMake(CMTimeMakeWithSeconds(0, 1), recordingAsset.duration);
[audioTrack insertTimeRange:recordRange ofTrack:recordAudioTrack atTime:self.currentTime error:&error];
if (error) [self showError:error];
//Delete the original asset
if([[NSFileManager defaultManager] fileExistsAtPath:url.path]){
error = nil;
[[NSFileManager defaultManager] removeItemAtURL:url error:&error];
if(error) [self showError:error];
}
//Write the composition
AVAssetExportSession * exportSession = [AVAssetExportSession exportSessionWithAsset:composition
presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = url;
exportSession.outputFileType = AVFileTypeAppleM4A;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if(exportSession.status != AVAssetExportSessionStatusCompleted){
[self showError:exportSession.error];
}
}];
//Delete the temporary asset
if([[NSFileManager defaultManager] fileExistsAtPath:recordingAssetUrl.path]){
error = nil;
[[NSFileManager defaultManager] removeItemAtURL:recordingAssetUrl error:&error];
if(error) [self showError:error]; //BOOM it blows up here
}
I'm not sure what other piece of code I should paste since it's such a generic error.
I'm using an AVAssetWriter to write the sample buffer to create the recording asset I receive from the capture session. The capture session successfully records and saves into files into the urls used in the above listing.