I used this code It's fine,but after converted the song to data and when i'm trying to send that converted data to MFMailComposeViewController or MFMessageComposeViewController, It's coming in Document format some times but failed to get the mp3 format.When I'm playing the song,which we sent to the MFmailComposeViewcontroller or MFMessageComposeViewController , the songs which converted correctly was playing correct but some is converting to document format . How to overcome this. Please suggest me .
SelectedAlbumUrl = [[arr_tablVArray objectAtIndex:indexPath.row] objectForKey:#"SongUrl"];
This method calling like this.
[self mediaItemToData:[arr_tablVArray objectAtIndex:indexPath.row]];
-(void)mediaItemToData : (MPMediaItem * ) curItem
{
NSURL *url = SelectedAlbumUrl;
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL: url options:nil];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset: songAsset
presetName:AVAssetExportPresetAppleM4A];
exporter.outputFileType = #"com.apple.m4a-audio";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * myDocumentsDirectory = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
[[NSDate date] timeIntervalSince1970];
NSTimeInterval seconds = [[NSDate date] timeIntervalSince1970];
NSString *intervalSeconds = [NSString stringWithFormat:#"%0.0f",seconds];
NSString * fileName = [NSString stringWithFormat:#"%#.caf",intervalSeconds];
NSLog(#"the file name is --->%#",fileName);
NSString *exportFile = [myDocumentsDirectory stringByAppendingPathComponent:fileName];
exportURL = [NSURL fileURLWithPath:exportFile];
exporter.outputURL = exportURL;
// (completion handler block omitted)
[exporter exportAsynchronouslyWithCompletionHandler:
^{
int exportStatus = exporter.status;
switch (exportStatus)
{
case AVAssetExportSessionStatusFailed:
{
NSError *exportError = exporter.error;
NSLog (#"AVAssetExportSessionStatusFailed: %#", exportError);
break;
}
case AVAssetExportSessionStatusCompleted:
{
NSLog (#"AVAssetExportSessionStatusCompleted");
NSData *data = [NSData dataWithContentsOfFile: [myDocumentsDirectory
stringByAppendingPathComponent:fileName]];
data = nil;
break;
}
case AVAssetExportSessionStatusUnknown:
{
NSLog (#"AVAssetExportSessionStatusUnknown"); break;
}
case AVAssetExportSessionStatusExporting:
{
NSLog (#"AVAssetExportSessionStatusExporting"); break;
}
case AVAssetExportSessionStatusCancelled:
{
NSLog (#"AVAssetExportSessionStatusCancelled"); break;
}
case AVAssetExportSessionStatusWaiting:
{
NSLog (#"AVAssetExportSessionStatusWaiting"); break;
}
default:
{
NSLog (#"didn't get export status"); break;
}
}
}];
}
After that url converting to NSData sending through email,message and airdrop like this
NSData *Data = [NSData dataWithContentsOfURL:exportURL];
[composer addAttachmentData:Data mimeType:#".caf" fileName:str_songtitle];
Try this
- (void)addAttachmentData:(NSData*)attachment mimeType:(NSString*)mimeType fileName:(NSString*)filename
with mimeType = audio/mpeg
Related
In my app I can access the device music library, and when you select a song, it loads, however, it no longer works, and I am constantly met with the error 'export session error'
Then the app just hangs with the spinning loading bar forever until I close the app.
Select music AssetUrl = ipod-library://item/item.mp3?id=2023536838012570661
export session error
The files that I believe are troublesome are .mp3 files;
If I use .m4a files, it seems to work fine - so is there a way to block mp3 files from appearing in the mediapicker? Or at least an alert to show the user they can't use them if they try to select an mp3 file?
Here is the code;
Picker code;
- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection
{
dispatch_async(dispatch_get_main_queue(), ^{
// Dismiss the media item picker.
[self dismissViewControllerAnimated:YES completion:nil];
if ([mediaItemCollection count] < 1) {
return;
}
[selectedItem release];
selectedItem = [[[mediaItemCollection items] objectAtIndex:0] retain];
NSURL* filePath = [selectedItem valueForProperty: MPMediaItemPropertyAssetURL];
NSLog(#"Select music AssetUrl = %#", filePath);
});
}
- (void)exportAssetAsSourceFormat:(MPMediaItem *)item {
dispatch_async(dispatch_get_main_queue(), ^{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSURL *assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL]; //MPMediaItemPropertyAssetURL
if (assetURL == nil)
{
NSLog(#"assetURL is null");
[pool release];
return;
}
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];
// JP
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
initWithAsset:songAsset
presetName:AVAssetExportPresetPassthrough];
NSArray *tracks = [songAsset tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *track = [tracks objectAtIndex:0];
id desc = [track.formatDescriptions objectAtIndex:0];
const AudioStreamBasicDescription *audioDesc = CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef)desc);
FourCharCode formatID = audioDesc->mFormatID;
NSString *fileType = nil;
NSString *ex = nil;
switch (formatID) {
case kAudioFormatLinearPCM:
{
UInt32 flags = audioDesc->mFormatFlags;
if (flags & kAudioFormatFlagIsBigEndian) {
fileType = #"public.aiff-audio";
ex = #"aif";
} else {
fileType = #"com.microsoft.waveform-audio";
ex = #"wav";
}
}
break;
case kAudioFormatMPEGLayer3:
fileType = #"com.apple.quicktime-movie";
ex = #"mp3";
break;
case kAudioFormatMPEG4AAC:
fileType = #"com.apple.m4a-audio";
ex = #"m4a";
break;
case kAudioFormatAppleLossless:
fileType = #"com.apple.m4a-audio";
ex = #"m4a";
break;
default:
break;
}
exportSession.outputFileType = fileType;
NSString *exportPath = [[NSTemporaryDirectory() stringByAppendingPathComponent:[EXPORT_NAME stringByAppendingPathExtension:ex]] retain];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) {
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
exportSession.outputURL = [NSURL fileURLWithPath:exportPath];
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (exportSession.status == AVAssetExportSessionStatusCompleted) {
NSLog(#"export session completed");
//return YES;
[self performSelectorOnMainThread:#selector(gotoMainView:)
withObject:[EXPORT_NAME stringByAppendingPathExtension:ex]
waitUntilDone:NO];
} else {
NSLog(#"export session error");
//return NO;
}
[exportSession release];
}];
[pool release];
});
}
Below is my code about what i have done for this .mov to .wav conversations :
- (void)mp4ForURL:(NSURL *)videoURL{
// Create the asset url with the video file
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
// Check if video is supported for conversion or not
if ([compatiblePresets containsObject:AVAssetExportPresetMediumQuality])////************************************////
{
//Create Export session
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName:AVAssetExportPresetMediumQuality];////************************************////
//Creating temp path to save the converted video
NSString* documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* myDocumentPath = [documentsDirectory stringByAppendingPathComponent:#"temp.mp4"];
NSURL *url = [[NSURL alloc] initFileURLWithPath:myDocumentPath];
//Check if the file already exists then remove the previous file
if ([[NSFileManager defaultManager]fileExistsAtPath:myDocumentPath])
{
[[NSFileManager defaultManager]removeItemAtPath:myDocumentPath error:nil];
}
exportSession.outputURL = url;
//set the output file format if you want to make it in other file format (ex .3gp)
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.shouldOptimizeForNetworkUse = YES;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status])
{
case AVAssetExportSessionStatusFailed:
NSLog(#"Export session failed");
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
case AVAssetExportSessionStatusCompleted:
{
//Video conversion finished
NSLog(#"Successful!");
[self convertMP4toMP3withFile:myDocumentPath];
}
break;
default:
break;
}
}];
}
else
{
NSLog(#"Video file not supported!");
}
}
-(void)convertMP4toCAFwithFile:(NSString*)dstPath //Converted to Core Audio Format .caf
{
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 = AVFileTypeCoreAudioFormat;
exportSesh.outputURL = dstURL;
[[NSFileManager defaultManager] removeItemAtURL:dstURL error:nil];
[exportSesh exportAsynchronouslyWithCompletionHandler:^{
AVAssetExportSessionStatus status = exportSesh.status;
NSLog(#"exportAsynchronouslyWithCompletionHandler: %li\n", (long)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];
NSInteger randomNumber = arc4random() % 100000;
strDateAndTime = [self getCurrentDateAndTime];
strAudioName = [NSString stringWithFormat:#"%#_%ld_%#.%#", #"Audio", (long)randomNumber, strDateAndTime, #"caf"];
NSString *toPathString = [NSString stringWithFormat:#"%#/%#", onlyPath, strAudioName];
[[NSFileManager defaultManager] moveItemAtPath:dstPath toPath:toPathString error:&error];
//[self uploadAudioOnAWSFromPath:toPathString];
[self convertToWavForFilePath:toPathString];
}
}];
}
- (void)convertToWavForFilePath:(NSString *)cafFilePath
{
// set up an AVAssetReader to read from the iPod Library
// NSString *cafFilePath=[[NSBundle mainBundle]pathForResource:#"test" ofType:#"caf"];
NSURL *assetURL = [NSURL fileURLWithPath:cafFilePath];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];
NSError *assetError = nil;
AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:songAsset
error:&assetError];
if (assetError) {
NSLog (#"error: %#", assetError);
return;
}
AVAssetReaderOutput *assetReaderOutput = [AVAssetReaderAudioMixOutput
assetReaderAudioMixOutputWithAudioTracks:songAsset.tracks
audioSettings: nil];
if (! [assetReader canAddOutput: assetReaderOutput]) {
NSLog (#"can't add reader output... die!");
return;
}
[assetReader addOutput: assetReaderOutput];
NSInteger randomNumber = arc4random() % 100000;
_finalAudioName = [NSString stringWithFormat:#"%#_%ld_%#", #"Audio", (long)randomNumber, strDateAndTime];
// NSString *title = #"MyRec";
NSArray *docDirs = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [docDirs objectAtIndex: 0];
__block NSString *wavFilePath = [[docDir stringByAppendingPathComponent :_finalAudioName]
stringByAppendingPathExtension:#"wav"];
_finalAudioName = [wavFilePath lastPathComponent];
if ([[NSFileManager defaultManager] fileExistsAtPath:wavFilePath])
{
[[NSFileManager defaultManager] removeItemAtPath:wavFilePath error:nil];
}
NSURL *exportURL = [NSURL fileURLWithPath:wavFilePath];
AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:exportURL
fileType:AVFileTypeWAVE
error:&assetError];
if (assetError)
{
NSLog (#"error: %#", assetError);
return;
}
AudioChannelLayout channelLayout;
memset(&channelLayout, 0, sizeof(AudioChannelLayout));
channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
[NSNumber numberWithFloat:44100.0], AVSampleRateKey,
[NSNumber numberWithInt:1], AVNumberOfChannelsKey,
[NSData dataWithBytes:&channelLayout length:sizeof(AudioChannelLayout)], AVChannelLayoutKey,
[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
[NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
nil];
AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio
outputSettings:outputSettings];
if ([assetWriter canAddInput:assetWriterInput])
{
[assetWriter addInput:assetWriterInput];
}
else
{
NSLog (#"can't add asset writer input... die!");
return;
}
assetWriterInput.expectsMediaDataInRealTime = NO;
[assetWriter startWriting];
[assetReader startReading];
AVAssetTrack *soundTrack = [songAsset.tracks objectAtIndex:0];
CMTime startTime = CMTimeMake (0, soundTrack.naturalTimeScale);
[assetWriter startSessionAtSourceTime: startTime];
__block UInt64 convertedByteCount = 0;
dispatch_queue_t mediaInputQueue = dispatch_queue_create("mediaInputQueue", NULL);
[assetWriterInput requestMediaDataWhenReadyOnQueue:mediaInputQueue
usingBlock: ^
{
while (assetWriterInput.readyForMoreMediaData)
{
CMSampleBufferRef nextBuffer = [assetReaderOutput copyNextSampleBuffer];
if (nextBuffer)
{
// append buffer
[assetWriterInput appendSampleBuffer: nextBuffer];
convertedByteCount += CMSampleBufferGetTotalSampleSize (nextBuffer);
CMTime progressTime = CMSampleBufferGetPresentationTimeStamp(nextBuffer);
CMTime sampleDuration = CMSampleBufferGetDuration(nextBuffer);
if (CMTIME_IS_NUMERIC(sampleDuration))
progressTime= CMTimeAdd(progressTime, sampleDuration);
float dProgress= CMTimeGetSeconds(progressTime) / CMTimeGetSeconds(songAsset.duration);
NSLog(#"%f",dProgress);
}
else
{
[assetWriterInput markAsFinished];
[assetReader cancelReading];
[assetWriter finishWritingWithCompletionHandler:^{
[self uploadAudioOnAWSFromPath:wavFilePath];
}];
}
}
}];
}
In above code, the converted final file which is in .wav format that I have to send on AWS server to get text from it, For text conversation we used Google Speech API, and whenever I send file which is converted from below iOS 11 devices(like iOS 9,10), it shows me this error :
Error: WAV header indicates an unsupported format.
Above error is shown by Google Speech API while converting an Audio file(.wav) to Text format.
Above code is working perfectly with latest iOS 11 devices, only below iOS 11(like iOS 9,10) devices are not working properly.
I need to reduce the dimension of a video taken with an hybrid app without reduce the resolution therefore I'm trying to modify the cordova video editor plugin to reduce the dimension of the video by changing the bitrate.
I've tried to use SDAVAssetExportSession without any success and getting tons of CVPixel errors.
The plugin code is:
- (void) transcodeVideo:(CDVInvokedUrlCommand*)command
{
NSDictionary* options = [command.arguments objectAtIndex:0];
if ([options isKindOfClass:[NSNull class]]) {
options = [NSDictionary dictionary];
}
NSString *assetPath = [options objectForKey:#"fileUri"];
NSString *videoFileName = [options objectForKey:#"outputFileName"];
CDVQualityType qualityType = ([options objectForKey:#"quality"]) ? [[options objectForKey:#"quality"] intValue] : LowQuality;
NSString *presetName = Nil;
switch(qualityType) {
case HighQuality:
presetName = AVAssetExportPresetHighestQuality;
break;
case MediumQuality:
default:
presetName = AVAssetExportPresetMediumQuality;
break;
case LowQuality:
presetName = AVAssetExportPresetLowQuality;
}
CDVOutputFileType outputFileType = ([options objectForKey:#"outputFileType"]) ? [[options objectForKey:#"outputFileType"] intValue] : MPEG4;
BOOL optimizeForNetworkUse = ([options objectForKey:#"optimizeForNetworkUse"]) ? [[options objectForKey:#"optimizeForNetworkUse"] intValue] : NO;
float videoDuration = [[options objectForKey:#"duration"] floatValue];
BOOL saveToPhotoAlbum = [options objectForKey:#"saveToLibrary"] ? [[options objectForKey:#"saveToLibrary"] boolValue] : YES;
NSString *stringOutputFileType = Nil;
NSString *outputExtension = Nil;
switch (outputFileType) {
case QUICK_TIME:
stringOutputFileType = AVFileTypeQuickTimeMovie;
outputExtension = #".mov";
break;
case M4A:
stringOutputFileType = AVFileTypeAppleM4A;
outputExtension = #".m4a";
break;
case M4V:
stringOutputFileType = AVFileTypeAppleM4V;
outputExtension = #".m4v";
break;
case MPEG4:
default:
stringOutputFileType = AVFileTypeMPEG4;
outputExtension = #".mp4";
break;
}
// remove file:// from the assetPath if it is there
assetPath = [[assetPath stringByReplacingOccurrencesOfString:#"file://" withString:#""] mutableCopy];
// check if the video can be saved to photo album before going further
if (saveToPhotoAlbum && !UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(assetPath))
{
NSString *error = #"Video cannot be saved to photo album";
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error ] callbackId:command.callbackId];
return;
}
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *tempVideoPath =[NSString stringWithFormat:#"%#/%#%#", docDir, videoFileName, #".mov"];
NSData *videoData = [NSData dataWithContentsOfFile:assetPath];
[videoData writeToFile:tempVideoPath atomically:NO];
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:tempVideoPath] options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality])
{
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName: presetName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *videoPath = [NSString stringWithFormat:#"%#/%#%#", [paths objectAtIndex:0], videoFileName, outputExtension];
exportSession.outputURL = [NSURL fileURLWithPath:videoPath];
exportSession.outputFileType = stringOutputFileType;
exportSession.shouldOptimizeForNetworkUse = optimizeForNetworkUse;
NSLog(#"videopath of your file: %#", videoPath);
if (videoDuration)
{
int32_t preferredTimeScale = 600;
CMTime startTime = CMTimeMakeWithSeconds(0, preferredTimeScale);
CMTime stopTime = CMTimeMakeWithSeconds(videoDuration, preferredTimeScale);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exportSession.timeRange = exportTimeRange;
}
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusCompleted:
if (saveToPhotoAlbum) {
UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, nil, nil);
}
NSLog(#"Export Complete %d %#", exportSession.status, exportSession.error);
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:videoPath] callbackId:command.callbackId];
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %#", [[exportSession error] localizedDescription]);
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[[exportSession error] localizedDescription]] callbackId:command.callbackId];
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
default:
NSLog(#"Export default in switch");
break;
}
}];
}
}
How could I implement AVAssetWriter inside the cordova plugin?
NSDictionary *settings = #{AVVideoCodecKey:AVVideoCodecH264,
AVVideoWidthKey:#(video_width),
AVVideoHeightKey:#(video_height),
AVVideoCompressionPropertiesKey:
#{AVVideoAverageBitRateKey:#(desired_bitrate),
AVVideoProfileLevelKey:AVVideoProfileLevelH264Main31, /* Or whatever profile & level you wish to use */
AVVideoMaxKeyFrameIntervalKey:#(desired_keyframe_interval)}};
AVAssetWriterInput* writer_input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:settings];
I don't really need a flexible solution, hardcoding is fine.
I'm not really an Object-C expert (and I find it a quite obscure language)
I managed to solve the issue with SDAVAssetExportSession. Next, I'm contacting the author to commit the changes. Here is the code (MUST be added the CoreVideo.framework):
- (void) transcodeVideo:(CDVInvokedUrlCommand*)command
{
NSDictionary* options = [command.arguments objectAtIndex:0];
if ([options isKindOfClass:[NSNull class]]) {
options = [NSDictionary dictionary];
}
NSString *assetPath = [options objectForKey:#"fileUri"];
NSString *videoFileName = [options objectForKey:#"outputFileName"];
CDVQualityType qualityType = ([options objectForKey:#"quality"]) ? [[options objectForKey:#"quality"] intValue] : LowQuality;
NSString *presetName = Nil;
switch(qualityType) {
case HighQuality:
presetName = AVAssetExportPresetHighestQuality;
break;
case MediumQuality:
default:
presetName = AVAssetExportPresetMediumQuality;
break;
case LowQuality:
presetName = AVAssetExportPresetLowQuality;
}
CDVOutputFileType outputFileType = ([options objectForKey:#"outputFileType"]) ? [[options objectForKey:#"outputFileType"] intValue] : MPEG4;
BOOL optimizeForNetworkUse = ([options objectForKey:#"optimizeForNetworkUse"]) ? [[options objectForKey:#"optimizeForNetworkUse"] intValue] : NO;
float videoDuration = [[options objectForKey:#"duration"] floatValue];
BOOL saveToPhotoAlbum = [options objectForKey:#"saveToLibrary"] ? [[options objectForKey:#"saveToLibrary"] boolValue] : YES;
NSString *stringOutputFileType = Nil;
NSString *outputExtension = Nil;
switch (outputFileType) {
case QUICK_TIME:
stringOutputFileType = AVFileTypeQuickTimeMovie;
outputExtension = #".mov";
break;
case M4A:
stringOutputFileType = AVFileTypeAppleM4A;
outputExtension = #".m4a";
break;
case M4V:
stringOutputFileType = AVFileTypeAppleM4V;
outputExtension = #".m4v";
break;
case MPEG4:
default:
stringOutputFileType = AVFileTypeMPEG4;
outputExtension = #".mp4";
break;
}
// remove file:// from the assetPath if it is there
assetPath = [[assetPath stringByReplacingOccurrencesOfString:#"file://" withString:#""] mutableCopy];
// check if the video can be saved to photo album before going further
if (saveToPhotoAlbum && !UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(assetPath))
{
NSString *error = #"Video cannot be saved to photo album";
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error ] callbackId:command.callbackId];
return;
}
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *tempVideoPath =[NSString stringWithFormat:#"%#/%#%#", docDir, videoFileName, #".mov"];
NSData *videoData = [NSData dataWithContentsOfFile:assetPath];
[videoData writeToFile:tempVideoPath atomically:NO];
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:tempVideoPath] options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
SDAVAssetExportSession *encoder = [SDAVAssetExportSession.alloc initWithAsset:avAsset];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *videoPath = [NSString stringWithFormat:#"%#/%#%#", [paths objectAtIndex:0], videoFileName, outputExtension];
encoder.outputFileType = stringOutputFileType;
encoder.outputURL = [NSURL fileURLWithPath:videoPath];
encoder.shouldOptimizeForNetworkUse = optimizeForNetworkUse;
encoder.videoSettings = #
{
AVVideoCodecKey: AVVideoCodecH264,
AVVideoWidthKey: #1280,
AVVideoHeightKey: #720,
AVVideoCompressionPropertiesKey: #
{
AVVideoAverageBitRateKey: #1200000,
AVVideoProfileLevelKey: AVVideoProfileLevelH264High40,
},
};
encoder.audioSettings = #
{
AVFormatIDKey: #(kAudioFormatMPEG4AAC),
AVNumberOfChannelsKey: #2,
AVSampleRateKey: #44100,
AVEncoderBitRateKey: #128000,
};
[encoder exportAsynchronouslyWithCompletionHandler:^
{
if (encoder.status == AVAssetExportSessionStatusCompleted)
{
if (saveToPhotoAlbum) {
UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, nil, nil);
}
NSLog(#"Export Complete %d %#", encoder.status, encoder.error);
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:videoPath] callbackId:command.callbackId];
}
else if (encoder.status == AVAssetExportSessionStatusCancelled)
{
NSLog(#"Video export cancelled");
}
else
{
NSLog(#"Export failed: %#", [[encoder error] localizedDescription]);
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[[encoder error] localizedDescription]] callbackId:command.callbackId];
}
/*switch ([encoder status]) {
case AVAssetExportSessionStatusCompleted:
break;
case AVAssetExportSessionStatusFailed:
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
default:
NSLog(#"Export default in switch");
break;
}*/
}];
/*if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality])
{
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName: presetName];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *videoPath = [NSString stringWithFormat:#"%#/%#%#", [paths objectAtIndex:0], videoFileName, outputExtension];
exportSession.outputURL = [NSURL fileURLWithPath:videoPath];
exportSession.outputFileType = stringOutputFileType;
exportSession.shouldOptimizeForNetworkUse = optimizeForNetworkUse;
NSLog(#"videopath of your file: %#", videoPath);
if (videoDuration)
{
int32_t preferredTimeScale = 600;
CMTime startTime = CMTimeMakeWithSeconds(0, preferredTimeScale);
CMTime stopTime = CMTimeMakeWithSeconds(videoDuration, preferredTimeScale);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exportSession.timeRange = exportTimeRange;
}
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusCompleted:
if (saveToPhotoAlbum) {
UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, nil, nil);
}
NSLog(#"Export Complete %d %#", exportSession.status, exportSession.error);
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:videoPath] callbackId:command.callbackId];
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %#", [[exportSession error] localizedDescription]);
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[[exportSession error] localizedDescription]] callbackId:command.callbackId];
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
default:
NSLog(#"Export default in switch");
break;
}
}];
}*/
}
I have a video file from the device camera -- stored as /private/var/mobile/Media/DCIM/100APPLE/IMG_0203.MOV, for example, and I need to cut the first 10 seconds of this video. What API or libraries I can use?
I found solution with standard API: AVAssetExportSession
- (void)getTrimmedVideoForFile:(NSString *)filePath withInfo:(NSArray *)info
{
//[[NSFileManager defaultManager] removeItemAtURL:outputURL error:nil];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:filePath] options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
// NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSAllDomainsMask, YES);
// NSString *outputURL = paths[0];
NSFileManager *manager = [NSFileManager defaultManager];
// [manager createDirectoryAtPath:outputURL withIntermediateDirectories:YES attributes:nil error:nil];
// outputURL = [outputURL stringByAppendingPathComponent:#"output.mp4"];
NSString *outputURL = [NSString stringWithFormat:#"/tmp/%#.mp4", [info objectAtIndex:2]];
NSLog(#"OUTPUT: %#", outputURL);
// Remove Existing File
// [manager removeItemAtPath:outputURL error:nil];
if (![manager fileExistsAtPath:outputURL]) {
exportSession.outputURL = [NSURL fileURLWithPath:outputURL];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTime start = kCMTimeZero;
CMTime duration = kCMTimeIndefinite;
if ([[NSString stringWithFormat:#"%#", [info objectAtIndex:3]] floatValue] > 20.0) {
start = CMTimeMakeWithSeconds(1.0, 600);
duration = CMTimeMakeWithSeconds(10.0, 600);
}
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
[exportSession exportAsynchronouslyWithCompletionHandler:^(void) {
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
NSLog(#"Export Complete %d %#", exportSession.status, exportSession.error);
[self sendVideoPreview:info];
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Failed:%#",exportSession.error);
// [self addToDelayed:info withAction:#"add"];
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Canceled:%#",exportSession.error);
// [self addToDelayed:info withAction:#"add"];
break;
default:
break;
}
}];
} else {
[self sendVideoPreview:info];
}
Hello i am using below framworks,
#import <MediaPlayer/MediaPlayer.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
In one of button event i have implemented below code to open Library.
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = YES; // this is the default
[self presentModalViewController:mediaPicker animated:YES];
[mediaPicker release];
And in delegate methods of MPMediaPickerController implemented code as below
#pragma mark MPMediaPickerController delegate methods
- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
// Assign the selected item(s) to the music player and start playback.
counterIpod = [mediaItemCollection.items count];
totalcollection = counterIpod;
if (totalcollection > 10) {
NSString *str = [NSString stringWithFormat:#"App Only supports importing 10 songs at a time"];
UIAlertView *connectionAlert = [[UIAlertView alloc] initWithTitle:#"Message !" message:str delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[connectionAlert show];
[connectionAlert release];
}
else {
[self performSelector:#selector(saveMediaItem:) withObject:mediaItemCollection afterDelay:0.1];
//[self saveMediaItem:mediaItemCollection];
//[self showLoadingView];
}
}
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
// User did not select anything
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
}
#pragma mark Sace Item Collection to documentsDirectory
-(void)saveMediaItem:(MPMediaItemCollection *)mediaItemCollection {
for (int i = 0; i < [mediaItemCollection.items count]; i++) {
[self exportAssetAsSourceFormat:[[mediaItemCollection items] objectAtIndex:i]];
NSLog(#"for loop : %d", i);
}
NSArray *itemsArray1 = appDelegate.mediaItemCollection1.items;
MPMediaItemCollection *mediaItemCollection2;
if ([itemsArray1 count] != 0) {
mediaItemCollection2 = [self collectionByAppendingCollection:mediaItemCollection];
}
else {
mediaItemCollection2 = mediaItemCollection;
}
[self saveMediaItemAfterDeletting:mediaItemCollection2];
}
-(void)saveMediaItemAfterDeletting:(MPMediaItemCollection *)mediaItemCollection {
NSMutableData* data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:mediaItemCollection forKey:#"my_playlist"];
[archiver finishEncoding];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/playlist.data", documentsDirectory];
NSLog(#"file path = %#", filePath);
[data writeToFile:filePath atomically:YES];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
NSLog(#"file exists : ===========>>>>>>>>>>>");
} else {
NSLog(#"file doesn't exist");
}
//NSLog(#"archiving playlist success = %d", success);
[archiver release];
[data release];
[self UpdateMediaCollection];
}
-(NSString*) getExtension:(MPMediaItem *)item {
// [self showLoadingView];
NSURL *assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL];
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];
// JP
// AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
// initWithAsset:songAsset
// presetName:AVAssetExportPresetPassthrough];
NSArray *tracks = [songAsset tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *track = [tracks objectAtIndex:0];
id desc = [track.formatDescriptions objectAtIndex:0];
const AudioStreamBasicDescription *audioDesc = CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef)desc);
FourCharCode formatID = audioDesc->mFormatID;
//exportAudioMix.inputParameters = [NSArray arrayWithObject:exportAudioMixInputParameters];
//exportSession.audioMix = exportAudioMix;
NSString *fileType = nil;
NSString *ex = nil;
switch (formatID) {
case kAudioFormatLinearPCM:
{
UInt32 flags = audioDesc->mFormatFlags;
if (flags & kAudioFormatFlagIsBigEndian) {
fileType = #"public.aiff-audio";
ex = #"aif";
} else {
fileType = #"com.microsoft.waveform-audio";
ex = #"wav";
}
}
break;
case kAudioFormatMPEGLayer3:
fileType = #"com.apple.quicktime-movie";
ex = #"mp3";
break;
case kAudioFormatMPEG4AAC:
fileType = #"com.apple.m4a-audio";
ex = #"m4a";
break;
case kAudioFormatAppleLossless:
fileType = #"com.apple.m4a-audio";
ex = #"m4a";
break;
default:
break;
}
return ex;
}
#pragma mark Covert Item separate item collection and store songs into directory
- (void)exportAssetAsSourceFormat:(MPMediaItem *)item {
// [self showLoadingView];
NSLog(#"export asset called");
NSURL *assetURL = [item valueForProperty:MPMediaItemPropertyAssetURL];
NSLog(#"\n>>>> assetURL : %#",[assetURL absoluteString]);
AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL:assetURL options:nil];
// JP
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
initWithAsset:songAsset
presetName:AVAssetExportPresetPassthrough];
NSArray *tracks = [songAsset tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *track = [tracks objectAtIndex:0];
id desc = [track.formatDescriptions objectAtIndex:0];
const AudioStreamBasicDescription *audioDesc = CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef)desc);
FourCharCode formatID = audioDesc->mFormatID;
//exportAudioMix.inputParameters = [NSArray arrayWithObject:exportAudioMixInputParameters];
//exportSession.audioMix = exportAudioMix;
NSString *fileType = nil;
NSString *ex = nil;
switch (formatID) {
case kAudioFormatLinearPCM:
{
UInt32 flags = audioDesc->mFormatFlags;
if (flags & kAudioFormatFlagIsBigEndian) {
fileType = #"public.aiff-audio";
ex = #"aif";
} else {
fileType = #"com.microsoft.waveform-audio";
ex = #"wav";
}
}
break;
case kAudioFormatMPEGLayer3:
fileType = #"com.apple.quicktime-movie";
ex = #"mp3";
break;
case kAudioFormatMPEG4AAC:
fileType = #"com.apple.m4a-audio";
ex = #"m4a";
break;
case kAudioFormatAppleLossless:
fileType = #"com.apple.m4a-audio";
ex = #"m4a";
break;
default:
break;
}
exportSession.outputFileType = fileType;
NSString *fileName = nil;
fileName = [NSString stringWithString:[item valueForProperty:MPMediaItemPropertyTitle]];
fileName = [[fileName stringByAppendingString:#"-"] stringByAppendingString:[item valueForProperty:MPMediaItemPropertyArtist]];
NSArray *fileNameArray = nil;
fileNameArray = [fileName componentsSeparatedByString:#" "];
fileName = [fileNameArray componentsJoinedByString:#""];
NSLog(#">>>>> fileName = %#", fileName);
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [[docDir stringByAppendingPathComponent:fileName] stringByAppendingPathExtension:ex];
NSLog(#"filePath = %#", filePath);
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
//NSLog(#"file exist::::::::::==============>>>>>>>>>>>>>>>>>");
counterIpod--;
if(counterIpod == 0) {
//[self showAlertView];
//[self hideLoadingView];
}
NSString *str = [NSString stringWithFormat:#"Loading %d of %d Beats", totalcollection - counterIpod ,totalcollection];
[lbl performSelectorOnMainThread:#selector(setText:) withObject:str waitUntilDone:NO];
//NSLog(#"loading string : %#", str);
return;
}
//NSLog(#"file not exist ===========>>>>>>>>>");
// -------------------------------------
int fileNumber = 0;
NSString *fileNumberString = nil;
NSString *fileNameWithNumber = nil;
while ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
fileNumber++;
fileNumberString = [NSString stringWithFormat:#"-%02d", fileNumber];
fileNameWithNumber = [fileName stringByAppendingString:fileNumberString];
filePath = [[docDir stringByAppendingPathComponent:fileNameWithNumber] stringByAppendingPathExtension:ex];
//NSLog(#"filePath = %#", filePath);
}
// -------------------------------------
myDeleteFile(filePath);
exportSession.outputURL = [NSURL fileURLWithPath:filePath];
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (exportSession.status == AVAssetExportSessionStatusCompleted) {
NSLog(#"export session completed");
counterIpod--;
NSString *str = [NSString stringWithFormat:#"Loading %d of %d Beats", totalcollection - counterIpod ,totalcollection];
//[self performSelector:#selector(setLabelText:) withObject:str afterDelay:0.02];
[lbl performSelectorOnMainThread:#selector(setText:) withObject:str waitUntilDone:NO];
NSLog(#"loading string : %#", str);
if(counterIpod == 0) {
//[self showAlertView];
//[self hideLoadingView];
}
} else {
NSLog(#"export session error");
counterIpod--;
NSString *str = [NSString stringWithFormat:#"Loading %d of %d Beats", totalcollection - counterIpod ,totalcollection];
[lbl performSelectorOnMainThread:#selector(setText:) withObject:str waitUntilDone:NO];
//return NO;
if(counterIpod == 0) {
//[self showAlertView];
//[self hideLoadingView];
}
}
[exportSession release];
}];
//[appDelegate hideLoadingView];
}
#pragma mark method to delete file from document directory
void myDeleteFile (NSString* path) {
// NSLog(#"file path delete file :::::::::: %#", path);
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSError *deleteErr = nil;
[[NSFileManager defaultManager] removeItemAtPath:path error:&deleteErr];
if (deleteErr) {
NSLog (#"Can't delete %#: %#", path, deleteErr);
}
}
}
Above code work without any error on iOS 4.0 or prior version but for iOS 5.0 is crashes on device, I can't resolve these issues since last 15 days.
Thanks in advance for Help.
I have solved this issues,
just comment out this line
fileName = [[fileName stringByAppendingString:#"-"] stringByAppendingString:[item valueForProperty:MPMediaItemPropertyArtist]];
because for some songs there is null artist so it's crash...................
This is because you are using some songs has artist name while some with blank artist name, so you are trying to append blank name in string that's why app going to crash.
Hope you unserstand what i say...