How to convert response of AVAssetExportSession - ios

I am using AVAssetExportSession for Audio Recording with assert and here is my code to convert AVAssert to AVAssertExportSession.
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:self.asset presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = [NSURL URLWithString:dataPath];
exportSession.outputFileType = AVFileTypeAppleM4A;
exportSession.shouldOptimizeForNetworkUse = YES;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
NSLog(#".... Audio... %#",exportSession);
}];
It gives me output like this
<AVAssetExportSession: 0x177f4b30, asset = <AVURLAsset: 0x18981f60, URL = file:///private/var/mobile/Containers/Data/Application/8BB39AD5-EEFB-4AF1-A913-B26C5C072E61/tmp/1422861622SCVideo.0.m4a>, presetName = AVAssetExportPresetAppleM4A, outputFileType = com.apple.m4a-audio
Here i just want URL to NSString.
Help me for this

After the export session is complete, you can get what you want. Because it is an asynchronous operation.
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (exportSession.status == AVAssetExportSessionStatusFailed) {
NSLog(#"failed");
} else if(exportSession.status == AVAssetExportSessionStatusCompleted){
NSLog(#"completed!");
// here you can get the output url.
}
}];

Related

Unable to convert to mp4 in iOS 13

On a device running iOS 13, [exportSession exportAsynchronouslyWithCompletionHandler: always fails with message "The operation could not be completed" while converting .MOV video to mp4. However, the same code runs fine on iOS prior to 13 i.e 12. I am pasting below my complete method
- (void)encodeVideo:(NSString *)videoURL
{
// Create the asset url with the video file
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:videoURL] options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
// Check if video is supported for conversion or not
if ([compatiblePresets containsObject: AVAssetExportPresetLowQuality])
{
//Create Export session
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName:AVAssetExportPresetLowQuality];
//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!");
}
break;
default:
break;
}
}];
}
else
{
NSLog(#"Video file not supported!");
}
}
1.
Create Folder -
let filePath = documentDirectory.appendingPathComponent("FolderName")
if !fileManager.fileExists(atPath: filePath.path) {
do {
try fileManager.createDirectory(atPath: filePath.path, withIntermediateDirectories: true, attributes: nil)
} catch {
print(error.localizedDescription)
return nil
}
}
2.
Let url = videoURL
destinationURL = filePath.appendingPathComponent("filename.mp4")
url.startAccessingSecurityScopedResource()
do {
try FileManager.default.copyItem(at: url, to: destinationURL)
} catch {
Logging.Log.error("EncodeVideo failed \(error.localizedDescription)")
}
url.startAccessingSecurityScopedResource()
Start Mov to MP4 now it is working.

How can I convert unsupported audio file's format into one of the supported format of iOS?

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

How to take specific time interval on videos from Camera Roll on iOS?

I need to take specific time interval of the video. For instance; last 40 seconds of it. I have searched for it. But could not find even a clue.
Could you please help or show me a way to do it.
BR,
This may help you out:
AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:AVAssetExportPresetHighestQuality];
exportSession.outputURL = [NSURL fileURLWithPath:outputURL];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTimeRange timeRange = CMTimeRangeMake(CMTimeMake(startMilliseconds, 1000), CMTimeMake(endMilliseconds - startMilliseconds, 1000));
exportSession.timeRange = timeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch (exportSession.status) {
case AVAssetExportSessionStatusCompleted:
// Custom method to import the Exported Video
[self loadAssetFromFile:exportSession.outputURL];
break;
case AVAssetExportSessionStatusFailed:
//
NSLog(#"Failed:%#",exportSession.error);
break;
case AVAssetExportSessionStatusCancelled:
//
NSLog(#"Canceled:%#",exportSession.error);
break;
default:
break;
}
}];

AVAssetExportSession Trim & Download

