I have made a sample app to trim a video by getting it from camera roll. Written code is as follows:
-(IBAction)cutVideo
{
NSString *path=[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0];
path=[path stringByAppendingPathComponent:#"new.mov"];
[self splitVideo:path];
}
- (void)splitVideo:(NSString *)outputURL
{
#try
{
NSURL *fileURL=[[NSURL alloc] init];
fileURL=[NSURL fileURLWithPath:outputURL];
fileURL=[NSURL URLWithString:outputURL];
// NSString *videoBundleURL = [[NSBundle mainBundle] pathForResource:#"samp" ofType:#"mov"];
AVAsset *asset = [[AVURLAsset alloc] initWithURL:fileURL options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:asset];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality])
{
[self trimVideo:outputURL assetObject:asset];
}
// videoBundleURL = nil;
asset = nil;
compatiblePresets = nil;
}
#catch (NSException * e)
{
NSLog(#"Exception Name:%# Reason:%#",[e name],[e reason]);
}
}
- (void)trimVideo:(NSString *)outputURL assetObject:(AVAsset *)asset
{
#try
{
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
exportSession.outputURL = [NSURL fileURLWithPath:outputURL];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTime start = CMTimeMakeWithSeconds(startTime, 1);
CMTime duration = CMTimeMakeWithSeconds((endTime - startTime), 1);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
if ([[NSFileManager defaultManager] fileExistsAtPath:outputURL])
{
[[NSFileManager defaultManager] removeItemAtPath:outputURL error:nil];
}
[exportSession exportAsynchronouslyWithCompletionHandler: ^(void) {
NSLog(#"Export Status %d %#", exportSession.status, [exportSession.error description]);
}];
exportSession = nil;
}
#catch (NSException * e)
{
NSLog(#"Exception Name:%# Reason:%#",[e name],[e reason]);
}
}
all is working fine but error is in export file .. error is as follows
2012-12-12 13:27:27.896 RecordVideo[1472:907] Export Status 4 Error
Domain=NSURLErrorDomain Code=-1 "unknown error" UserInfo=0x1e577ad0
{NSErrorFailingURLStringKey=/var/mobile/Applications/A38CC8B9-A8CB-4A65-8308-
24A9BEB27626/Library/Documentation/new.mov,
NSErrorFailingURLKey=/var/mobile/Applications/A38CC8B9-A8CB-4A65-8308-
24A9BEB27626/Library/Documentation/new.mov, NSLocalizedDescription=unknown error,
NSUnderlyingError=0x1e537da0 "The operation couldn’t be completed. (OSStatus error
-12935.)", NSURL=/var/mobile/Applications/A38CC8B9-A8CB-4A65-8308-
24A9BEB27626/Library/Documentation/new.mov}
Any help will be appreciated, thanks
Related
I'm using AVAssetExportSession exportAsynchronouslyWithCompletionHandler to export an audio, but error.
(In many audios, just one audio will occur this problem.)
+ (void)exportAudioWithAsset:(AVAsset *)asset exportPath:(nonnull NSString *)exportPath completion:(nonnull void (^)(BOOL, NSError * _Nullable, NSURL * _Nullable))completion {
if (!asset || !exportPath) {
if (completion) {
completion(NO, nil, nil);
}
return;
}
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetAppleM4A];
session.outputURL = [NSURL fileURLWithPath:exportPath];
session.outputFileType = AVFileTypeAppleM4A;
session.shouldOptimizeForNetworkUse = YES;
[session exportAsynchronouslyWithCompletionHandler:^{
if (session.status == AVAssetExportSessionStatusCompleted) {
NSData *data = [NSData dataWithContentsOfFile:exportPath];
if ([data length] > 0) {
if (completion) {
completion(YES, nil, [NSURL fileURLWithPath:exportPath]);
}
} else {
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) {
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
if (completion) {
completion(NO, session.error, nil);
}
}
} else {
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) {
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
if (completion) {
completion(NO, session.error, nil);
}
}
}];
}
Session's error : Error Domain=AVFoundationErrorDomain Code=-11800 "这项操作无法完成" UserInfo={NSLocalizedFailureReason=发生未知错误(-12769), NSLocalizedDescription=这项操作无法完成, NSUnderlyingError=0x283a97630 {Error Domain=NSOSStatusErrorDomain Code=-12769 "(null)"}}
(这项操作无法完成 means couldn't complete)
To solve this problem, I replace AVAssetExportSession with AVAssetReader And AVAssertWriter to export.
I'm trying to use the following code to save a snippet of audio from a url stream (e.g., a radio station broadcast):
float vocalStartMarker = 0.0;
float vocalEndMarker = 20.0;
NSURL *audioFileInput = [[NSURL alloc] initWithString: #"http://streamedaudio.mp3"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0]; //Get the docs directory
NSString *filePath = [documentsPath stringByAppendingPathComponent:#"TestName.m4a"]; //Add the file name
//[audioFileInput writeToFile:filePath atomically:YES]; //Write the file
NSURL *audioFileOutput = [[NSURL alloc] initWithString: filePath];
NSLog(#"%#", audioFileOutput);
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(vocalStartMarker * 100)), 100);
CMTime stopTime = CMTimeMake((int)(ceil(vocalEndMarker * 100)), 100);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exportSession.outputURL = audioFileOutput;
exportSession.outputFileType = AVFileTypeAppleM4A;
exportSession.timeRange = exportTimeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^
{
if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
// It worked!
}
else if (AVAssetExportSessionStatusFailed == exportSession.status)
{
NSLog(#"%#", exportSession.error);
return;
}
}];
I get the following error:
2015-12-26 14:17:11.523 SaveURL[4135:24621] Error Domain=AVFoundationErrorDomain Code=-11838 "Operation Stopped" UserInfo={NSLocalizedDescription=Operation Stopped, NSLocalizedFailureReason=The operation is not supported for this media.}
Is this because i'm trying to convert an MP3 to M4A?
Thanks in advance for your help with this.
Application Transport Security restricts requests to HTTPS unless you explicitly allow it.
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];
}
float vocalStartMarker = 1.0;
float vocalEndMarker = 3.0;
NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSURL *audioFileInput =[NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/idea_honey_bunny.mp3", [[NSBundle mainBundle] resourcePath]]];
NSURL *audioFileOutput =[NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/idea_honey_bunny.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
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(vocalStartMarker * 1)), 1);
CMTime stopTime = CMTimeMake((int)(ceil(vocalEndMarker * 1)), 1);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exportSession.outputURL = audioFileOutput;
exportSession.outputFileType = AVFileTypeAppleM4A;
exportSession.timeRange = exportTimeRange;
[exportSession exportAsynchronouslyWithCompletionHandler:^
{
if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
NSLog(#"It worked!");
}
else if (AVAssetExportSessionStatusFailed == exportSession.status)
{
// It failed...
}
}];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileOutput error:&error];
// audioPlayer.numberOfLoops = -1;
if (audioPlayer == nil)
NSLog(#"%#",error);
else
[audioPlayer play];
return YES;
}
i want to try trimming audio file but compiler not entered in this if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
NSLog(#"It worked!");
}
else if (AVAssetExportSessionStatusFailed == exportSession.status)
{
// It failed...
}
}]; bloock and file not trim
You have given same path for audioFileOutput and audioFileInput...So it is going into fail case.And also make sure that file is existed at input path...please change the OutputFile path and check..
exportAsynchronouslyWithCompletionHandler method takes some time to export new asset. So you create your audio player with asset, which not ready.
Try to change your code like this
[exportSession exportAsynchronouslyWithCompletionHandler:^
{
if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
NSLog(#"It worked!");
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileOutput error:&error];
if (audioPlayer == nil) {
NSLog(#"%#",error);
}
else {
[audioPlayer play];
}
}
else if (AVAssetExportSessionStatusFailed == exportSession.status)
{
// It failed...
}
}];
Also, as Murali said above, change path for output file
Currently I'm working on a application which deals with the videos.
In my application user can trim the video, I have a custom control for selecting the start time and end time. I need to trim the video by these two values. I tried with UIVideoEditorController like follows.
UIVideoEditorController* videoEditor = [[[UIVideoEditorController alloc] init] autorelease];
videoEditor.delegate = self;
NSString* videoPath = [[NSBundle mainBundle] pathForResource:#"test" ofType:#"MOV"];
if ( [UIVideoEditorController canEditVideoAtPath:videoPath] )
{
videoEditor.videoPath = videoPath;
[self presentModalViewController:videoEditor animated:YES];
}
else
{
NSLog( #"can't edit video at %#", videoPath );
}
But the issue is the above code will display apple's video editor control and user can do some operations on that view. I don't want to display this view, because I have already displayed the video on MPMoviePlayer and received the user input (start time and end time) for trimming the video on a custom control.
How can I trim a video without displaying UIVideoEditorController ?
Finally I found the solution.
We can use AVAssetExportSession for trimming video without displaying UIVideoEditorController.
My code is like:
- (void)splitVideo:(NSString *)outputURL
{
#try
{
NSString *videoBundleURL = [[NSBundle mainBundle] pathForResource:#"Video_Album" ofType:#"mp4"];
AVAsset *asset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath:videoBundleURL] options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:asset];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality])
{
[self trimVideo:outputURL assetObject:asset];
}
videoBundleURL = nil;
[asset release];
asset = nil;
compatiblePresets = nil;
}
#catch (NSException * e)
{
NSLog(#"Exception Name:%# Reason:%#",[e name],[e reason]);
}
}
This method trims the video
- (void)trimVideo:(NSString *)outputURL assetObject:(AVAsset *)asset
{
#try
{
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:asset presetName:AVAssetExportPresetLowQuality];
exportSession.outputURL = [NSURL fileURLWithPath:outputURL];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTime start = CMTimeMakeWithSeconds(splitedDetails.startTime, 1);
CMTime duration = CMTimeMakeWithSeconds((splitedDetails.stopTime - splitedDetails.startTime), 1);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[self checkExportSessionStatus:exportSession];
[exportSession release];
exportSession = nil;
}
#catch (NSException * e)
{
NSLog(#"Exception Name:%# Reason:%#",[e name],[e reason]);
}
}
This method checks the status of trimming:
- (void)checkExportSessionStatus:(AVAssetExportSession *)exportSession
{
[exportSession exportAsynchronouslyWithCompletionHandler:^(void)
{
switch ([exportSession status])
{
case AVAssetExportSessionStatusCompleted:
NSLog(#"Export Completed");
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Error in exporting");
break;
default:
break;
}
}];
}
I'm calling the splitVideo method from the export button action method and passes the output URL as argument.
We can import AVFoundation/AVFoundation.h
-(BOOL)trimVideofile
{
float videoStartTime;//define start time of video
float videoEndTime;//define end time of video
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_%#.mov", [dateFormatter stringFromDate:[NSDate date]]];
NSURL *videoFileOutput = [NSURL fileURLWithPath:OutputFilePath];
NSURL *videoFileInput;//<Path of orignal Video file>
if (!videoFileInput || !videoFileOutput)
{
return NO;
}
[[NSFileManager defaultManager] removeItemAtURL:videoFileOutput error:NULL];
AVAsset *asset = [AVAsset assetWithURL:videoFileInput];
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:asset
presetName:AVAssetExportPresetLowQuality];
if (exportSession == nil)
{
return NO;
}
CMTime startTime = CMTimeMake((int)(floor(videoStartTime * 100)), 100);
CMTime stopTime = CMTimeMake((int)(ceil(videoEndTime * 100)), 100);
CMTimeRange exportTimeRange = CMTimeRangeFromTimeToTime(startTime, stopTime);
exportSession.outputURL = videoFileOutput;
exportSession.timeRange = exportTimeRange;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[exportSession exportAsynchronouslyWithCompletionHandler:^
{
if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
NSLog(#"Export OK");
}
else if (AVAssetExportSessionStatusFailed == exportSession.status)
{
NSLog(#"Export failed: %#", [[exportSession error] localizedDescription]);
}
}];
return YES;
}