我正在尝试将使用相机作为UIImagePickerController录制后录制的两个视频合并。我已成功将视频合并为一个,但我对视频的方向存在一些问题。
正如我所知,UIImagePickerController的所有视频都是以横向拍摄的,这意味着以肖像录制的视频会旋转90°。
每次录制后,我都会将新视频添加到阵列
func imagePickerController(picker: UIImagePickerController!, didFinishPickingMediaWithInfo info:NSDictionary) {
let tempImage = info[UIImagePickerControllerMediaURL] as NSURL
videos.append(tempImage)
let pathString = tempImage.relativePath
self.dismissViewControllerAnimated(true, completion: {})
}
然后当我想要合并时,我会浏览每个视频并创建一条指令并将指令添加到另一个数组
var composition = AVMutableComposition()
let trackVideo:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
let trackAudio:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())
var insertTime = kCMTimeZero
for i in 0...(videos.count-1){
let moviePathUrl = videos[i]
let sourceAsset = AVURLAsset(URL: moviePathUrl, options: nil)
let tracks = sourceAsset.tracksWithMediaType(AVMediaTypeVideo)
let audios = sourceAsset.tracksWithMediaType(AVMediaTypeAudio)
if tracks.count > 0{
var videoDuration = CMTimeRangeMake(kCMTimeZero, sourceAsset.duration);
let assetTrack:AVAssetTrack = tracks[0] as AVAssetTrack
let assetTrackAudio:AVAssetTrack = audios[0] as AVAssetTrack
trackVideo.insertTimeRange(videoDuration, ofTrack: assetTrack, atTime: insertTime, error: nil)
trackAudio.insertTimeRange(videoDuration, ofTrack: assetTrackAudio, atTime: insertTime, error: nil)
//Rotate
var rotater = AVMutableVideoCompositionLayerInstruction(assetTrack: assetTrack)
rotater.setTransform(assetTrack.preferredTransform, atTime: insertTime)
rotater.setOpacity(0.0, atTime: CMTimeAdd(insertTime, sourceAsset.duration))
instructions.append(rotater)
//Resize
var resizer = AVMutableVideoCompositionLayerInstruction(assetTrack: assetTrack)
resizer.setCropRectangle(CGRectMake(0, 0, 300, 300), atTime: insertTime)
instructions.append(resizer)
insertTime = CMTimeAdd(insertTime, sourceAsset.duration)
}
}
当我创建所有指令时,我将它们添加到主指令并创建导出会话。
var instruction = AVMutableVideoCompositionInstruction();
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, insertTime);
instruction.layerInstructions = instructions;
var mainCompositionInst = AVMutableVideoComposition()
mainCompositionInst.instructions = NSArray(object: instruction)
mainCompositionInst.frameDuration = CMTimeMake(1, 60);
mainCompositionInst.renderSize = CGSizeMake(300, 300);
var exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality)
exporter.videoComposition = mainCompositionInst;
我错过了什么?
答案 0 :(得分:6)
尝试在图层说明的初始值设定项中使用trackVideo
,这样它就会使用AVMutableCompositionTrack
' trackID
而不是源资源trackID
}
更新
您只需要一个AVMutableVideoCompositionLayerInstruction
,因此请在循环前以AVMutableCompositionTrack
作为参数进行声明。然后在循环的每次迭代中,为您正在使用的当前视频资产设置图层指令(transform,crop rect)的必要属性。您可以控制在每次插入时应如何显示合成轨道中的视频内容。
最后,将单个layerInstruction放在指令数组中,并在视频合成中使用它。
var layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: trackVideo)
for i in 0...(videos.count-1){
//...your other code here
layerInstruction.setTransform(assetTrack.preferredTransform, atTime: insertTime)
layerInstruction.setCropRectangle(CGRectMake(0, 0, 300, 300), atTime: insertTime)
}
var instruction = AVMutableVideoCompositionInstruction();
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, insertTime);
instruction.layerInstructions = NSArray(object: layerInstruction);
var mainCompositionInst = AVMutableVideoComposition()
mainCompositionInst.instructions = NSArray(object: instruction)
答案 1 :(得分:1)
你有两层。您需要将旋转指令应用于合成中的两个图层。你在这里做的是将旋转指令仅应用于其中一个。获取对视频合成中两个元素的引用,并对两个层应用单独的指令。
答案 2 :(得分:1)
你可以使用这个简单的代码,它对我有用:
var assetVideoTrack = (sourceAsset.tracksWithMediaType(AVMediaTypeVideo)).last as! AVAssetTrack
var compositionVideoTrack = (composition.tracksWithMediaType(AVMediaTypeVideo)).last as! AVMutableCompositionTrack
if (assetVideoTrack.playable && compositionVideoTrack.playable) {
compositionVideoTrack.preferredTransform = assetVideoTrack.preferredTransform
}