I'm trying to trim and download online video using AVExportSession.
code:
FileMove *fileMove = (FileMove*)data;
NSString *url = #"http://download.wavetlan.com/SVV/Media/HTTP/H264/Talkinghead_Media/H264_test1_Talkinghead_mp4_480x360.mp4";
NSURL *videoURL = [NSURL URLWithString:[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"VideoURL: %#",videoURL);
AVAsset *anAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:anAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
initWithAsset:anAsset presetName:AVAssetExportPresetLowQuality];
NSURL *outputURL = [NSURL fileURLWithPath:fileMove.dst];
NSLog(#"outputURL: %#",outputURL);
exportSession.outputURL = outputURL;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTime start = CMTimeMakeWithSeconds(1.0, 600);
CMTime duration = CMTimeMakeWithSeconds(3.0, 600);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
if ([[NSFileManager defaultManager] fileExistsAtPath:fileMove.dst])
[[NSFileManager defaultManager] removeItemAtPath:fileMove.dst error:nil];
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %#", [[exportSession error]description ]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
break;
default:
break;
}
}];
}
Error:
Export failed: Error Domain=AVFoundationErrorDomain Code=-11800 "The
operation could not be completed" UserInfo=0x635a820
{NSLocalizedDescription=The operation could not be completed,
NSUnderlyingError=0x1ff4240 "The operation couldn’t be completed.
(OSStatus error -12780.)", NSLocalizedFailureReason=An unknown error
occurred (-12780)}
Do you guys see any issue in the code ? Is there any limitation in AVExportSession accessing online video ?
I've managed to trim remote video using AVFoundation. Here is the sample code which is written in Swift:
let range: CMTimeRange
let sourceURL: NSURL
let targetFileURL: NSURL
let requiredKeys = [ "exportable", "tracks" ]
let asset = AVAsset(URL: sourceURL)
asset.loadValuesAsynchronouslyForKeys(requiredKeys) {
// Error handling code here
precondition(asset.statusOfValueForKey("exportable", error: nil) == .Loaded)
precondition(asset.statusOfValueForKey("tracks", error: nil) == .Loaded)
precondition(asset.exportable)
let composition = AVMutableComposition()
do {
try composition.insertTimeRange(range, ofAsset: asset, atTime: kCMTimeZero)
} catch {
// Error handling code here
return
}
let finalComposition = composition.copy() as! AVComposition
guard let export = AVAssetExportSession(asset: finalComposition, presetName: AVAssetExportPresetPassthrough) else {
// Error handling code here
return
}
export.outputURL = targetFileURL
export.outputFileType = AVFileTypeMPEG4
export.exportAsynchronouslyWithCompletionHandler {
switch export.status {
case .Completed:
// Alright!
break
case .Cancelled, .Failed:
// Error handling code here
break
default:
fatalError("Shouldn't be called")
}
}
}
The URL used for creating an AVAsset needs to be a local file that you have access to. You will need to download it onto the device before creating the AVAsset like so
I think we are not able to export online videos
see here:
Unable to export AVPlayerItem
So I guess, you can download video first locally and then trim,save and use it.

Trimming audio file in iOS 7 using AVAssetExportSession gives wrong duration

