how to control orientation of video assembled with AVMutableComposition

前端 未结 3 2035
隐瞒了意图╮
隐瞒了意图╮ 2021-01-31 12:36

I am assembling a bunch of video clips filmed on the iPhone in portrait mode. To assemble them I am taking straightforward approach as follows:

AVURLAsset to get hold

相关标签:
3条回答
  • 2021-01-31 13:15

    Setup a video composition that will handle rotate + scale:

    AVMutableVideoComposition* videoComposition = [[AVMutableVideoComposition videoComposition]retain];
    videoComposition.renderSize = CGSizeMake(320, 240);
    videoComposition.frameDuration = CMTimeMake(1, 30);
    
    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30) );
    
    AVMutableVideoCompositionLayerInstruction* rotator = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]];
    CGAffineTransform translateToCenter = CGAffineTransformMakeTranslation( 0,-320);    
    CGAffineTransform rotateBy90Degrees = CGAffineTransformMakeRotation( M_PI_2);
    CGAffineTransform shrinkWidth = CGAffineTransformMakeScale(0.66, 1); // needed because Apple does a "stretch" by default - really, we should find and undo apple's stretch - I suspect it'll be a CALayer defaultTransform, or UIView property causing this
    CGAffineTransform finalTransform = CGAffineTransformConcat( shrinkWidth, CGAffineTransformConcat(translateToCenter, rotateBy90Degrees) );
    [rotator setTransform:finalTransform atTime:kCMTimeZero];
    
    instruction.layerInstructions = [NSArray arrayWithObject: rotator];
    videoComposition.instructions = [NSArray arrayWithObject: instruction];
    
    0 讨论(0)
  • 2021-01-31 13:31

    Here's some code that adjusted the rotation using the preferred transform:

        // our composition, with one video and one audio track
    AVMutableComposition* composition = [AVMutableComposition composition];
    AVMutableCompositionTrack *videoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    AVMutableCompositionTrack *audioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    
    // loop through all the clips, adding them to our track and inserting composition instructions
    NSDictionary* options = @{ AVURLAssetPreferPreciseDurationAndTimingKey: @YES };
    CMTime insertionPoint = kCMTimeZero;
    NSMutableArray* instructions = [NSMutableArray array];
    NSError* error = nil;
    for (NSURL* outputFileURL in self.movieFileURLs) {
        AVURLAsset *asset = [AVURLAsset URLAssetWithURL:outputFileURL options:options];
    
        // insert this clip's video track into our composition
        NSArray *videoAssetTracks = [asset tracksWithMediaType:AVMediaTypeVideo];
        AVAssetTrack *videoAssetTrack = (videoAssetTracks.count > 0 ? [videoAssetTracks objectAtIndex:0] : nil);
        [videoTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero, asset.duration) ofTrack:videoAssetTrack atTime:insertionPoint error:&error];
    
        // create a layer instruction at the start of this clip to apply the preferred transform to correct orientation issues
        AVMutableVideoCompositionLayerInstruction *instruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoAssetTrack];
        [instruction setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero];
    
        // create the composition instructions for the range of this clip
        AVMutableVideoCompositionInstruction * videoTrackInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
        videoTrackInstruction.timeRange = CMTimeRangeMake(insertionPoint, asset.duration);
        videoTrackInstruction.layerInstructions = @[instruction];
        [instructions addObject:videoTrackInstruction];
    
        // insert this clip's audio track into our composition
        NSArray *audioAssetTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
        AVAssetTrack *audioAssetTrack = (audioAssetTracks.count > 0 ? [audioAssetTracks objectAtIndex:0] : nil);
        [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:audioAssetTrack atTime:insertionPoint error:nil];
    
        // advance the insertion point to the end of the clip
        insertionPoint = CMTimeAdd(insertionPoint, asset.duration);
    }
    
    // create our video composition which will be assigned to the player item
    AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
    videoComposition.instructions = instructions;
    videoComposition.frameDuration = CMTimeMake(1, videoTrack.naturalTimeScale);
    videoComposition.renderSize = videoTrack.naturalSize;
    _videoComposition = videoComposition;
    
    0 讨论(0)
  • 2021-01-31 13:32

    If all you want is preserve you video orientation you may want to assign AVMutableCompositionTrack prefferedTransition value from AVAssetTrack like this:

    AVAssetTrack *videoAssetTrack= [[videoAsset tracksWithMediaType:AVMediaTypeVideo] lastObject];
    
    AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    [videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:&error];
    
    videoCompositionTrack.preferredTransform = videoAssetTrack.preferredTransform;
    
    0 讨论(0)
提交回复
热议问题