El video no gira utilizando AVMutableVideoCompositionLayerInstruction

Estoy tratando de fusionar dos videos que obtengo después de grabar usando la camera como UIImagePickerController. He logrado combinar los videos en uno, pero tengo algunos problemas con la orientación de los videos.

Como lo he entendido con el UIImagePickerController es que todos los videos se capturan en el paisaje, esto significa que los videos grabados en vertical giran 90 °.

Después de cada grabación agrego el nuevo video a una matriz

func imagePickerController(picker: UIImagePickerController!, didFinishPickingMediaWithInfo info:NSDictionary) { let tempImage = info[UIImagePickerControllerMediaURL] as NSURL videos.append(tempImage) let pathString = tempImage.relativePath self.dismissViewControllerAnimated(true, completion: {}) } 

Luego, cuando quiero fusionar, repaso cada video y creo una instrucción y agrego las instrucciones a otra matriz

 var composition = AVMutableComposition() let trackVideo:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeVideo, prefernetworkingTrackID: CMPersistentTrackID()) let trackAudio:AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, prefernetworkingTrackID: 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.prefernetworkingTransform, 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) } } 

Cuando haya creado todas las instrucciones, las agregaré a las instrucciones principales y crearé la session de export.

 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; 

¿Qué me estoy perdiendo?

Intente utilizar trackVideo en el inicializador para la instrucción layer, de modo que utilice el AVMutableCompositionTrack de trackID lugar del trackID del recurso de trackID

Actualizar:

Solo necesita una AVMutableVideoCompositionLayerInstruction , por lo que debe declararla antes del bucle con AVMutableCompositionTrack como parámetro. Luego, en cada iteración del ciclo, establezca las properties necesarias de la instrucción de capa (transformar, recortar rect.) Para el activo de video actual con el que está trabajando. Está controlando cómo debería mostrarse el contenido de video en la pista de composition en cada momento de inserción.

Al final, coloque la instrucción Single layer en el set de instrucciones y use eso en la composition de video.

 var layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: trackVideo) for i in 0...(videos.count-1){ //...your other code here layerInstruction.setTransform(assetTrack.prefernetworkingTransform, 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) 

Tienes dos capas Debe aplicar las instrucciones de rotation a ambas capas en la composition. Lo que está haciendo aquí es aplicar las instrucciones de rotation a solo una de ellas. Obtenga una reference a ambos elementos en la composition del video y aplique instrucciones separadas a las dos capas.

Puedes usar este código simple, funciona para mí:

  var assetVideoTrack = (sourceAsset.tracksWithMediaType(AVMediaTypeVideo)).last as! AVAssetTrack var compositionVideoTrack = (composition.tracksWithMediaType(AVMediaTypeVideo)).last as! AVMutableCompositionTrack if (assetVideoTrack.playable && compositionVideoTrack.playable) { compositionVideoTrack.prefernetworkingTransform = assetVideoTrack.prefernetworkingTransform }