简体   繁体   English

使用AVAssetWriter降低视频帧速率,同时保持相同的长度/持续时间

[英]Reduce Video Frame Rate While Keeping Same Length/Duration Using AVAssetWriter

We'll start with a basic example: Let's assume we have a video with duration of 6 seconds and 30 FPS (180 frames in total). 我们从一个基本示例开始:假设我们有一个视频,时长为6秒,帧率为30 FPS(总共180帧)。 I'd like to reduce the FPS to 15 while keeping the video 6 seconds. 我想将FPS降低到15,同时将视频保持6秒钟。 Meaning I'll need to remove/drop frames from the video ( 6 seconds * 15 FPS = 90 frames). 这意味着我需要从视频中删除/删除帧(6秒* 15 FPS = 90帧)。

Me & my team are able to change video frame rate using AVAssetWriter , but it just makes the video longer. 我和我的团队可以使用AVAssetWriter更改视频帧速率,但这只会使视频更长。 We tried to skip frames inside the: 我们试图跳过以下内容中的帧:

while(videoInput.isReadyForMoreMediaData){
          let sample = assetReaderVideoOutput.copyNextSampleBuffer()
          if (sample != nil){
             if counter % 2 == 0 {
                  continue // skip frame
              }
          videoInput.append(sampleBufferToWrite!)
} 

But it does not work. 但这行不通。 The writer forces the initial samples count, even if we skip it. 即使我们跳过它,作者也会强制执行初始样本计数。

Bottom line, How can we reduce the video Frame Rate while maintain the same duration (We are trying to create a GIFY video feeling)? 底线,我们如何在保持相同时长的同时降低视频帧频(我们正在尝试营造一种GIFY视频的感觉)?

Any help would be highly appreciated! 任何帮助将不胜感激!

Best Regards, Roi 最好的问候,Roi

For each dropped frame, you need to compensate by doubling the duration of the sample you're going to write. 对于每个丢失的帧,您需要通过将要写入的样本的持续时间加倍来进行补偿。

while(videoInput.isReadyForMoreMediaData){
  if let sample = assetReaderVideoOutput.copyNextSampleBuffer() {
    if counter % 2 == 0 {
      let timingInfo = UnsafeMutablePointer<CMSampleTimingInfo>.allocate(capacity: 1)
      let newSample = UnsafeMutablePointer<CMSampleBuffer?>.allocate(capacity: 1)

      // Should check call succeeded
      CMSampleBufferGetSampleTimingInfo(sample, 0, timingInfo)

      timingInfo.pointee.duration = CMTimeMultiply(timingInfo.pointee.duration, 2)

      // Again, should check call succeeded
      CMSampleBufferCreateCopyWithNewTiming(nil, sample, 1, timingInfo, newSample)
      videoInput.append(newSample.pointee!)
    }
    counter = counter + 1
  }
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM