I'm trying to export a .mov file from a source video created by UIImagePickerController. The problem is that the output file AVAssetExportSession creates is only 668 bytes. Why is it failing? my code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSURL *imagePickerVideoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSString *filename = @"vid1.mov";
AVAsset *video = [AVAsset assetWithURL:imagePickerVideoURL];
AVAssetExportSession *exportSession
= [AVAssetExportSession exportSessionWithAsset:video presetName:AVAssetExportPresetMediumQuality];
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
exportSession.outputURL = [pathToSavedVideosDirectory URLByAppendingPathComponent:filename];
NSLog(@"processing video...: %@", exportSession);
[exportSession exportAsynchronouslyWithCompletionHandler:^{
NSLog(@"done processing video!");
}];
}
I'm going to guess it's because exportSession
was not retained in memory, thus gets killed after the didFinishPickingMediaWithInfo
completes (before the export session completion handler runs).
Store exportSession
to a @property
or change your completion handler to copy a reference to exportSession
like so:
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (AVAssetExportSessionStatusCompleted == exportSession.status)
{
NSLog(@"done processing video!");
}
}];
you need to write down steps for video file with AVAssetExportSession..
Start with Asset
Put your fileURL
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:fileURL options:nil];
Create AVMutableComposition
AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack *clipVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:clipVideoTrack atTime:kCMTimeZero error:nil];
[compositionVideoTrack setPreferredTransform:[[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] preferredTransform]];
AVAssetTrack *clipAudioTrack = [[videoAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,videoAsset.duration) ofTrack:clipAudioTrack atTime:kCMTimeZero error:nil];
Create AVMutableVideoComposition
with Aniamtion layer if you want
AVMutableVideoComposition* videoComp = [[AVMutableVideoComposition videoComposition] retain];
videoComp.renderSize = CGSizeMake(videoSize.width, videoSize.height);
videoComp.frameDuration = CMTimeMake(1, 30);
videoComp.renderScale = 1.0;
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
Animation layer are here if you need otherwise pass nil
.
CGSize videoSize = [videoAsset naturalSize];
//layer mixing
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
[parentLayer addSublayer:videoLayer];
Add aniamtion to your selected layer which you need to add as sublayer
in parentLayer
Add instruction in video composition with mention animation layer and time duration.
AVMutableVideoCompositionInstruction
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mixComposition duration]);
AVAssetTrack *videoTrack = [[mixComposition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
videoComp.instructions = [NSArray arrayWithObject: instruction];
Now creating AVAssetExportSession
with use of AVMutableComposition
and AVMutableVideoComposition
_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
_assetExport.videoComposition = videoComp;
//Create tmepory path for exported video file. .m4a would be preferred extension for AVFoundation.
NSString *videoName = @"demo.m4a";
NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
{
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
Add url in Export session and some required property.
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
Start Export session and perform action when you will get complete message.
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
switch (_assetExport.status)
{
case AVAssetExportSessionStatusUnknown:
NSLog(@"Unknown");
case AVAssetExportSessionStatusExporting:
NSLog(@"Exporting");
case AVAssetExportSessionStatusFailed:
NSLog(@"exporting failed");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(@"exporting completed");
[self performSelectorOnMainThread:@selector(completeVideoExport) withObject:nil waitUntilDone:YES];
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"export cancelled");
break;
}
_assetExport = nil;
[_assetExport release];
}
];
if you need any more let me know..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With