情况:
我正在尝试以一些参数导出视频,例如视频比特率、音频比特率、帧速率、更改视频分辨率等。请注意,我允许用户设置分数形式的视频帧速率; 用户可以设置视频帧速率为23.98。
我使用AVAssetWriter和AVAssetReader进行此操作。我使用AVAssetWriterInputPixelBufferAdaptor编写样本缓冲区。
除了视频帧速率之外,其他所有内容都正常工作。
我尝试过的:
- 设置AVVideoExpectedSourceFrameRateKey。这并没有帮助。(代码片段在这里)
- 设置AVAssetWriterInput.mediaTimeScale。同样,它更改了视频帧速率,但使视频变得缓慢,就像AVAssetWriter.movieTimeScale一样。视频在某些点上显示不同的帧,有时会卡住并重新开始。(代码片段在这里)
- 使用AVAssetReaderVideoCompositionOutput并设置AVMutableVideoComposition.frameDuration,就像SDAVAssetExportSession一样。具有讽刺意味的是,在SDAVAssetExportSession代码中,视频以我想要的正确帧速率导出,但在我的代码中却无法工作。代码片段在这里
我不确定为什么它在我的代码中不起作用。这种方法的问题是它总是从AVAssetReaderVideoCompositionOutput.copyNextSampleBuffer()返回nil。
- 手动更改帧的时间戳,如这里所建议的使用CMSampleTimingInfo。例如:
var sampleTimingInfo = CMSampleTimingInfo()
var sampleBufferToWrite: CMSampleBuffer?
CMSampleBufferGetSampleTimingInfo(vBuffer, at: 0, timingInfoOut: &sampleTimingInfo)
sampleTimingInfo.duration = CMTimeMake(value: 100, timescale: Int32(videoConfig.videoFrameRate * 100))
sampleTimingInfo.presentationTimeStamp = CMTimeAdd(previousPresentationTimeStamp, sampleTimingInfo.duration)
previousPresentationTimeStamp = sampleTimingInfo.presentationTimeStamp
let status = CMSampleBufferCreateCopyWithNewTiming(allocator: kCFAllocatorDefault, sampleBuffer: vBuffer,sampleTimingEntryCount: 1, sampleTimingArray: &sampleTimingInfo, sampleBufferOut: &sampleBufferToWrite)
采用这种方法可以准确设置帧率,但视频时长会增加(正如在问题答案的评论中提到的)。如果目标帧速率较低,则需要丢弃一些帧以降低帧速率(在大多数情况下我需要降低帧速率)。
如果我想要30fps,并且当前的帧速率是60fps,那么只需丢弃每秒钟的第二个帧并相应地设置SampleBuffer时间即可。
如果我采用这种方法(即设置23.98 fps),如何确定要丢弃哪一帧?如果目标帧速率更高,又该如何复制帧?请记住:帧速率可能是分数。