[英]How to control video frame rate with AVAssetReader and AVAssetWriter?
[英]Problem setting video frame rate using AVAssetWriter/AVAssetReader
我正在嘗試使用一些參數導出視頻,例如視頻比特率、音頻比特率、幀率、更改視頻分辨率等。請注意,我讓用戶以分數形式設置視頻幀率; 比如用戶可以設置視頻幀率,比如 23.98。
我使用AVAssetWriter和AVAssetReader進行此操作。 我使用AVAssetWriterInputPixelBufferAdaptor來編寫示例緩沖區。
除了視頻幀率,其他一切都很好。
我不確定為什么它不適用於我的代碼。 這種方法的問題是它總是從AVAssetReaderVideoCompositionOutput.copyNextSampleBuffer()返回 nil。
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 時間。
如果我使用這種方法 go(即設置 23.98 fps),我如何決定丟棄哪個幀,如果目標幀速率更高,復制哪個幀? 提醒:幀率可能是分數。
這是選擇框架的想法。 假設源視頻的fps是F,目標fps是TF。 比率 = TF/F
每次初始化一個等於-rate的變量n並添加rate,當n的整數部分發生變化時,選擇幀。
e.g. rate = 0.3
n: -0.3 0 0.3 0.6 0.9 1.2 1.5 1.8 2.1
^ ^ ^
frame index: 0 1 2 3 4 5 6 7
select 0 4 7
float rate = 0.39999f; // TF/F
float n = -rate; // to make sure first frame will be selected
for (int i = 0; i < 100; ++i, n += rate) { // i stands for frame index, take a video with 100 frames as an example
int m = floor(n);
int tmp = n+rate;
// if rate > 1.0 repeat i
// if rate < 1.0 some of the frames will be dropped
for (int j = 0; m+j < tmp; ++j) {
// Use this frame
printf("%d ", i);
}
}
NSMutableDictionary *writerInputParams = [[NSMutableDictionary alloc] init];
[writerInputParams setObject:AVVideoCodecTypeH264 forKey:AVVideoCodecKey];
[writerInputParams setObject:[NSNumber numberWithInt:width] forKey:AVVideoWidthKey];
[writerInputParams setObject:[NSNumber numberWithInt:height] forKey:AVVideoHeightKey];
[writerInputParams setObject:AVVideoScalingModeResizeAspectFill forKey:AVVideoScalingModeKey];
NSMutableDictionary * compressionProperties = [[NSMutableDictionary alloc] init];
[compressionProperties setObject:[NSNumber numberWithInt: 20] forKey:AVVideoExpectedSourceFrameRateKey];
[compressionProperties setObject:[NSNumber numberWithInt: 20] forKey:AVVideoAverageNonDroppableFrameRateKey];
[compressionProperties setObject:[NSNumber numberWithInt: 0.0] forKey:AVVideoMaxKeyFrameIntervalDurationKey];
[compressionProperties setObject:[NSNumber numberWithInt: 1] forKey:AVVideoMaxKeyFrameIntervalKey];
[compressionProperties setObject:[NSNumber numberWithBool:YES] forKey:AVVideoAllowFrameReorderingKey];
[compressionProperties setObject:AVVideoProfileLevelH264BaselineAutoLevel forKey:AVVideoProfileLevelKey];
[writerInputParams setObject:compressionProperties forKey:AVVideoCompressionPropertiesKey];
self.assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:writerInputParams];
self.assetWriterInput.expectsMediaDataInRealTime = YES;
已經驗證過SCNView每秒刷新60幀,但是使用AVAssetWriter只想保存每秒20幀,怎么辦?
上面的 AVVideoExpectedSourceFrameRateKey 和 AVVideoAverageNonDroppableFrameRateKey 都不會影響 fps,配置 fps 將不起作用,.. // 設置它以確保制作功能電影。 即使錄音中途中斷。 在這種情況下,應該只損失最后一秒。 self,videoWriter;movieFragmentInterval = CMTimeMakeWithSeconds(1.0.1000); self.videoWriter.shouldOptimizeForNetworkUse = YES; self.videoWriter.movieTimeScale = 20; 以上配置也不會影響fps。
self.assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:writerInputParams];
self.assetWriterInput.expectsMediaDataInRealTime = YES;
/// this config will change video frame presenttime to fit fps, but it will be change video duration.
// self.assetWriterInput.mediaTimeScale = 20; self.assetWriterInput.mediaTimeScale 會影響fps,但是會導致視頻時長被拉長3倍,因為BOOL isSUc = [self.writerAdaptor appendPixelBuffer:cvBuffer withPresentationTime:presentationTime]; 填充幀的時間會重新修改,所以配置了self.assetWriterInput.mediaTimeScale值,與預期嚴重不符,視頻時長不應拉長。
所以如果你想控制AVAssetWriter最后保存的視頻的fps,你必須通過控制,並且必須保證每秒調用20次。
CMTime presentationTime = CMTimeMake(_writeCount * (1.0/20.0) * 1000, 1000);
BOOL isSUc = [self.writerAdaptor appendPixelBuffer:cvBuffer withPresentationTime:presentationTime];
_writeCount += 1;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.