In our iOS app, we will receive flv**(Container)** file having video and audio streaming something like this
Input #0, flv, from 'test.flv':
Metadata:
streamName : flvLiveStream
encoder : Lavf55.12.100
Duration: 00:00:48.00, start: 66064.401000, bitrate: 632 kb/s
Stream #0:0, 41, 1/1000: **Video: h264 (Baseline)**, 1 reference frame, yuv420p(progressive, left), 1280x720, 0/1, 15 fps, 1k tbr, 1k tbn
Stream #0:1, 14, 1/1000: **Audio: pcm_alaw,** 8000 Hz, mono, s16, 64 kb/s
and this needs to be converted to mp4 container and format as well, I am trying using ffmpeg, I believe thats only the way , using transcoding.c file but failed at this stage
Impossible to convert between the formats supported by the filter 'in' and the filter 'auto_scaler_0'
I am trying to learn from OSX command like ffmpeg -I test.flv test.mp4 ,
is that feasible to port to iOS
will it work in all different scenarios,
In Summary
--- What is the best possible way to convert flv to mp4 on the iOS device
where video will be in h264 and audio will be in swf codec ?
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"MyVideo.mp4"];
NSURL *outputURL = [NSURL fileURLWithPath:filePath];
[self convertVideoToLowQuailtyWithInputURL:localUrl outputURL:outputURL handler:^(AVAssetExportSession *exportSession)
{
if (exportSession.status == AVAssetExportSessionStatusCompleted) {
// Video conversation completed
}
}];
- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL outputURL:(NSURL*)outputURL handler:(void (^)(AVAssetExportSession*))handler {
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetPassthrough];
exportSession.outputURL = outputURL;
exportSession.outputFileType = AVFileTypeMPEG4;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void) {
handler(exportSession);
}];
}
(Please note I've already looked at this other SO post.)
The Problem
I'm trying to convert an avi video to an mp4 so that I can play it natively on an iOS app using Objective-C
What I've Tried
I'm trying the following code to do that conversion:
- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL outputURL:(NSURL*)outputURL handler:(void (^)(AVAssetExportSession*))handler {
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
exportSession.outputURL = outputURL;
exportSession.outputFileType = AVFileTypeMPEG4;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void) {
handler(exportSession);
}];
}
The error that is returned from the exportSession is Cannot Open
Extra Information
When I run the video that I'm trying to convert through Mediainfo I get the following for the video:
7 332kb/s, 1920*1080 (16:9), at 25.000 FPS, AVC (Baseline#L3.1) (CABAC / 1 Ref Frames)
And this for the audio:
128 kb/s, 8 000 Hz, 16 bits, 1 channel, PCM (Little / Signed)
I also used the exportPresetsCompatibleWithAsset: method on AVAssetExportSession and got the following results:
AVAssetExportPreset1920x1080,
AVAssetExportPresetLowQuality,
AVAssetExportPresetAppleM4A,
AVAssetExportPresetHEVCHighestQuality,
AVAssetExportPreset640x480,
AVAssetExportPreset3840x2160,
AVAssetExportPresetHEVC3840x2160,
AVAssetExportPresetHighestQuality,
AVAssetExportPreset1280x720,
AVAssetExportPresetMediumQuality,
AVAssetExportPreset960x540,
AVAssetExportPresetHEVC1920x1080
Another thing to note is that when playing with the preset and the output I managed to get an audio only file that was basically white noise. This was using the preset AVAssetExportPresetAppleM4A.
I hope that I've jotted down enough information.
Update
Using the comment by Ashley, i've created a function to return the export settings compatible with the asset.
- (void)determineCompatibleExportForAsset:(AVURLAsset *)asset completion:(void(^)(NSArray<ExportSettings *> *exports))handler {
NSArray<NSString *> *presets = #[
AVAssetExportPresetLowQuality,
AVAssetExportPresetMediumQuality,
AVAssetExportPresetHighestQuality,
AVAssetExportPresetHEVCHighestQuality,
AVAssetExportPreset640x480,
AVAssetExportPreset960x540,
AVAssetExportPreset1280x720,
AVAssetExportPreset1920x1080,
AVAssetExportPreset3840x2160,
AVAssetExportPresetHEVC1920x1080,
AVAssetExportPresetHEVC3840x2160,
AVAssetExportPresetAppleM4A,
AVAssetExportPresetPassthrough
];
NSArray<NSString *> *outputs = #[
AVFileTypeQuickTimeMovie,
AVFileTypeMPEG4,
AVFileTypeAppleM4V,
AVFileTypeAppleM4A,
AVFileType3GPP,
AVFileType3GPP2,
AVFileTypeCoreAudioFormat,
AVFileTypeWAVE,
AVFileTypeAIFF,
AVFileTypeAIFC,
AVFileTypeAMR,
AVFileTypeMPEGLayer3,
AVFileTypeSunAU,
AVFileTypeAC3,
AVFileTypeEnhancedAC3,
AVFileTypeJPEG,
AVFileTypeDNG,
AVFileTypeHEIC,
AVFileTypeAVCI,
AVFileTypeHEIF,
AVFileTypeTIFF
];
__block int counter = 0;
int totalCount = (int)presets.count * (int)outputs.count;
NSMutableArray<ExportSettings *> *exportSettingsArray = [#[] mutableCopy];
for (NSString *preset in presets) {
for (NSString *output in outputs) {
[AVAssetExportSession determineCompatibilityOfExportPreset:preset withAsset:asset outputFileType:output completionHandler:^(BOOL compatible) {
if (compatible) {
ExportSettings *exportSettings = [[ExportSettings alloc] initWithPreset:preset outputType:output];
[exportSettingsArray addObject:exportSettings];
}
counter++;
if (counter == totalCount) {
if (handler) {
handler([exportSettingsArray copy]);
}
}
}];
}
}
}
The results of this are as follows:
"Preset: AVAssetExportPresetAppleM4A Output: com.apple.m4a-audio",
"Preset: AVAssetExportPresetPassthrough Output: com.microsoft.waveform-audio",
"Preset: AVAssetExportPresetPassthrough Output: public.aifc-audio",
"Preset: AVAssetExportPresetPassthrough Output: public.aiff-audio",
"Preset: AVAssetExportPresetPassthrough Output: com.apple.coreaudio-format",
"Preset: AVAssetExportPresetPassthrough Output: com.apple.quicktime-movie"
From this I deduced that using the preset AVAssetExportPresetPassthrough and output type AVFileTypeQuickTimeMovie would be compatible.
However when running the following code: (i've tried .mp4, .mov and .qt for the file type)
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"MyVideo.mov"];
NSURL *outputURL = [NSURL fileURLWithPath:filePath];
NSURL *localURL = [NSBundle URLForResource:#"20180626_145233-v" withExtension:#"avi" subdirectory:nil inBundleWithURL:[NSBundle mainBundle].bundleURL];
[self convertVideoToLowQuailtyWithInputURL:localURL outputURL:outputURL handler:^(AVAssetExportSession *exportSession) {
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %#", [exportSession error]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(#"Successfully");
NSLog(#"OutputURL: %#", outputURL.absoluteString);
break;
default:
break;
}
}];
Which calls:
- (void)convertVideoToLowQuailtyWithInputURL:(NSURL*)inputURL outputURL:(NSURL*)outputURL handler:(void (^)(AVAssetExportSession*))handler {
[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetPassthrough];
exportSession.outputURL = outputURL;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void) {
handler(exportSession);
}];
}
I get this error:
Export failed: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (-12842), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x60400024def0 {Error Domain=NSOSStatusErrorDomain Code=-12842 "(null)"}}
The reason you cannot open the file is because iOS does not support AVI files.
Here is the link to the Apple documentation on supported file types within AVFoundation.
Or this image for posterity should the values change:
Finally, you can just inspect the definition of AVFileType from within XCode to see this list for yourself.
For what it is worth, a cursory inspection on AVI via Google indicates that there are limitations with the AVI container that have been rectified in newer formats that are supported by iOS, so there is likely little incentive to add support at a later date.
While also a potential issue being that Microsoft created AVI, I cannot locate any restrictive licensing that would prohibit someone from using it, but IANAL.
You should use FFmpeg library for that kind of purposes.
Here is an open-source video-player based on FFmpeg: https://github.com/kolyvan/kxmovie
I don't know if this player still works for the latest iOS but in any case in source codes, you can discover many interesting things that can help you with your problem (such as how to use FFmpeg library).
Very easy to do with MobileFFMpeg
https://stackoverflow.com/a/59325680/1466453
Once you have MobileFFMpeg then make a call as follows:
[MobileFFMpeg execute:#"-i infile.avi youroutput.mp4"];
In my app, few audio files which are downloaded from server are not supported. mpeg,x-wav audio formats are not supported in my Objective-C code. How can I convert them into one of the supported types of iOS?
You could import them into garage band and then export as an IOS compatible format such as .m4a or .mp3
Below code maybe useful to you.And change the outputFileType what you want
AVAsset * asset = [AVAsset assetWithURL:inputURL];
AVAssetExportSession * exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.outputURL = outputURL;
exportSession.metadata = asset.metadata;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (exportSession.status == AVAssetExportSessionStatusCompleted)
{
NSLog(#"AV export succeeded.");
}
else if (exportSession.status == AVAssetExportSessionStatusCancelled)
{
NSLog(#"AV export cancelled.");
}
else
{
NSLog(#"AV export failed with error: %# (%ld)", exportSession.error.localizedDescription, (long)exportSession.error.code);
}
}];
For Ref:-
https://stackoverflow.com/a/41053633
NOTE:- Not tested
This question already has an answer here:
iPhone - Separating audio from a video file and saving it to a separate file
(1 answer)
Closed 9 years ago.
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.
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");
}
}];
I have a 22kHz wave file and want a 22kHz m4a file. AVAssetExportSession with the preset AVAssetExportPresetAppleM4A automatically converts my wav to 44kHZ. I've tried different presets and nil to create the ExportSession, but without success.
Is there a way to set custom export properties of an AVAssetExportSession or do I need a completely different approach like the one stated in How to convert WAV file to M4A??
here is the code I have so far, which works great if you want a 44kHz file:
AVURLAsset *wavAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:wavPath] options:optionsDict];
AVMutableComposition *mutableComposition = [AVMutableComposition composition];
[mutableComposition insertTimeRange:CMTimeRangeMake(kCMTimeZero, wavAsset.duration)
ofAsset:wavAsset atTime:kCMTimeZero error:&error];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
initWithAsset:[mutableComposition copy] presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = [NSURL fileURLWithPath:m4aPath];
exportSession.outputFileType = AVFileTypeAppleM4A;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted: {
[exportSession release];
completionHandler(nil);
break;
}
case AVAssetExportSessionStatusFailed: {
NSLog(#"There was an error while exporting the file: %#", exportSession.error);
completionHandler(exportSession.error);
break;
}
// ... handle some other cases...
default: {
break;
}
}
}];
Would be great if I just missed something.
Thanks in advance,
Dom
I've had some luck with the TPAACAudioConverter available here. It uses the ExtendedAudioFile API in the AudioToolbox Framework.