AVAssetExportSession rotation error's when video is from camera roll - ios

I am trying to convert .mov video to .mp4 and at the same time correcting the orientation.
The code I use below works great when recording a video using UIImagePickerController however if the video is selected from the camera roll I get this error and I don't see why:
Export failed: Operation Stopped : Error
Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped"
UserInfo=0x1815ca50 {NSLocalizedDescription=Operation Stopped,
NSLocalizedFailureReason=The video could not be composed.}
I have tried first saving the video to another file, but it made no difference.
Here is the code I am using to convert the video:
- (void)convertVideoToLowQuailtyAndFixRotationWithInputURL:(NSURL*)inputURL handler:(void (^)(NSURL *outURL))handler
{
if ([[inputURL pathExtension] isEqualToString:#"MOV"])
{
NSURL *outputURL = [inputURL URLByDeletingPathExtension];
outputURL = [outputURL URLByAppendingPathExtension:#"mp4"];
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetTrack *sourceVideoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack *sourceAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
AVMutableComposition* composition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration)
ofTrack:sourceVideoTrack
atTime:kCMTimeZero error:nil];
[compositionVideoTrack setPreferredTransform:sourceVideoTrack.preferredTransform];
AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration)
ofTrack:sourceAudioTrack
atTime:kCMTimeZero error:nil];
AVMutableVideoComposition *videoComposition = [self getVideoComposition:avAsset];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetMediumQuality])
{
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:composition presetName:AVAssetExportPresetMediumQuality];
exportSession.outputURL = outputURL;
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.videoComposition = videoComposition;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status])
{
case AVAssetExportSessionStatusFailed:
NSLog(#"Export failed: %# : %#", [[exportSession error] localizedDescription], [exportSession error]);
handler(nil);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(#"Export canceled");
handler(nil);
break;
default:
handler(outputURL);
break;
}
}];
}
} else {
handler(inputURL);
}
}
- (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset
{
AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
CGSize videoSize = videoTrack.naturalSize;
BOOL isPortrait_ = [self isVideoPortrait:asset];
if(isPortrait_) {
// NSLog(#"video is portrait ");
videoSize = CGSizeMake(videoSize.height, videoSize.width);
}
composition.naturalSize = videoSize;
videoComposition.renderSize = videoSize;
videoComposition.frameDuration = CMTimeMakeWithSeconds( 1 / videoTrack.nominalFrameRate, 600);
AVMutableCompositionTrack *compositionVideoTrack;
compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoTrack atTime:kCMTimeZero error:nil];
AVMutableVideoCompositionLayerInstruction *layerInst;
layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[layerInst setTransform:videoTrack.preferredTransform atTime:kCMTimeZero];
AVMutableVideoCompositionInstruction *inst = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
inst.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
inst.layerInstructions = [NSArray arrayWithObject:layerInst];
videoComposition.instructions = [NSArray arrayWithObject:inst];
return videoComposition;
}

AVFoundation Error Constant -11841 means that you have an invalid video composition. See this link if you'd like more info on the error constants:
https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVFoundation_ErrorConstants/Reference/reference.html
While no major errors pop out at me immediately, I can suggest the following ways to narrow down the source of your problem.
First, instead of passing nil for the error parameter in these calls:
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration)
ofTrack:sourceVideoTrack
atTime:kCMTimeZero error:nil];
create an NSError object and pass the reference to it like so:
NSError *error = nil;
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration)
ofTrack:sourceVideoTrack
atTime:kCMTimeZero error:&error];
Examine the error to make sure your video and audio tracks get inserted in the composition track correctly. The error should be nil if all goes well.
if(error)
NSLog(#"Insertion error: %#", error);
You may also want to check your AVAsset's composable and exportable, and hasProtectedContent properties. If these are not YES, YES, and NO, respectively, you may have a problem creating your new video file.
Occasionally I've seen an issue where creating a time range for an audio track does not like the 600 timescale when used in a composition with a video track. You may want to create a new CMTime for the duration (avAsset.duration) in
CMTimeRangeMake(kCMTimeZero, avAsset.duration)
only for inserting the audio track. In the new CMTime,use a timescale of 44100 (or whatever the sample rate of the audio track is.) The same goes for your videoComposition.frameDuration. Depending on the nominalFrameRate of your video track, your time may not be represented correctly with 600 timescale.
Finally, there's a helpful tool provided by Apple to debug video compositions:
https://developer.apple.com/library/mac/samplecode/AVCompositionDebugViewer/Introduction/Intro.html
It gives a visual representation of your composition and you can see where things don't look like they should.

You should definitely use the method isValidForAsset:timeRange:validationDelegate: of AVVideoCompostion, it will diagnose any issue with your video composition.
I had the same problem and the solution for me was to create the layerInstruction with the AVMutableCompositionTrack instead of the original track:
layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack];

