I managed it to download a youtube video using NSUrlConnection and save it to the device. Now I want to convert this (I guess .mp4) file to an .mp3 audio file. Does anyone know a solution for this problem? Maybe there's a way to only download the audio from the video? This would save a lot of time.
Asked
Active
Viewed 3,397 times
6
-
I don't think so its duplicate. As there is no accepted answer in so called original question. – Alok C Jan 22 '16 at 17:29
1 Answers
7
First of all, you don't want to convert anything, that's slow. Instead you want to extract the audio stream from the mp4 file. You can do this by creating an AVMutableComposition
containing only the audio track of the original file and then exporting the composition with an AVAssetExportSession
. This is currently m4a centric. If you want to handle both m4a and mp3 output, check the audio track type, make sure to set the right file extension and choose between AVFileTypeMPEGLayer3
or AVFileTypeAppleM4A
in the export session.
NSURL* dstURL = [NSURL fileURLWithPath:dstPath];
[[NSFileManager defaultManager] removeItemAtURL:dstURL error:nil];
AVMutableComposition* newAudioAsset = [AVMutableComposition composition];
AVMutableCompositionTrack* dstCompositionTrack;
dstCompositionTrack = [newAudioAsset addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
AVAsset* srcAsset = [AVURLAsset URLAssetWithURL:srcURL 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;
[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");
}
}];

Rhythmic Fistman
- 34,352
- 5
- 87
- 159
-
thanks! Sounds awesome. Is there a way to do the same, only with the url of the video file given to kind of "stream" it? Its very slow to download the whole file first. – Valle Dec 26 '13 at 16:21
-
Try setting srcURL to remote URL. It takes longer to inspect tracks, so you should load the tracks asynchronously. – Rhythmic Fistman Dec 26 '13 at 22:20
-
Everything works quite well but sometimes I get an "empty array" error because the saving of the video file is not ready. Do you guys know a way to get a completitionHandler (or something) for NSData writeToFile? – Valle Jan 02 '14 at 20:20
-
writeToFile is synchronous so that shouldn't be the problem. Ask a new question and post some code. If my answer solved your problem, click the big checkbox to accept it as the answer. – Rhythmic Fistman Jan 02 '14 at 22:14
-
-
srcURL is a file URL to the video from which to extract the audio track. – Rhythmic Fistman Dec 14 '14 at 20:34
-
I can extract successfully a M4A file, but no MP3. Somebody achieved this? – iOS Dev Oct 07 '16 at 10:15
-
-