Проблема с применением scaleTimeRange к нескольким видео в видео AVMutableComposition

Я пытаюсь объединить видео с помощью scaleTimeRanges (чтобы сделать их медленными или ускоренными); однако он не работает так, как хотелось бы. Только первое видео имеет эффект временного диапазона... не все.

Работа выполняется в функции слияния видео; это довольно просто... однако я не уверен, почему масштабирование временного диапазона не работает только для первого видео, а не для следующих...

Это тестовый проект для тестирования, в нем есть мой текущий код: https://github.com/meyesyesme/creationMergeProj

Это функция слияния, которую я использую, с масштабированием временного диапазона, которое в настоящее время закомментировано (вы можете раскомментировать, чтобы увидеть, что это не работает):

func mergeVideosTestSQ(arrayVideos:[VideoSegment], completion:@escaping (URL?, Error?) -> ()) {


let mixComposition = AVMutableComposition()


var instructions: [AVMutableVideoCompositionLayerInstruction] = []
var insertTime = CMTime(seconds: 0, preferredTimescale: 1)

print(arrayVideos, "<- arrayVideos")
/// for each URL add the video and audio tracks and their duration to the composition
for videoSegment in arrayVideos {
    
    let sourceAsset = AVAsset(url: videoSegment.videoURL!)
    
    let frameRange = CMTimeRange(start: CMTime(seconds: 0, preferredTimescale: 1), duration: sourceAsset.duration)
    
    guard
        let nthVideoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)),
        let nthAudioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: Int32(kCMPersistentTrackID_Invalid)), //0 used to be kCMPersistentTrackID_Invalid
        let assetVideoTrack = sourceAsset.tracks(withMediaType: .video).first
    else {
        print("didnt work")
        return
    }
    
    var assetAudioTrack: AVAssetTrack?
    assetAudioTrack = sourceAsset.tracks(withMediaType: .audio).first
    print(assetAudioTrack, ",-- assetAudioTrack???", assetAudioTrack?.asset, "<-- hes", sourceAsset)
    
    do {
        
        try nthVideoTrack.insertTimeRange(frameRange, of: assetVideoTrack, at: insertTime)
        try nthAudioTrack.insertTimeRange(frameRange, of: assetAudioTrack!, at: insertTime)
        
        //MY CURRENT SPEED ATTEMPT:
        let newDuration = CMTimeMultiplyByFloat64(frameRange.duration, multiplier: videoSegment.videoSpeed)
        nthVideoTrack.scaleTimeRange(frameRange, toDuration: newDuration)
        nthAudioTrack.scaleTimeRange(frameRange, toDuration: newDuration)
        
        print(insertTime.value, "<-- fiji, newdur --->", newDuration.value, "sourceasset duration--->", sourceAsset.duration.value, "frameRange.duration -->", frameRange.duration.value)
        
        //instructions:
        let nthInstruction = ViewController.videoCompositionInstruction(nthVideoTrack, asset: sourceAsset)
        nthInstruction.setOpacity(0.0, at: CMTimeAdd(insertTime, newDuration)) //sourceasset.duration
        
        instructions.append(nthInstruction)
        insertTime = insertTime + newDuration //sourceAsset.duration
        
        
    } catch {
        DispatchQueue.main.async {
            print("didnt wor2k")
        }
    }
    
}


let mainInstruction = AVMutableVideoCompositionInstruction()
mainInstruction.timeRange = CMTimeRange(start: CMTime(seconds: 0, preferredTimescale: 1), duration: insertTime)

mainInstruction.layerInstructions = instructions

let mainComposition = AVMutableVideoComposition()
mainComposition.instructions = [mainInstruction]
mainComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
mainComposition.renderSize = CGSize(width: 1080, height: 1920)

let outputFileURL = URL(fileURLWithPath: NSTemporaryDirectory() + "merge.mp4")

//below to clear the video form docuent folder for new vid...
let fileManager = FileManager()
try? fileManager.removeItem(at: outputFileURL)

print("<now will export: ???? ????????????????????????????????????????????????????????????????????????????????????????????????????????????")


/// try to start an export session and set the path and file type
if let exportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) { //DOES NOT WORK WITH AVAssetExportPresetPassthrough
    exportSession.outputFileType = .mov
    exportSession.outputURL = outputFileURL
    exportSession.videoComposition = mainComposition
    exportSession.shouldOptimizeForNetworkUse = true
    
    /// try to export the file and handle the status cases
    exportSession.exportAsynchronously {
        if let url = exportSession.outputURL{
            completion(url, nil)
        }
        if let error = exportSession.error {
            completion(nil, error)
        }
    }
    
}

}

Вы увидите такое поведение: первое видео работает хорошо, но следующие видео не работают и имеют проблемы с установкой непрозрачности и т. д. Я пробовал разные комбинации, и это пока самое близкое.

Я застрял на этом некоторое время!


person NCT 127    schedule 07.11.2020    source источник


Ответы (1)


  1. После того, как вы масштабируете видео, продолжительность композиции пересчитывается, поэтому вам нужно добавить следующую часть в соответствии с этим изменением. Заменять

     insertTime = insertTime + duration
    

    с

     insertTime = insertTime + newDuration
    
  2. Вам также необходимо обновить значение setOpacity at, я бы посоветовал вам переместить эту строку после обновления insertTime и использовать новое значение, чтобы удалить дублирующую работу здесь

  3. Когда вы применяете масштаб, он применяется к новой композиции, поэтому вам нужно использовать относительный диапазон:

     let currentRange = CMTimeRange(start: insertTime, duration: frameRange.duration)
     nthVideoTrack.scaleTimeRange(currentRange, toDuration: newDuration)
     nthAudioTrack.scaleTimeRange(currentRange, toDuration: newDuration)
    
person Philip    schedule 12.11.2020
comment
да, я обновил свой код до этого, однако он все еще не работает. Вы можете увидеть, если вы протестируете, если вы сделаете, например, три видео, скажем, со скоростью 0,3, первое видео работает хорошо, но второе и третье не будут работать хорошо. Кажется, любое слияние, которое имеет ›= 3 видео, не будет работать... по крайней мере, из моего тестирования - person NCT 127; 13.11.2020
comment
Я нашел вторую проблему в вашем коде, пожалуйста, ознакомьтесь с обновленным ответом - person Philip; 14.11.2020
comment
Ok! из моего тестирования это отлично работает! Я сделаю еще немного тестов, а потом скажу тебе! - person NCT 127; 15.11.2020