下面有新的编辑
我已经参考了AVMutableComposition - Only Playing First Track (Swift),但这并没有提供我正在寻找的答案。
我有一个AVMutableComposition()
。我试图在单个合成中应用多个AVCompositionTrack
,它们都是相同类型的AVMediaTypeVideo
。这是因为我正在使用两个不同的AVMediaTypeVideo
源,它们具有来自AVAsset
的不同CGSize
和preferredTransforms
。
所以,唯一的方法是将它们的指定preferredTransforms
提供在2个不同的轨道中。但是,由于某种原因,只有第一个轨道实际上会提供任何视频,几乎就像第二个轨道不存在一样。
所以,我尝试过:
1)使用AVMutableVideoCompositionLayerInstruction
并应用AVVideoComposition
和AVAssetExportSession
,这可以工作,并且可以处理变换,但是处理时间远远超过1分钟,这在我的情况下是不适用的。
2)使用多个轨道,没有AVAssetExportSession
,相同类型的第二个轨道从未出现。现在,我可以把它们都放在一个轨道上,但是所有的视频将与第一个视频具有相同的大小和preferredTransform,这是我绝不想要的,因为它们会在所有方面拉伸。
所以我的问题是,这是否可能:
1)仅对轨道应用指示而不使用AVAssetExportSession
?//迄今为止最佳方式。
2)减少导出时间?(我尝试过使用PresetPassthrough
,但如果您有exporter.videoComposition
则无法使用该选项,其中包含我的指示。这是我知道可以放置指示的唯一位置,不确定是否可以将其放在其他地方。
这是我的一些代码(没有导出器,因为我不需要在任何地方导出任何东西,只需在AVMutableComposition组合项目后执行操作。
func merge() {
if let firstAsset = controller.firstAsset, secondAsset = self.asset {
let mixComposition = AVMutableComposition()
let firstTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo,
preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
do {
//Don't need now according to not being able to edit first 14seconds.
if(CMTimeGetSeconds(startTime) == 0) {
self.startTime = CMTime(seconds: 1/600, preferredTimescale: Int32(600))
}
try firstTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, CMTime(seconds: CMTimeGetSeconds(startTime), preferredTimescale: 600)),
ofTrack: firstAsset.tracksWithMediaType(AVMediaTypeVideo)[0],
atTime: kCMTimeZero)
} catch _ {
print("Failed to load first track")
}
//This secondTrack never appears, doesn't matter what is inside of here, like it is blank space in the video from startTime to endTime (rangeTime of secondTrack)
let secondTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo,
preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
// secondTrack.preferredTransform = self.asset.preferredTransform
do {
try secondTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, secondAsset.duration),
ofTrack: secondAsset.tracksWithMediaType(AVMediaTypeVideo)[0],
atTime: CMTime(seconds: CMTimeGetSeconds(startTime), preferredTimescale: 600))
} catch _ {
print("Failed to load second track")
}
//This part appears again, at endTime which is right after the 2nd track is suppose to end.
do {
try firstTrack.insertTimeRange(CMTimeRangeMake(CMTime(seconds: CMTimeGetSeconds(endTime), preferredTimescale: 600), firstAsset.duration-endTime),
ofTrack: firstAsset.tracksWithMediaType(AVMediaTypeVideo)[0] ,
atTime: CMTime(seconds: CMTimeGetSeconds(endTime), preferredTimescale: 600))
} catch _ {
print("failed")
}
if let loadedAudioAsset = controller.audioAsset {
let audioTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: 0)
do {
try audioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, firstAsset.duration),
ofTrack: loadedAudioAsset.tracksWithMediaType(AVMediaTypeAudio)[0] ,
atTime: kCMTimeZero)
} catch _ {
print("Failed to load Audio track")
}
}
}
}
编辑
苹果公司表示:“通过实现AVVideoCompositionInstruction协议的类的NSArray实例指示视频合成的指令。 对于数组中的第一个指令,timeRange.start必须小于或等于将尝试播放或进行其他处理的最早时间 (请注意,这通常是kCMTimeZero)。对于后续指令,timeRange.start必须等于前一个指令的结束时间。最后一条指令的结束时间必须大于或等于将尝试播放或进行其他处理的最新时间 (请注意,这通常是与AVVideoComposition实例相关联的资产的持续时间)。”
这只是说明整个组合必须在指令内部分层,如果您决定使用任何指令(这就是我的理解)。为什么?如何在此示例中仅应用于轨道2而不更改轨道1或3:
从0秒到10秒的第1轨道,从10秒到20秒的第2轨道,从20秒到30秒的第3轨道。
任何关于此的解释可能都会回答我的问题(如果可行的话)。