2016-04-16 31 views
13

TLDR - vedi EDITfissaggio orientamento quando la cucitura (la fusione) video utilizzando AVMutableComposition

sto creando un applicazione di test a Swift dove voglio ricamare più video insieme dal mio directory apps documenti utilizzando AVMutableComposition.

Ho avuto successo nel fare questo in una certa misura, tutti i miei video sono cuciti insieme e tutto sta mostrando la dimensione corretta ritratto e paesaggio.

Il mio problema è, tuttavia, che tutti i video vengono visualizzati nell'orientamento dell'ultimo video nella compilation.

So che per risolvere questo problema dovrò aggiungere istruzioni di livello per ogni traccia che aggiungo, tuttavia non riesco a farlo bene, con le risposte che ho trovato l'intera compilation sembra uscire in un ritratto l'orientamento con i video panoramici è semplicemente ridimensionato per adattarsi alla visualizzazione verticale, quindi quando accendo il telefono su un lato per visualizzare i video panoramici sono ancora piccoli poiché sono stati adattati alle dimensioni di un ritratto.

Questo non è il risultato che sto cercando, voglio la funzionalità cioè atteso se un video è il paesaggio si mostra in scala quando in modalità verticale, ma se il telefono viene ruotato voglio che il video del paesaggio per riempire lo schermo (come è quando visualizzeresti semplicemente un video di paesaggio nelle foto) e lo stesso per il ritratto in modo che quando viene visualizzato in verticale sia a schermo intero e quando viene ruotato di lato il video viene ridimensionato in dimensioni orizzontali (come quando guarda un ritratto in foto).

In sintesi il risultato desiderato che voglio è che durante la visualizzazione di una compilation che ha paesaggio e ritratto video posso visualizzare l'intera compilation con il mio telefono su un lato e il video paesaggio sono a schermo intero e ritratto viene ridimensionato, o durante la visualizzazione lo stesso video in verticale, i video ritratti sono a schermo intero e i video panoramici vengono ridimensionati.

Con tutte le risposte ho trovato che questo non era il caso e sembravano tutti avere un comportamento molto inaspettato quando si importava un video dalle foto da aggiungere alla compilazione e lo stesso comportamento casuale quando si aggiungevano i video che erano stati girati con la parte anteriore fotocamera frontale (per essere chiari con i miei attuali video di implementazione importati dalla libreria e i video "selfie" appaiono nella dimensione corretta senza questi problemi).

Sto cercando un modo per ruotare/scalare questi video in modo che siano sempre visualizzati con l'orientamento corretto e la scala in base a quale direzione l'utente sta tenendo il telefono.

EDIT: Ora so che non è possibile avere entrambi gli orientamenti orizzontale e verticale in un singolo video, quindi il risultato atteso che sto cercando sarebbe quello di avere il video finale in orientamento orizzontale. ho capito come fare a cambiare tutti gli orientamenti e le scale per ottenere tutto allo stesso modo, ma il mio output è un video di ritratto se qualcuno potesse aiutarmi a cambiare questo modo che il mio output sia orizzontale sarebbe apprezzato.

Qui di seguito è la mia funzione per ottenere le istruzioni per ogni video:

func videoTransformForTrack(asset: AVAsset) -> CGAffineTransform 
{ 
    var return_value:CGAffineTransform? 

    let assetTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0] 

    let transform = assetTrack.preferredTransform 
    let assetInfo = orientationFromTransform(transform) 

    var scaleToFitRatio = UIScreen.mainScreen().bounds.width/assetTrack.naturalSize.width 
    if assetInfo.isPortrait 
    { 
     scaleToFitRatio = UIScreen.mainScreen().bounds.width/assetTrack.naturalSize.height 
     let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio) 
     return_value = CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor) 
    } 
    else 
    { 
     let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio) 
     var concat = CGAffineTransformConcat(CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor), CGAffineTransformMakeTranslation(0, UIScreen.mainScreen().bounds.width/2)) 
     if assetInfo.orientation == .Down 
     { 
      let fixUpsideDown = CGAffineTransformMakeRotation(CGFloat(M_PI)) 
      let windowBounds = UIScreen.mainScreen().bounds 
      let yFix = assetTrack.naturalSize.height + windowBounds.height 
      let centerFix = CGAffineTransformMakeTranslation(assetTrack.naturalSize.width, yFix) 
      concat = CGAffineTransformConcat(CGAffineTransformConcat(fixUpsideDown, centerFix), scaleFactor) 
     } 
     return_value = concat 
    } 
    return return_value! 
} 

E l'esportatore:

// Create AVMutableComposition to contain all AVMutableComposition tracks 
    let mix_composition = AVMutableComposition() 
    var total_time = kCMTimeZero 

    // Loop over videos and create tracks, keep incrementing total duration 
    let video_track = mix_composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID()) 

    var instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: video_track) 
    for video in videos 
    { 
     let shortened_duration = CMTimeSubtract(video.duration, CMTimeMake(1,10)); 
     let videoAssetTrack = video.tracksWithMediaType(AVMediaTypeVideo)[0] 

     do 
     { 
      try video_track.insertTimeRange(CMTimeRangeMake(kCMTimeZero, shortened_duration), 
       ofTrack: videoAssetTrack , 
       atTime: total_time) 

      video_track.preferredTransform = videoAssetTrack.preferredTransform 

     } 
     catch _ 
     { 
     } 

     instruction.setTransform(videoTransformForTrack(video), atTime: total_time) 

     // Add video duration to total time 
     total_time = CMTimeAdd(total_time, shortened_duration) 
    } 

    // Create main instrcution for video composition 
    let main_instruction = AVMutableVideoCompositionInstruction() 
    main_instruction.timeRange = CMTimeRangeMake(kCMTimeZero, total_time) 
    main_instruction.layerInstructions = [instruction] 
    main_composition.instructions = [main_instruction] 
    main_composition.frameDuration = CMTimeMake(1, 30) 
    main_composition.renderSize = CGSize(width: UIScreen.mainScreen().bounds.width, height: UIScreen.mainScreen().bounds.height) 

    let exporter = AVAssetExportSession(asset: mix_composition, presetName: AVAssetExportPreset640x480) 
    exporter!.outputURL = final_url 
    exporter!.outputFileType = AVFileTypeMPEG4 
    exporter!.shouldOptimizeForNetworkUse = true 
    exporter!.videoComposition = main_composition 

    // 6 - Perform the Export 
    exporter!.exportAsynchronouslyWithCompletionHandler() 
    { 
     // Assign return values based on success of export 
     dispatch_async(dispatch_get_main_queue(), {() -> Void in 
       self.exportDidFinish(exporter!) 
     }) 
    } 

Ci scusiamo per la lunga spiegazione Volevo solo assicurarsi che ero molto chiaro con quello che stavo chiedendo perché altre risposte non hanno funzionato per me.

+0

per quanto riguarda la modifica ho detto che aveva fatto registrare una taglia per far sapere a qualcuno lo farò assegnare punti per una risposta corretta, anche se non di taglie è stato pubblicato ancora IE entro i primi 2 giorni. ora ho aggiunto una taglia e ancora guadagnato attenzione zero su questa domanda tranne che per le modifiche ???? – AngryDuck

+0

Per una domanda con una dipendenza da dati esterni come questo, sarebbe utile se si potesse pubblicare l'intero progetto, inclusi i video di esempio, quindi è facile da riprodurre. – jtbandes

+0

Questo è un campione minimo completo che mostrerà il problema hai solo bisogno di 2 video come AVAssets nell'array video uno su orizzontale e uno in verticale e vedrai il problema – AngryDuck

risposta

1

Non sono sicuro che il tuo orientationFromTransform() ti dia l'orientamento corretto.

penso che si tenta di modificarlo o provare qualcosa di simile:

extension AVAsset { 

    func videoOrientation() -> (orientation: UIInterfaceOrientation, device: AVCaptureDevicePosition) { 
     var orientation: UIInterfaceOrientation = .Unknown 
     var device: AVCaptureDevicePosition = .Unspecified 

     let tracks :[AVAssetTrack] = self.tracksWithMediaType(AVMediaTypeVideo) 
     if let videoTrack = tracks.first { 

      let t = videoTrack.preferredTransform 

      if (t.a == 0 && t.b == 1.0 && t.d == 0) { 
       orientation = .Portrait 

       if t.c == 1.0 { 
        device = .Front 
       } else if t.c == -1.0 { 
        device = .Back 
       } 
      } 
      else if (t.a == 0 && t.b == -1.0 && t.d == 0) { 
       orientation = .PortraitUpsideDown 

       if t.c == -1.0 { 
        device = .Front 
       } else if t.c == 1.0 { 
        device = .Back 
       } 
      } 
      else if (t.a == 1.0 && t.b == 0 && t.c == 0) { 
       orientation = .LandscapeRight 

       if t.d == -1.0 { 
        device = .Front 
       } else if t.d == 1.0 { 
        device = .Back 
       } 
      } 
      else if (t.a == -1.0 && t.b == 0 && t.c == 0) { 
       orientation = .LandscapeLeft 

       if t.d == 1.0 { 
        device = .Front 
       } else if t.d == -1.0 { 
        device = .Back 
       } 
      } 
     } 

     return (orientation, device) 
    } 
}