I have a requirement where user will be allowed to trim a audio file before submitting to server. The trimming function works fine in iOS 6 and not in iOS 7.
This happens in iOS 7 when user chooses a song from iTunes library and start trimming. It appears as trimmed. The new file which is created after trimming plays upto trimmed and rest will be blank. Also the duration shows the original song duration. This doesn't happen for all files. It happens only for some files. Also I did check the exportable and hasProtectedContent . Both have correct values (exportable - yes, hasProtectedContent - no). Can I know what could be issue in iOS 7.
I am pasting the trimming audio file code for reference
- (void)trimAndExportAudio:(AVAsset *)avAsset withDuration:(NSInteger)durationInSeconds withStartTime:(NSInteger)startTime endTime:(NSInteger)endTime toFileName:(NSString *)filename withTrimCompleteBlock:(TrimCompleteBlock)trimCompleteBlock
{
if (startTime < 0 || startTime > durationInSeconds || startTime >= endTime)
{
CGLog(#"start time = %d endTime %d durationInSeconds %d", startTime, endTime, durationInSeconds);
trimCompleteBlock(NO, #"Invalid Start Time");
return;
}
if (endTime > durationInSeconds)
{
CGLog(#"start time = %d endTime %d durationInSeconds %d", startTime, endTime, durationInSeconds);
trimCompleteBlock(NO, #"Invalid End Time");
return;
}
// create the export session
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:avAsset presetName:AVAssetExportPresetAppleM4A];
if (exportSession == nil)
{
trimCompleteBlock(NO, #"Could not create an Export Session.");
return;
}
//export file path
NSError *removeError = nil;
NSString *filePath = [[CGUtilities applicationLibraryMyRecordingsDirectory] stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
[[NSFileManager defaultManager] removeItemAtPath:filePath error:&removeError];
}
if (removeError)
{
CGLog(#"Error removing existing file = %#", removeError);
}
// create trim time range
CMTime exportStartTime = CMTimeMake(startTime, 1);
CMTime exportStopTime = CMTimeMake(endTime, 1);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(exportStartTime, exportStopTime);
// configure export session output with all our parameters
exportSession.outputURL = [NSURL fileURLWithPath:filePath]; // output path
exportSession.outputFileType = AVFileTypeAppleM4A; // output file type
exportSession.timeRange = exportTimeRange; // trim time range
//perform the export
__weak AVAssetExportSession *weakExportSession = exportSession;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
if (![filename isEqualToString:kLibraryTempFileName])
{
//created a new recording
}
trimCompleteBlock(YES, nil);
}
else if (AVAssetExportSessionStatusFailed == exportSession.status)
{
// a failure may happen because of an event out of your control
// for example, an interruption like a phone call comming in
// make sure and handle this case appropriately
trimCompleteBlock(NO, weakExportSession.error.description);
}
else
{
trimCompleteBlock(NO, weakExportSession.error.description);
}
}];
}
Thanks
We can import AVFoundation/AVFoundation.h
-(BOOL)trimAudiofile{
float audioStartTime;//define start time of audio
float audioEndTime;//define end time of audio
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd_HH-mm-ss"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libraryCachesDirectory = [paths objectAtIndex:0];
libraryCachesDirectory = [libraryCachesDirectory stringByAppendingPathComponent:#"Caches"];
NSString *OutputFilePath = [libraryCachesDirectory stringByAppendingFormat:#"/output_%#.mp4", [dateFormatter stringFromDate:[NSDate date]]];
NSURL *audioFileOutput = [NSURL fileURLWithPath:OutputFilePath];
NSURL *audioFileInput;//<Path of orignal audio file>
if (!audioFileInput || !audioFileOutput)
{
return NO;
}
[[NSFileManager defaultManager] removeItemAtURL:audioFileOutput error:NULL];
AVAsset *asset = [AVAsset assetWithURL:audioFileInput];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:asset
presetName:AVAssetExportPresetAppleM4A];
if (exportSession == nil)
{
return NO;
}
CMTime startTime = CMTimeMake((int)(floor(audioStartTime * 100)), 100);
CMTime stopTime = CMTimeMake((int)(ceil(audioEndTime * 100)), 100);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exportSession.outputURL = audioFileOutput;
exportSession.timeRange = exportTimeRange;
exportSession.outputFileType = AVFileTypeAppleM4A;
[exportSession exportAsynchronouslyWithCompletionHandler:^
{
if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
NSLog(#"Export OK");
}
else if (AVAssetExportSessionStatusFailed == exportSession.status)
{
NSLog(#"Export failed: %#", [[exportSession error] localizedDescription]);
}
}];
return YES;
}

Resources