Try commenting the below line and run your project
exportSession.videoComposition = videoComposition;

Related

Merging audio and video file in ios

I am trying to merge Audio and Video file, below is my code :
AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:_BAckgroungMusicFileURL options:nil];
AVURLAsset* videoAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:_AppDel._RecordedVideoPath] options:nil];
AVMutableComposition* composition = [AVMutableComposition composition];
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = CMTimeMake(1,24);
videoComposition.renderScale = 1.0;
AVMutableCompositionTrack *compositionCommentaryTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]
atTime:kCMTimeZero error:nil];
AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
atTime:kCMTimeZero error:nil];
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack];
AVAssetTrack *sourceVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(M_PI/2);
CGAffineTransform rotateTranslate = CGAffineTransformTranslate(rotationTransform,320,0);
[compositionVideoTrack setPreferredTransform:sourceVideoTrack.preferredTransform];
[layerInstruction setTransform:rotateTranslate atTime:kCMTimeZero];
instruction.layerInstructions = [NSArray arrayWithObject: layerInstruction];
videoComposition.instructions = [NSArray arrayWithObject: instruction];
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:composition
presetName:AVAssetExportPresetPassthrough];
NSDate *_TodayDate = [NSDate dateWithTimeIntervalSinceNow:0];
_CalenderDate = [_TodayDate description];
_CombinedVideoPath = [NSString stringWithFormat:#"%#/%#.mov", DOCUMENTS_FOLDER, _CalenderDate] ;
NSURL *exportUrl = [NSURL fileURLWithPath:_CombinedVideoPath];
_assetExport.outputFileType = #"com.apple.quicktime-movie";
NSLog(#"file type %#",_assetExport.outputFileType);
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
switch (_assetExport.status)
{
case AVAssetExportSessionStatusCompleted:
NSLog(#"AVAssetExportSessionStatusCompleted");
[self SaveVideo];
break;
case AVAssetExportSessionStatusFailed:
NSLog(#"Export Failed");
NSLog(#"ExportSessionError: %#", [_assetExport.error localizedDescription]);
[self mergingCompleted];
break;
case AVAssetExportSessionStatusCancelled:
[self mergingCompleted];
NSLog(#"Export Session Status: %d", _assetExport.status);
NSLog(#"Export Failed");
NSLog(#"ExportSessionError: %#", [_assetExport.error localizedDescription]);
break;
}
}];
Here the video to be merged is recorded video. But my problem is that, when I am trying to merge this audio and video the resultant video contains the recorded video and the audio. It does not contain the audio of the recorded video. How can I have the video its audio to be merged with another audio.
Any help will be appreciated.
Thanks in advance

AVErrorInvalidVideoComposition on export a video

Before post my question, I will describe the reason of I'm compose a video with a single track. In short terms, I need a video with constant frame rate and I not found another ways to do that without export video and compose it with AVMutableComposition.
Ok, I'm very confusing with this, because sometimes my video are successful exported and sometimes not, when the video isn't exported, I got the error code -11841 (AVErrorInvalidVideoComposition). For me, this error is very generic and don't describe the reason why the video composition is invalid.
I checked all attributes but I can't find the reason why my AVMutableVideoComposition is incorrect.
There is the main code I've made to create video composition and export that.
- (void)saveVideoAtURL:(NSURL *)url withCompletionBlock:(CompletionBlock)completionBlock
{
NSError *error;
NSArray *videoTracks;
NSArray *audioTracks;
AVURLAsset *asset;
AVAssetTrack *videoAssetTrack;
AVAssetTrack *audioAssetTrack;
AVMutableComposition *composition;
AVMutableVideoComposition *videoComposition;
AVMutableCompositionTrack *videoCompositionTrack;
AVMutableCompositionTrack *audioCompositionTrack;
AVMutableVideoCompositionInstruction *videoCompositionInstruction;
AVMutableVideoCompositionLayerInstruction *videoCompositionLayerInstruction;
self.completionBlock = completionBlock;
NSDictionary *options = #{
AVURLAssetPreferPreciseDurationAndTimingKey:#YES
};
asset = [[AVURLAsset alloc] initWithURL:url options:options];
composition = [AVMutableComposition new];
videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
audioCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
videoTracks = [asset tracksWithMediaType:AVMediaTypeVideo];
videoAssetTrack = videoTracks[0];
CGSize renderSize = videoAssetTrack.naturalSize;
audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
audioAssetTrack = audioTracks[0];
[videoCompositionTrack insertTimeRange:timeRange ofTrack:videoAssetTrack atTime:kCMTimeZero error:&error];
if(error)
{
DLog(#"Error: %#", [error localizedDescription]);
self.completionBlock(NO, error);
return;
}
[audioCompositionTrack insertTimeRange:timeRange ofTrack:audioAssetTrack atTime:kCMTimeZero error:&error];
if(error)
{
DLog(#"Error: %#", [error localizedDescription]);
self.completionBlock(NO, error);
return;
}
// There is a very important instruction, without this, the video will be blank.
videoCompositionLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoAssetTrack];
// Instructions about the video composition
videoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
// Setup the video composition
videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = CMTimeMake(1, 30);
videoComposition.renderSize = renderSize;
videoComposition.renderScale = 1.0;
videoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration);
videoCompositionInstruction.layerInstructions = #[videoCompositionLayerInstruction];
videoComposition.instructions = #[videoCompositionInstruction];
// Get a new url to export the video
NSURL *outputURL = [self generateOutputURL];
// Create and exporter and save the video locally
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:[composition copy] presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL = outputURL;
exporter.videoComposition = videoComposition;
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
[exporter exportAsynchronouslyWithCompletionHandler:^{
switch (exporter.status) {
case AVAssetExportSessionStatusFailed:
case AVAssetExportSessionStatusCancelled:
DLog(#"Failed %#", exporter.error);
self.completionBlock(NO, exporter.error);
break;
case AVAssetExportSessionStatusExporting:
DLog(#"Exporting");
break;
case AVAssetExportSessionStatusCompleted:
[self exportDidFinish:exporter];
break;
default:
break;
}
}];
}

Audio Mixing in iOS using AVFoundation doesnt work

I am trying to stitch a bunch of videos together and then add some music over the video in iOS. The audio is added using AVMutableAudioMix. However when the video is finally exported the audio mix is missing. Here is how the code looks like :
- (void)mergeVideos:(NSArray *)videos{
AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
CMTime currentTime = kCMTimeZero;
for (AVAsset *asset in videos) {
// 2 - Video track
[videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
ofTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:currentTime error:nil];
[audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
ofTrack:[[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:currentTime error:nil];
currentTime = CMTimeAdd(currentTime, asset.duration);
}
// 4 - Get path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:#"mergeVideo-%d.mp4",arc4random() % 1000]];
NSURL *url = [NSURL fileURLWithPath:myPathDocs];
// 5 - Create exporter
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:mixComposition];
NSString *quality = AVAssetExportPresetHighestQuality;
//load the audio
AVMutableAudioMix *audioMix = nil;
NSURL *audioURL = [self loadAudioFile];// gives a url for a .caf file from the bundle
if (audioURL) {
AVURLAsset *audioAsset = [AVURLAsset assetWithURL:audioURL];
AVAssetTrack *aTrack = (AVAssetTrack *)[[audioAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
AVMutableAudioMixInputParameters *trackMix =
[AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:aTrack];
[trackMix setVolumeRampFromStartVolume:0 toEndVolume:1 timeRange:
CMTimeRangeMake(CMTimeMakeWithSeconds(0, 1), CMTimeMakeWithSeconds(3, 1))];
[trackMix setVolume:1.0 atTime:kCMTimeZero];
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
audioMix.inputParameters = [NSArray arrayWithObject:trackMix];
}
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
presetName:quality];
if (audioMix) {
exporter.audioMix = audioMix;
}
exporter.outputURL=url;
exporter.outputFileType = AVFileTypeMPEG4;
exporter.shouldOptimizeForNetworkUse = YES;
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self exportDidFinish:exporter];
});
}];
}
There is no error while executing. Just that the music contained in the .caf file doesnt get mixed to the exported file. Any idea what is going on?
You haven't inserted the audio from the .caf file into any AVMutableCompositionTrack, so the audio mix associated with aTrack is not going to adjust the volume for the .caf file. If you'd like the audio from the .caf file to be included in the video with the associated audio mix, create another AVMutableCompositionTrack to hold the audio from the .caf file:
AVMutableCompositionTrack *audioTrackCAF = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
(with the time ranges set to your liking):
[audioTrackCAF insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration)
ofTrack:aTrack atTime:kCMTimeZero error:nil]
Additionally, is helpful to pass an NSError * (instead of nil) to insertTimeRange:ofTrack:atTime:error to make sure you had valid time ranges and your media was inserted.

Why aren't AVMutableVideoCompositionInstruction's being applied?

I am using AVAssetExportSession to concatenate several video recordings into a single entry.
As the user can switch between front and rear camera during the recording, the orientation of the recordings switches such that if a recording comprises of one clip using the forward facing camera and a second using the rear, then the concatenated video will show the first clip using the expected orientation and the second upside down (or vice versa).
I know I need to set the videoComposition instructions on the exporter, but I have had no joy in getting any rotations to be applied to the exported video.
In the example below, I am setting a dummy rotation transform of 90 degrees, just to try and force a change across the board, but my exported video is unaffected . . . I'm guessing I'm missing something obvious, but I can't see what, can anyone see my mistake?
AVMutableComposition *composition = [AVMutableComposition composition];
AVAssetExportSession *assetExport = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetPassthrough];
NSMutableArray *instructions = [NSMutableArray new];
AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
CGAffineTransform transformToApply=CGAffineTransformMakeRotation(90.0);
for (NSURL *path in filePaths) {
NSLog(#"%#", path);
AVURLAsset *asset =[AVURLAsset assetWithURL:path];
CMTime atTime = composition.duration;
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
ofTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
atTime:atTime error:&error];
AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]];
[layerInstruction setTransform:transformToApply atTime:kCMTimeZero];
AVMutableVideoCompositionInstruction * videoTrackInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
videoTrackInstruction.timeRange = CMTimeRangeMake(atTime, asset.duration);
videoTrackInstruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
[instructions addObject:videoTrackInstruction];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
ofTrack:[[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]
atTime:atTime error:&error];
}
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.instructions = instructions;
videoComposition.frameDuration = CMTimeMake(1, compositionVideoTrack.naturalTimeScale);
videoComposition.renderSize = compositionVideoTrack.naturalSize;
assetExport.videoComposition = videoComposition;
Schoolboy error, the transform should be radians, not degrees - https://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/CGAffineTransform/Reference/reference.html

