Note that there are some explanatory texts on larger screens.

plurals
  1. POVideo orientation issues when exporting with AVMutableVideoComposition
    text
    copied!<p>Here is the function I used to export video:</p> <pre><code>- (void) videoOutput { //1 - Early exit if there's no video file selected if (!self.videoAsset) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Please Load a Video Asset First" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; return; } // 2 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances. AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init]; // 3 - Video track AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, self.videoAsset.duration) ofTrack:[[self.videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil]; // 3.1 - Create AVMutableVideoCompositionInstruction AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, self.videoAsset.duration); // 3.2 - Create an AVMutableVideoCompositionLayerInstruction for the video track and fix the orientation. AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; AVAssetTrack *videoAssetTrack = [[self.videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; BOOL isVideoAssetPortrait_ = NO; CGAffineTransform videoTransform = videoAssetTrack.preferredTransform; if (videoTransform.a == 0 &amp;&amp; videoTransform.b == 1.0 &amp;&amp; videoTransform.c == -1.0 &amp;&amp; videoTransform.d == 0) { isVideoAssetPortrait_ = YES; } if (videoTransform.a == 0 &amp;&amp; videoTransform.b == -1.0 &amp;&amp; videoTransform.c == 1.0 &amp;&amp; videoTransform.d == 0) { isVideoAssetPortrait_ = YES; } if (videoTransform.a == 1.0 &amp;&amp; videoTransform.b == 0 &amp;&amp; videoTransform.c == 0 &amp;&amp; videoTransform.d == 1.0) { isVideoAssetPortrait_ = NO; } if (videoTransform.a == -1.0 &amp;&amp; videoTransform.b == 0 &amp;&amp; videoTransform.c == 0 &amp;&amp; videoTransform.d == -1.0) { isVideoAssetPortrait_ = NO; } [videolayerInstruction setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero]; [videolayerInstruction setOpacity:0.0 atTime:self.videoAsset.duration]; // 3.3 - Add instructions mainInstruction.layerInstructions = [NSArray arrayWithObjects:videolayerInstruction,nil]; AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition]; CGSize naturalSize; if(isVideoAssetPortrait_){ naturalSize = CGSizeMake(videoAssetTrack.naturalSize.height, videoAssetTrack.naturalSize.width); } else { naturalSize = videoAssetTrack.naturalSize; } mainCompositionInst.renderSize = naturalSize; mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction]; mainCompositionInst.frameDuration = CMTimeMake(1, 30); // 4 - Get path NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent: [NSString stringWithFormat:@"FinalVideo-%d.mov",arc4random() % 1000]]; NSURL *url = [NSURL fileURLWithPath:myPathDocs]; // 5 - Create exporter AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality]; exporter.outputURL=url; exporter.outputFileType = AVFileTypeQuickTimeMovie; exporter.shouldOptimizeForNetworkUse = YES; exporter.videoComposition = mainCompositionInst; [exporter exportAsynchronouslyWithCompletionHandler:^{ dispatch_async(dispatch_get_main_queue(), ^{ [self exportDidFinish:exporter]; }); }]; } </code></pre> <p>The problem is that the first time I use this function to export a portrait video, the variable <strong>videoTransform (videoAssetTrack.preferredTransform)</strong> are:</p> <pre><code>videoTransform.a == 0 &amp;&amp; videoTransform.b == 1.0 &amp;&amp; videoTransform.c == -1.0 &amp;&amp; videoTransform.d == 0 </code></pre> <p>And the variable <strong>isVideoAssetPortrait_</strong> equals <strong>YES</strong>. Everything is right. However, after exporting completed and saved to Camera Roll, I used this function reload <strong>the result video</strong>. This time, the <strong>videoTransform</strong> changed:</p> <pre><code>videoTransform.a == 1.0 &amp;&amp; videoTransform.b == 0 &amp;&amp; videoTransform.c == 0 &amp;&amp; videoTransform.d == 1.0 </code></pre> <p>And <strong>isVideoAssetPortrait_</strong> equals <strong>NO</strong>. It means that after one time export, the <strong>videoTransform</strong> has changed it's values (orientation from portrait -> landscape)</p> <p>I googled many questions about video orientation of AV Foundation, but there hasn't found the solution yet.</p> <p>Thank you for reading my long explanation. If you have any question, please let me know.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload