Отсутствуют некоторые видео при сшивке с помощью AVFoundations

Я пытаюсь объединить несколько видео с помощью AVFoundation. Он отлично работает, когда я добавляю только два видео. Но когда я пытаюсь добавить 3 видео, вторая видеодорожка пуста, но общая продолжительность экспортируемых видео правильная.

Вот мой пример кода:

Код для добавления видео:

func addVideo(videoAsset: AVAsset, isLast: Bool = false)
{
    // Add video track
    guard let videoTrack = self.mixComposition.addMutableTrack(
       withMediaType: .video,
       preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
       else { return }
        
    do
    {
        try videoTrack.insertTimeRange(
          CMTimeRangeMake(start: .zero, duration: videoAsset.duration),
          of: videoAsset.tracks(withMediaType: .video)[0],
          at: totalVideoTrackDuration)
            
          // Add instruction for this track
          // video helper fixes the video orientation 
          let instruction = VideoHelper.videoCompositionInstruction(videoTrack, asset: videoAsset)
            
          if !isLast
          {
             // hide this clip when its done rendering
             instruction.setOpacity(0.0, at: videoAsset.duration)
          }
            
          // add to layer instruction
          self.instructions.append(instruction)
            
          // get the sum of all added track durations
          self.totalVideoTrackDuration = CMTimeAdd(self.totalVideoTrackDuration, videoAsset.duration)
      }
            
      catch
      {
          print("Failed to load track")
          return
      }
}

Вот код для экспорта видео:

func export()
{
   // 6
   let mainInstruction = AVMutableVideoCompositionInstruction()
        
    // set time range
    mainInstruction.timeRange = CMTimeRangeMake(   
       start: .zero,
       duration: self.totalVideoTrackDuration
    )
        
    
    mainInstruction.layerInstructions = self.instructions
        
    let mainComposition = AVMutableVideoComposition()
    mainComposition.instructions = [mainInstruction]
    mainComposition.frameDuration = CMTimeMake(value: 1, timescale: self.timeScale)
    mainComposition.renderSize = self.videoSize
        
    guard let documentDirectory = FileManager.default.urls(
       for: .documentDirectory,
       in: .userDomainMask).first
       else { return }
        
        // file name
    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .long
    dateFormatter.timeStyle = .short
    let date = Date().format(format: "mm-dd-yy-HH-mm-ss")!
    let url = documentDirectory.appendingPathComponent("mergeVideo-\(date).mov")
        
    guard let exporter = AVAssetExportSession(
       asset: self.mixComposition,
       presetName: AVAssetExportPresetHighestQuality)
       else { return }
        
    exporter.outputURL = url
    exporter.outputFileType = AVFileType.mov
    exporter.shouldOptimizeForNetworkUse = true
    exporter.videoComposition = mainComposition
     
    exporter.exportAsynchronously {
            
    PHPhotoLibrary.shared().performChanges({ 
       PHAssetChangeRequest.
          creationRequestForAssetFromVideo(
            atFileURL: exporter.outputURL!)
          }){ 

          saved, error in
          
             if saved 
             {
                print("Export successful")
             } 
             else
             {
                print("video erro: \(error)")
             }
        }
    }
}

Вот как я вызываю функцию addVideo:

// 4-second video
self.addVideo(videoAsset: asset1) 

// 3-second video
self.addVideo(videoAsset: asset2) 

// 4-second video
self.addVideo(videoAsset: asset3, isLast: true)

// export
self.export()

// the total duration of the exported video is 11 seconds. But the middle part, is blank.

person Allan Macatingrao    schedule 17.08.2020    source источник


Ответы (1)


Оказывается, проблемная строка:

if !isLast
{
   // hide this clip when its done rendering
   instruction.setOpacity(0.0, at: videoAsset.duration)
}

// get the sum of all added track durations
self.totalVideoTrackDuration = CMTimeAdd(self.totalVideoTrackDuration, videoAsset.duration)

Должен быть:

// get the sum of all added track durations
self.totalVideoTrackDuration = CMTimeAdd(self.totalVideoTrackDuration, videoAsset.duration)

if !isLast
{
   instruction.setOpacity(0.0, at: self.totalVideoTrackDuration)
}

Документация для setOpacity немного сбивает с толку. Я думал, что параметр at - это время в этом конкретном временном диапазоне видео.

person Allan Macatingrao    schedule 17.08.2020