iOS rotate every frame of video

I need to rotate a video because of iPhone back camera is recording as if it were always on landscape left.
I need to physically rotate video because settings orientation don't work on all browser (ex. Chrome).
So I setup some code to read recorded video and saving it after rotation.
I used AVAssetExportSession which seems to work quite well apart two problems:
- the exported video have some black frames at the beginning
- some videos won't be exported.
Is it possible to have some insight about the problem?
Thanks!
Code:
AVAsset* asset = [AVURLAsset URLAssetWithURL: videoUrl options:nil];
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoTrack atTime:kCMTimeZero error: &error];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:audioTrack atTime:kCMTimeZero error: &error];
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake( kCMTimeZero, asset.duration);
AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack];
[layerInstruction setTransform:transformToApply atTime:kCMTimeZero];
CGAffineTransform transformToApply = ///code to setup transformation
[layerInstruction setTransform:transformToApply atTime:kCMTimeZero];
[layerInstruction setOpacity:0.0 atTime:asset.duration];
instruction.layerInstructions = [NSArray arrayWithObject: layerInstruction];
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.instructions = [NSArray arrayWithObject: instruction];
videoComposition.frameDuration = CMTimeMake( 1, 600);
videoComposition.renderScale = 1.0;
videoComposition.renderSize = videoOutputSize;
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetMediumQuality] ;
exportSession.outputURL = self.outputUrl;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
exportSession.videoComposition = videoComposition;
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
__block BOOL finishedExporting = NO;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
//
}];

Resources