制作一个真正慢动作的慢动作视频

时间:2017-04-16 15:16:03

标签: ios avfoundation avassetwriter avassetwriterinput

我正在制作我的应用程序并以120和240 fps拍摄视频。

当我在Mac上观看这些视频时,我会在时间轴下方看到这些标记。

enter image description here

这些标记是可编辑的,代表慢动作区域。因此,视频以正常帧速率开始,以慢动作进入并在结束时返回正常帧速率。 iOS没有把那些标记放在那里。在那种情况下,我想知道是否有办法删除它们并使视频完全慢动作。

我正在正常初始化AVAssetWriter,就像我对视频非慢动作一样。

另外,我注意到这些"慢动作"视频不是真正的慢动作,但它们是"食谱"用于在iOS设备和使用QuickTime X的Mac上正常播放的慢动作。即使QuickTime 7也无法正常播放。

无论如何要使这个东西成为可以在任何玩家,任何计算机上播放的真实慢动作?

2 个答案:

答案 0 :(得分:2)

你的慢动作"视频文件实际上只是具有高帧率的视频文件。 iOS正在降低播放速率,以慢动作的形式展示额外的帧。问题是其他播放器以1的播放速率播放,因此为了使效果更便携,您需要修改帧显示时间戳。

您可以使用AVMutableComposition执行此操作但我更喜欢使用更多wysiwyg AVAssetReader / AVAssetWriter对。对于输入文件中的每一帧都是这样的:

if let inSampleBuffer = readerOutput.copyNextSampleBuffer() {
    let inTimeStamp = CMSampleBufferGetPresentationTimeStamp(inSampleBuffer)
    let outTimeStamp = CMTimeMultiplyByFloat64(inTimeStamp, 30.0/240)  // 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
}

答案 1 :(得分:0)

出现这种情况是因为您的视频帧率太高。所以iOS会自动为你的视频添加slowMo。 对于那些正在为此问题寻找 AVComposition 解决方案的人, 我发现了两个(糟糕的)解决方案:

  • 将 AVAssetExportSession 设置为 AVAssetExportPresetMediumQuality 或更低会导致帧速率下降,但质量也会变差。不好。
  • 将 AVAssetExportSession.videoComposition 设置为 frameDuration 为 CMTimeMake(1, 30) 的视频合成,但使用它导出视频需要很长时间,这也不好。我不知道是什么导致它需要这么长时间。

第二个是目前最好的解决方案。我已经为此发布了一些示例代码:

   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: {