This question has a couple of answers however my condition is a little different and none of the answers solve my problem.
Objective
I am trying to add a slow motion ramp to a part of my video (in the form of the letter "U" ) which I successfully achieved with the following code :
// Description : 1) For a given TimeRange , get the start and end frame.
// 2) Divide this TimeRange to 10 segment
// 3) Scale each segment with a CMTime that
// increments in each iteration of the for loop
func downWithRamp(track : AVMutableCompositionTrack){
let frameTime = CMTimeMake(1, Int32(track.nominalFrameRate))
let x1 : Double = 50
let x2 : Double = 150
let parts = (x2 - x1)/10
let x1Time = CMTimeMultiplyByFloat64(frameTime, x1)
let x2Time = CMTimeMultiplyByFloat64(frameTime, x2)
let tenthDuration = CMTimeMultiplyByFloat64(CMTimeSubtract(x2Time, x1Time) , 1/10)
var scaleFactor = 1.0
var timing = CMTimeMultiplyByFloat64(frameTime, Float64(x1))
for x in Swift.stride(from: x1, to: x2, by: parts ){
print("\(x)th Frame")
let factor = CMTimeMultiplyByFloat64( tenthDuration , 1/scaleFactor) //scale to this time
print("This range will be scaled by \(CMTimeGetSeconds(factor)) seconds")
let timeRange = CMTimeRange(start: timing, duration : tenthDuration)
print("TimeRange = \(CMTimeGetSeconds(timeRange.start)) - \(CMTimeGetSeconds(timeRange.end))secs ")
track.scaleTimeRange(timeRange , toDuration: factor)
if x < x1 + (x2 - x1)/2 {
scaleFactor = scaleFactor + 0.2 }
else { scaleFactor = scaleFactor - 0.2 }
timing = CMTimeAdd(timing, factor)
print()
}}
ISSUE : When playing the asset , The AVPlayer shows the desired result . However when I try to export the video , an arbitrary segment (scaled) appears blank.
This is how I export the video
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
let filePath = documentsDirectory.appendingPathComponent("rendered-audio.mp4")
deleteFile(filePath)
if let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality){
// exportSession.canPerformMultiplePassesOverSourceMediaData = true
exportSession.outputURL = filePath
exportSession.shouldOptimizeForNetworkUse = true
exportSession.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration)
exportSession.outputFileType = AVFileTypeQuickTimeMovie
exportSession.exportAsynchronously {
print("finished: \(filePath) : \(exportSession.status.rawValue) ")
if exportSession.status.rawValue == 4{
print("Export failed -> Reason: \(exportSession.error!.localizedDescription))")
print(exportSession.error!)
}
}
}
Some solutions suggest that the problem lies in precise timing when using scaleTimeRange(..)
, but as far as I can tell this technique generates accurate timings for each frame.Even logging shows no inconsistencies with timing.
What could be the cause of this terrifying snag. Any suggestion would be a life- saver.Thanks!