AVMutableComposition 旋转视频

14

我最近发现在使用AVMutableComposition时出现了一个问题,希望能得到一些见解。

我想能够以两种方向录制视频-横向左和右。 当我在横向右(Home键在右侧)录制视频时,它们被添加到合成中并以正确的方向播放。 但是,如果我在横向左(Home键在左侧)录制,则这些剪辑会倒置播放。

然而,只有当它们被插入到合成中时,它们才会倒置播放,否则它们将以正确的方向播放。为什么合成会翻转以横向左拍摄的剪辑的旋转? 我应该怎么修复这个问题? 非常感谢任何帮助!


我也注意到无论我做什么,这种情况都会发生。事先设置录制方向,尝试旋转等。如果我单独播放第一段剪辑,则轨道是正面朝上的,但是一旦它被合并到组合中,它就会翻转过来。 - anon_dev1234
3个回答

35

如果你只是想保持原有的旋转方式,这里有一个稍微简单一点的方法。

// Grab the source track from AVURLAsset for example.
AVAssetTrack *assetVideoTrack = [asset tracksWithMediaType:AVMediaTypeVideo].lastObject;

// Grab the composition video track from AVMutableComposition you already made.
AVMutableCompositionTrack *compositionVideoTrack = [composition tracksWithMediaType:AVMediaTypeVideo].lastObject;

// Apply the original transform.    
if (assetVideoTrack && compositionVideoTrack) {
   [compositionVideoTrack setPreferredTransform:assetVideoTrack.preferredTransform];
}

// Export...

2
如果在组合中有多个具有不同变换的轨道,则不能简单地将每个轨道的变换设置为相同,需要进行不同的补偿。 - Julian F. Weinert
2
@bgoers 或许答案已经失效了,对我来说现在它不起作用了,因为我查到了 PreferredTransform 属性是只读的。我们无法影响这个属性。 - kokos8998
嘿@JulianF.Weinert,你好吗?我需要你的帮助。你有没有用合成播放多个视频?因为我们可以为所有合成设置preferredtransform,而不是为单个视频设置。 - Jagveer Singh
@JagveerSingh 没错。我脑海中没有现成的解决方案,但你应该能够按时间基础应用变换。一个给定片段时间的变换。如果你同时拥有它们,你可能能够创建一个组合的组合?(现在不确定) - Julian F. Weinert
@JulianF.Weinert,我已经在这里详细地提出了我的问题,请加入我的问题并告诉我解决方案。另外,您是否尝试过组合的组合。https://stackoverflow.com/questions/45145516/play-avplayer-using-avmutablecomposition-if-videos-having-different-preferredtra - Jagveer Singh
显示剩余3条评论

9

问题解决了。终于能够旋转轨道并将其转换为框架。非常好用。

    //setting up the first video based on previous recording
    CMTimeRange videoDuration = CMTimeRangeMake(kCMTimeZero, [self.previousRecording duration]);
    AVAssetTrack *clipVideoTrack = [[self.previousRecording tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    AVAssetTrack *clipAudioTrack = [[self.previousRecording tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    [compositionVideoTrack insertTimeRange:videoDuration ofTrack:clipVideoTrack atTime:nextClipStartTime error:nil];
    [compositionAudioTrack insertTimeRange:videoDuration ofTrack:clipAudioTrack atTime:nextClipStartTime error:nil];

    //our first track instruction - set up the instruction layer, then check the orientation of the track
    //if the track is in landscape-left mode, it needs to be rotated 180 degrees (PI)
    AVMutableVideoCompositionLayerInstruction *firstTrackInstruction =
         [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];

    if([self orientationForTrack:clipVideoTrack] == UIDeviceOrientationLandscapeLeft) {
        CGAffineTransform rotation = CGAffineTransformMakeRotation(M_PI);
        CGAffineTransform translateToCenter = CGAffineTransformMakeTranslation(640, 480);
        CGAffineTransform mixedTransform = CGAffineTransformConcat(rotation, translateToCenter);
        [firstTrackInstruction setTransform:mixedTransform atTime:kCMTimeZero];
    }

大家好,我也遇到了同样的问题。我使用了你们的代码,但是在[self orientationForTrack:clipVideoTrack]附近出现了错误(找不到该方法)。请问你们能否帮助我解决这个问题? - ask123
那是我自己定义的一个方法,用于确定轨道的方向。它以AVAssetTrack作为参数,然后使用首选方向。我稍微改了一下我的方法,但这应该会有所帮助 https://dev59.com/a2445IYBdhLWcg3w7ug0#6046421 - anon_dev1234
[self orientationForTrack:]是什么?它的实现是什么? - Julian F. Weinert
@Julian,我在你上面的评论中回答了那个问题,请参考一下。 - anon_dev1234

0

我认为答案肯定是最好的选择,但它只是部分正确。实际上,为了使其正常工作,我们还必须调整导出的渲染大小,翻转纵向轨道的自然大小的高度和宽度。

我刚刚测试了一下,并引用了AVFoundation编程指南-编辑部分,建议实现@dizy答案中实际建议的内容,但加上了提到的内容:

所有AVAssetTrack对象都有一个preferredTransform属性,其中包含该资产轨迹的方向信息。每当资产轨迹在屏幕上显示时,都会应用此变换。在先前的代码中,图层指令的变换设置为资产轨迹的变换,以便新组合中的视频正常显示 一旦您调整了其渲染大小。

那么代码应该像这样(只需添加两行):

// Grab the source track from AVURLAsset for example.
AVAssetTrack *assetVideoTrack = [asset tracksWithMediaType:AVMediaTypeVideo].lastObject;

// Grab the composition video track from AVMutableComposition you already made.
AVMutableCompositionTrack *compositionVideoTrack = [composition tracksWithMediaType:AVMediaTypeVideo].lastObject;

// Apply the original transform.    
if (assetVideoTrack && compositionVideoTrack) {
   [compositionVideoTrack setPreferredTransform:assetVideoTrack.preferredTransform];
}

flippedSize = CGSize(compositionVideoTrack.naturalSize.height, compositionVideoTrack.naturalSize.width);
composition.renderSize = flippedSize;

// Export..

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接