3

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!

  • could you do an example project? – Rhythmic Fistman Feb 28 '17 at 02:41
  • Shall I post the project on Github? –  Mar 01 '17 at 07:45
  • That would be fine – Rhythmic Fistman Mar 01 '17 at 07:46
  • Took me a while ... https://github.com/Tyrone27/RampedSlowMotionExample –  Mar 01 '17 at 08:36
  • if the timings are all correct then this is probably a bug – Rhythmic Fistman Mar 04 '17 at 05:54
  • Have you tried it out? I want to know because I'm concerned there is something that I might be missing. –  Mar 04 '17 at 11:53
  • I tried it - I didn't look very closely at the timing, but if it works for the `AVPlayer` it should be right, right? – Rhythmic Fistman Mar 04 '17 at 21:40
  • 1
    That is exactly where the problem lies. Works for the `AVPlayer`. After pressing the `button` , `AVExportSession` exports the file to the _Documents folder_ (its `url` in the **Xcode Console log**). Once saved, when the file is played with QuickTime , an empty segment is clearly noticed. For higher precision I used the seekbar that **trim** option provides (in QuickTime) , to see where exactly this empty segment is. –  Mar 05 '17 at 12:56

0 Answers0