2017-11-11 2 views
0

Ich arbeite an einer App, die mehrere Videoclips zu einem endgültigen Video zusammenführt. Ich möchte den Benutzern die Möglichkeit geben, einzelne Clips bei Bedarf stummzuschalten (so werden nur Teile des endgültigen zusammengeführten Videos stumm geschaltet). Ich habe die AVAssets in eine Klasse namens "Video" eingepackt, die eine "shouldMute" -Eigenschaft hat.AVMutableAudioMix mehrere Volumenänderungen an einem Track

Mein Problem ist, wenn ich die Lautstärke eines der AVAssetTracks auf Null setzt, bleibt es für den Rest des endgültigen Videos stummgeschaltet. Hier ist mein Code:

var completeDuration : CMTime = CMTimeMake(0, 1) 
    var insertTime = kCMTimeZero 
    var layerInstructions = [AVVideoCompositionLayerInstruction]() 
    let mixComposition = AVMutableComposition() 
    let audioMix = AVMutableAudioMix() 

    let videoTrack = 
     mixComposition.addMutableTrack(withMediaType: AVMediaType.video, 
             preferredTrackID: kCMPersistentTrackID_Invalid) 
    let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) 


    // iterate through video assets and merge together 
    for (i, video) in clips.enumerated() { 

     let videoAsset = video.asset 
     var clipDuration = videoAsset.duration 

     do { 
      if video == clips.first { 
       insertTime = kCMTimeZero 
      } else { 
       insertTime = completeDuration 
      } 


      if let videoAssetTrack = videoAsset.tracks(withMediaType: .video).first { 
       try videoTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, clipDuration), of: videoAssetTrack, at: insertTime) 
       completeDuration = CMTimeAdd(completeDuration, clipDuration) 
      } 

      if let audioAssetTrack = videoAsset.tracks(withMediaType: .audio).first { 
       try audioTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, clipDuration), of: audioAssetTrack, at: insertTime) 

       if video.shouldMute { 
        let audioMixInputParams = AVMutableAudioMixInputParameters() 
        audioMixInputParams.trackID = audioTrack!.trackID 
        audioMixInputParams.setVolume(0.0, at: insertTime) 
        audioMix.inputParameters.append(audioMixInputParams) 
       } 
      } 

     } catch let error as NSError { 
      print("error: \(error)") 
     } 

     let videoInstruction = videoCompositionInstructionForTrack(track: videoTrack!, video: video) 
     if video != clips.last{ 
      videoInstruction.setOpacity(0.0, at: completeDuration) 
     } 

     layerInstructions.append(videoInstruction) 
     } // end of video asset iteration 

Wenn ich hinzufügen, eine andere setVolume: atTime Anweisung die Lautstärke wieder auf 1,0 am Ende des Clips zu erhöhen, dann der erste Band-Befehl vollständig ignoriert und das komplette Video spielt bei voller Lautstärke .

Mit anderen Worten, das funktioniert nicht:

if video.shouldMute { 
        let audioMixInputParams = AVMutableAudioMixInputParameters() 
        audioMixInputParams.trackID = audioTrack!.trackID 
        audioMixInputParams.setVolume(0.0, at: insertTime) 
        audioMixInputParams.setVolume(1.0, at: completeDuration) 
        audioMix.inputParameters.append(audioMixInputParams) 
       } 

ich die AUDIOMIX auf meinem AVPlayerItem und AVAssetExportSession beide gesetzt haben. Was mache ich falsch? Was kann ich tun, damit Benutzer die Zeitbereiche einzelner Clips stummschalten können, bevor sie zum endgültigen Video hinzugefügt werden?

Antwort

0

Anscheinend habe ich das falsch gemacht. Wie Sie oben sehen können, verfügt meine Komposition über zwei AVMutableCompositionTracks: eine Videospur und eine Audiospur. Obwohl ich die Zeitbereiche einer Reihe anderer Spuren in diese beiden Spuren eingefügt habe, gibt es immer noch nur zwei Spuren. Also brauchte ich nur ein AVMutableAudioMixInputParameters-Objekt, um es mit meiner einen Audiospur zu verbinden.

Ich initialisierte ein einzelnes AVMutableAudioMixInputParameters-Objekt und dann, nachdem ich den Zeitbereich jedes Clips eingefügt hatte, überprüfte ich, ob es stummgeschaltet werden sollte und legte eine Lautstärke für den Zeitbereich des Clips fest auf die gesamte Audiospur). So sieht das in meiner Clip-Iteration aus:

if let audioAssetTrack = videoAsset.tracks(withMediaType: .audio).first { 
       try audioTrack?.insertTimeRange(CMTimeRangeMake(kCMTimeZero, clipDuration), of: audioAssetTrack, at: insertTime) 

       if video.shouldMute { 
        audioMixInputParams.setVolumeRamp(fromStartVolume: 0.0, toEndVolume: 0.0, timeRange: CMTimeRangeMake(insertTime, clipDuration)) 
       } else { 
        audioMixInputParams.setVolumeRamp(fromStartVolume: 1.0, toEndVolume: 1.0, timeRange: CMTimeRangeMake(insertTime, clipDuration)) 
       } 
      }