2014-12-23 14 views
5

Próbuję połączyć dwa filmy, które otrzymuję po nagraniu, używając aparatu jako UIImagePickerController. Udało mi się połączyć filmy w jeden, ale mam pewne problemy z orientacją filmów.Wideo nie obraca się za pomocą AVMutableVideoCompositionLayerInstruction

Jak mam rozumieć to z UIImagePickerController jest to, że wszystkie filmy są ujęte w krajobrazie, oznacza to, że filmy nagrane w układzie pionowym są obrócone o 90 °.

Po każdym nagraniu dodaję nowy film na tablicy

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

Wtedy gdy chcę połączyć idę przez każdego filmu i stworzyć dyspozycję i dodaje dyspozycję do innej tablicy

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) 

    } 
} 

Po utworzeniu wszystkich instrukcji dodam je do głównej instrukcji i utworzę sesję eksportu.

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; 

Czego mi brakuje?

Odpowiedz

5

Spróbuj użyć trackVideo w inicjatora do Instrukcji warstwy więc będzie użyć AVMutableCompositionTrack „s trackID zamiast aktywo źródłowego trackID

Aktualizacja:

Wystarczy tylko jeden AVMutableVideoCompositionLayerInstruction, więc zadeklarować przed Pętla z parametrem AVMutableCompositionTrack. Następnie w każdej iteracji pętli ustaw niezbędne właściwości instrukcji warstwy (transformuj, przycinaj) dla bieżącego zasobu wideo, z którym pracujesz. Kontrolujesz, jak zawartość wideo w ścieżce kompozycji powinna być wyświetlana przy każdym czasie wstawiania.

Na koniec umieść pojedynczy layerInstruction w tablicy instrukcje i użyć jej w składzie wideo.

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) 
+0

Wciąż ten sam problem, bez różnicy –

+0

Właściwie, myślę, że potrzebujesz tylko jednej instancji 'rotater'. Jest tylko jedna ścieżka kompozycji wideo, więc musisz zadeklarować 'rotater' poza pętlą i ustawić przekształcenie, aby zastosować je w czasie rozpoczęcia każdego nowego wideo. Jeśli łączysz filmy, nie ma potrzeby ustawiania krycia na 0. Następny pojawi się. – jlw

+0

Jeśli dobrze cię zrozumiałem, tworzę rotację za pomocą trackVideo tuż przed pętlą. Następnie wewnątrz pętli ustawiam transformację, tak jak poprzednio. To też nie działa. :/ –

1

Masz dwie warstwy. Trzeba zastosować instrukcję rotacji do obu warstw w kompozycji. To, co tu robisz, polega na stosowaniu instrukcji rotacji tylko do jednego z nich. Uzyskaj odniesienie do obu elementów w kompozycji wideo i zastosuj osobne instrukcje do tych dwóch warstw.

+0

Czy nie jest to, co mam już robić? Dodałem więcej mojego kodu do mojego pytania –

1

można po prostu użyć tego prostego kodu, to działa na mnie:

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 
    }