Making a real slow motion video that are all slow motion
Asked Answered
A

2

9

I am creating this app of mine and shooting videos at 120 and 240 fps.

When I watch these videos on my mac I see these markers below the timeline.

enter image description here

These markers are editable and represent the area that is in slow motion. So, the video starts at the normal frame rate, enters on slow motion and returns to normal frame rate at the end. I do not put those markers there, iOS did. In that case I wonder if there are a way to remove them and make the videos entirely slow motion.

I am just initializing AVAssetWriter normally as I would for a video non-slow motion.

Also, I have noticed that these "slow motion" videos are not really slow motion but they are "recipes" for slow motion that just play correctly on iOS devices and Macs using QuickTime X. Not even QuickTime 7 plays them correctly.

Anyway to make this thing a real slow motion that can be played on any player, any computer?

Alver answered 16/4, 2017 at 15:16 Comment(1)
did you fixed this issue, could you please provide sample code of your solutionRacine
H
5

Your "slow motion" video files are actually just video files with high framerates. iOS is lowering the playback rate to show off the extra frames in the form of slow motion. The problem is that other players play at a playback rate of 1, so to make the effect portable you need to modify the frame presentation timestamps instead.

You can probably do this with an AVMutableComposition but I prefer to use the more wysiwyg AVAssetReader/AVAssetWriter pair. Something like this for every frame in the input file:

if let inSampleBuffer = readerOutput.copyNextSampleBuffer() {
    let inTimeStamp = CMSampleBufferGetPresentationTimeStamp(inSampleBuffer)
    let outTimeStamp = CMTimeMultiplyByFloat64(inTimeStamp, 240.0/30)  // slow 240 fps down to 30fps (8x slowmo)
    var outSampleBuffer: CMSampleBuffer?
    var outTimingInfo = CMSampleTimingInfo(duration: kCMTimeInvalid, presentationTimeStamp: outTimeStamp, decodeTimeStamp: kCMTimeInvalid)

    if CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault, inSampleBuffer, 1, &outTimingInfo, &outSampleBuffer) == noErr {
        writerInput.appendSampleBuffer(outSampleBuffer!)
    }
} else {
    // finished
}
Helgahelge answered 16/4, 2017 at 23:17 Comment(5)
is it possible to use this in realtime from the Camera ? i.e. Load the Camera at 240fps, feed frames to AVAssetWriterInput in realtime and export via AVAssetWriter.finishWriting() ? So the output video plays with slow-mo effect at 30fps. Do you know what are the ideal AVVideoCompressionPropertiesKey dictionary for that?Antoniettaantonin
The code above does exactly what you’re asking. I don’t think you need to add any special keys to your settings.Helgahelge
Your example is meant to be used from a video already in Disk. Load 240fps Video File -> AssetReader -> Push frames with new (30fps) timing into Writer -> new mp4 video with slow-mo effect. But I mean feeding the frames at 240fps into the AssetWriter in real time...but expect it to write a 30fps (slow-mo effect) video to disk in one pass. Camera -> Frames (240fps) -> Push frame with new (30fps)timing into Writer -> .mp4 slow mo effect video. I tried the above with your code, QuickTime info says it was encoded at 596.43 FPS.Antoniettaantonin
on another note: I think it should be 240/30.0 instead of 30.0/240Antoniettaantonin
You are 100% right @omarojo, that scale factor is upside down - and the code needs to deal with non zero start times to work with an AVCaptureSession. You say the AVAssetWriter[Input] can deal with 240fps, with expectsMediaDataInRealTime set to true? I didn't know that worked, you used to have to use a AVCaptureMovieFileOutput, in which case the PTS filter would have to happen in a 2nd (fast, non-decoding, parse-only) pass. p.s. SORRY! I obviously didn't test this answer.Helgahelge
V
0

this occurs because your video's frame rate is too high. So iOS will automatically add slowMo to your video. For those who are looking for AVComposition Solution for this issue, Two (bad) solutions I've found:

  • Setting AVAssetExportSession to AVAssetExportPresetMediumQualityor less will cause the frame rate to drop but quality will also be worse. Not good.
  • Setting AVAssetExportSession.videoComposition to a video composition with frameDuration that is CMTimeMake(1, 30) but it takes really long to export the video with that, which is not good either. I don't know what causes it to take so long.

second one is the best solution for now. i've posted some sample code for that:

   let videoComposition = AVMutableVideoComposition(propertiesOf: mixComposition)
            videoComposition.sourceTrackIDForFrameTiming = kCMPersistentTrackID_Invalid
            videoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
            // Changes FPS to 30

            //export the video to as per your requirement conversion
            if let exportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) {
                exportSession.videoComposition =  videoComposition
                exportSession.outputURL = outputURL
                exportSession.outputFileType = AVFileType.mp4
               
                
                /// try to export the file and handle the status cases
                exportSession.exportAsynchronously(completionHandler: {
Verbiage answered 8/5, 2021 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.