I am trying to extract the audio file from .m4v video. It shows the error like,
Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=0x15e350d0 {NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x15d1c6b0 "The operation couldn’t be completed. (OSStatus error -12124.)", NSLocalizedFailureReason=An unknown error occurred (-12124)}
This is my code:
-(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 = [[NSBundle mainBundle] URLForResource:#"sample_iPod" withExtension:#"m4v"];
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];
//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(AVAssetExportSessionStatusCompleted != status){
NSLog(#"Export status not yet completed. Error: %#", exportSession.error.description);
}
}];
}
How can I resolve this error?
I've tested your code in simulator. It's working fine in simulator(IOS7). But When I run on iPodTouch-5, it shows error as like what you've mention. Spend more than 15 mins, found and silly mistake.
Getting path as below(Documentssample_audio.mp4) when I run in Device..
#"file:///var/mobile/Applications/A1E1D85F-0198-4A0C-80F8-222F0DA1C31A/Documentssample_audio.mp4"
so I've modified path as..
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0];
NSString *dstPath = [documentsDirectory stringByAppendingString:#"/sample_audio.mp4"];
Now I'm getting path as below(/Documents/sample_audio.mp4) and working fine. But I don't know, How it is happened
#"file:///var/mobile/Applications/A1E1D85F-0198-4A0C-80F8-222F0DA1C31A/Documents/sample_audio.mp4"
Related
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 am really stuck on this, i have merged videos (mp4 kind that are saved in xcode, and mov - from users photo library) and audio (mp3 kind saved in xcode). On the simulator it works fine and shows the video and audio, but on the device it doesn't show the video only plays the sound . here is the code for merging:` AVMutableComposition* mixComposition = [AVMutableComposition composition];
//Audio
//Now first load your audio file using AVURLAsset. Make sure you give the correct path of your videos.
NSURL *audio_url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:_video.musicFileName ofType:#"mp3"]];
AVURLAsset *audioAsset = [[AVURLAsset alloc] initWithURL:audio_url options:nil];
CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, audioAsset.duration);
//Now we are creating the first AVMutableCompositionTrack containing our audio and add it to our AVMutableComposition object.
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
//Video
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
NSString *fistPartMovieFilename = #"firstpart";
NSString *lastPartMovieFilename = #"lastpart";
//[_video.selectedVideosFileName insertObject:fistPartMovieFilename atIndex:0];
//[_video.selectedVideosFileName addObject:lastPartMovieFilename];
NSMutableArray *timeRanges = [NSMutableArray arrayWithCapacity:_video.selectedVideosFileName.count];
NSMutableArray *tracks = [NSMutableArray arrayWithCapacity:_video.selectedVideosFileName.count];
NSLog(#"_video.selectedVideosFileName %#",_video.selectedVideosFileName);
for (int i=0; i<[_video.selectedVideosFileName count]; i++)
{
AVURLAsset *assetClip;
NSString *fileName = [_video.selectedVideosFileName objectAtIndex:i];
if ([[_video.selectedVideosFileName objectAtIndex:i] isKindOfClass:[NSURL class]])
{
assetClip = [AVAsset assetWithURL:[_video.selectedVideosFileName objectAtIndex:i]];
}
else
{
assetClip = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[NSString stringWithString:fileName] ofType:#"mp4"]] options:nil];
}
AVAssetTrack *clipVideoTrack = [[assetClip tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[timeRanges addObject:[NSValue valueWithCMTimeRange:CMTimeRangeMake(kCMTimeZero, assetClip.duration)]];
[tracks addObject:clipVideoTrack];
NSLog(#"timeRanges %#",timeRanges);
NSLog(#"tracks %#",tracks);
NSLog(#"assetClip %#",assetClip);
NSLog(#"clipVideoTrack %#",clipVideoTrack);
}
NSError *error = nil;
BOOL sucsess = [compositionVideoTrack insertTimeRanges:timeRanges
ofTracks:tracks
atTime:kCMTimeZero
error:&error];
if (!sucsess || error) {
NSLog(#"video error %#", error);
}
the error i get when trying on device is : video error
Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=0x1704707c0
{NSUnderlyingError=0x174247050 "The operation couldn’t be completed. (OSStatus error -12780.)", NSLocalizedFailureReason=An unknown error occurred (-12780), NSLocalizedDescription=The operation could not be completed
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
NSString *outputFilePath = [docsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"Zagoori-%d.mov",arc4random() % 1000]];
NSURL *outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
[[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];
//Now create an AVAssetExportSession object that will save your final video at specified path.
AVAssetExportSession *_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition
presetName:AVAssetExportPresetLowQuality];
NSLog(#"supportedFileTypes %#", [_assetExport supportedFileTypes]);
_assetExport.outputFileType = #"com.apple.quicktime-movie";
_assetExport.outputURL = outputFileUrl;
[_assetExport exportAsynchronouslyWithCompletionHandler:^
{
dispatch_async(dispatch_get_main_queue(), ^{
switch ([_assetExport status]) {
case AVAssetExportSessionStatusExporting:
NSLog(#"Export in progress ");
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed (%ld): %#", (long)[[_assetExport error] code], [[_assetExport error] localizedFailureReason]);
[_assetExport cancelExport];
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(#"Export done");
[self exportDidFinish:_assetExport];
// NSLog (#"finished writing %f", [dtStartDate timeIntervalSinceNow]);
break;
case AVAssetExportSessionStatusWaiting:
NSLog (#"AVAssetExportSessionStatusWaiting");
break;
case AVAssetExportSessionStatusUnknown:
NSLog (#"AVAssetExportSessionStatusUnknown");
break;
}
});
}];
-(void)loadMoviePlayer:(NSURL*)moviePath {
_moviePlayerController = [[MPMoviePlayerController alloc]
initWithContentURL:moviePath];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(introMovieFinished:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:_moviePlayerController];
_moviePlayerController.view.hidden = NO;
_moviePlayerController.view.frame = CGRectMake(0, 0, _videoView.frame.size.width,
_videoView.frame.size.height);
_moviePlayerController.view.backgroundColor = [UIColor clearColor];
_moviePlayerController.scalingMode = MPMovieScalingModeAspectFit;
_moviePlayerController.fullscreen = NO;
[_moviePlayerController prepareToPlay];
[_moviePlayerController readyForDisplay];
[_moviePlayerController setControlStyle:MPMovieControlStyleDefault];
_moviePlayerController.shouldAutoplay = YES;
[_videoView addSubview:_moviePlayerController.view];
[_videoView setHidden:NO];
}
I am really clueless of what the problem could be, Help please! :)
so i have found the problem,it is caused by the AVURLAsset instances
Since the AVURLAsset *assetClip is in inside the for loop, it is not valid outside of it and neither is the tracks that i extracted.
I kept my assetClip in an array and that solved the problem.
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
I have tried to export audio file from the iPod-Library. My objective is to create new file in app Document folder with this iPod-Library file .Its fails to create files for some items only . Below is my code snippet.
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL: url options:nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc]
initWithAsset: songAsset
presetName: AVAssetExportPresetAppleM4A];
exporter.outputFileType = #"com.apple.m4a-audio";
NSString *songName = [filename stringByAppendingString:#".m4a"];
NSString *musicfilepath = [documentsDirectory stringByAppendingPathComponent:#"musics/"];
[[NSFileManager defaultManager] createDirectoryAtPath:musicfilepath withIntermediateDirectories:YES attributes:nil error:nil];
NSString *exportFile = [musicfilepath stringByAppendingPathComponent:songName];
NSError *error1;
if([[NSFileManager defaultManager] fileExistsAtPath:exportFile])
{
[[NSFileManager defaultManager] removeItemAtPath:exportFile error:&error1];
}
NSURL* exportURL = [[NSURL fileURLWithPath:exportFile] retain];
exporter.outputURL = exportURL;
Am getting Error as shown below when tried with the error handler block :
[exporter exportAsynchronouslyWithCompletionHandler:^{
int exportStatus = exporter.status;
switch (exportStatus) {
case AVAssetExportSessionStatusFailed: {
NSError *exportError = exporter.error;
NSLog (#"AVAssetExportSessionStatusFailed: %#", exportError);
break;
}
}
}];
AVAssetExportSessionStatusFailed: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo=0x214f20 {NSLocalizedFailureReason=An unknown error occurred (-12124), NSUnderlyingError=0x218270 "The operation couldn’t be completed. (OSStatus error -12124.)", NSLocalizedDescription=The operation could not be completed}
Having played a lot with this myself, some of the answers may be relevant and correct. One other thing to watch out for is that I often used to get similar AVFoundation errors if trying to combine videos that had different frame-rates. Check the source files frame rate and check your CMTime's too. You may have to pre-process some files before adding them into a AVMutableComposition.
If you have iTunes match on and the file is not downloaded to the device, this can happen. Can you check to see if that is the case for you? If so I can give code to detect it.
+ (BOOL)isDownloadedFromiCloud:(MPMediaItem *)item {
if ([item valueForProperty:MPMediaItemPropertyAssetURL] != nil) {
AVURLAsset *asset = [AVURLAsset assetWithURL:[item valueForProperty:MPMediaItemPropertyAssetURL]];
if (asset.exportable)
return YES;
}
return NO;
}
I've experienced this too. Are you using iTunes match? It may be that the file is not on the actual device. You can check this on the AVAsset by checking the properties such as hasProtectedContent or ensuring exportable is YES.
Also, I notice you are using the AVExportSession preset AVAssetExportPresetAppleM4A'. This will re-encode the file you are exporting. It may be easier (and much faster) to just pass-though instead usingAVAssetExportPresetPassthrough`. This assumes you are happy with the existing file format, which maybe .m4a, .mp3, .wav etc...
The the music file path your are using might be wrong. Try this
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
documentsDirectory = [documentsDirectory stringByAppendingPathComponent:#"Music"];
NSError* error;
if (![[NSFileManager defaultManager] fileExistsAtPath:documentsDirectory])
[[NSFileManager defaultManager] createDirectoryAtPath:documentsDirectory withIntermediateDirectories:NO attributes:nil error:&error];
NSString *exportFile = [documentsDirectory stringByAppendingPathComponent:songName];
if([[NSFileManager defaultManager] fileExistsAtPath:exportFile])
{
[[NSFileManager defaultManager] removeItemAtPath:exportFile error:&error1];
}
if (error != nil) {
NSURL* exportURL = [[NSURL fileURLWithPath:exportFile] retain];
exporter.outputURL = exportURL;
[exporter exportAsynchronouslyWithCompletionHandler:^{
int exportStatus = exporter.status;
switch (exportStatus) {
case AVAssetExportSessionStatusFailed: {
NSError *exportError = exporter.error;
NSLog (#"AVAssetExportSessionStatusFailed: %#", exportError);
break;
}
}
}
];
}
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.