AVVideoExpectedSourceFrameRateKey
原打算使用 AVAssetWriterInput 的 outputSettings 參數(shù)中的 AVVideoExpectedSourceFrameRateKey 設(shè)置輸出幀率,但設(shè)置后不起作用,查看文檔后發(fā)現(xiàn) ’This is not used to control the frame rate‘仲器。遂放棄該參數(shù)
原生參數(shù)不起作用的前提下,我們只能考慮其他的方式來達到目的阿迈。首先鼎天,我們需要理解幀率的概念,fps- frame pre sencond(每秒的幀數(shù))蔚叨,那么降低幀率也就是降低每秒包含的幀數(shù)载绿,所以我們就可以通過丟幀的方式來降低幀率粥诫。
丟幀
降低幀率其實也就是減少視頻中每秒的幀數(shù),那么丟棄掉冗余的視頻幀也就達到了我們的目的
iOS 轉(zhuǎn)碼流程
目前我們使用的 AVAsset 的轉(zhuǎn)碼流程:先將輸入視頻解碼得到一幀幀的視頻幀卢鹦,然后將視頻幀送入編碼器進行編碼得到輸出視頻臀脏。
那么在得到視頻幀之后我們就可以選擇是否要將該幀送入編碼器。
幀率為 frame count / second, 那么幀間隔就是 1/fps冀自。通過判斷兩幀之間的時間間隔即判斷是否丟棄該幀:
/**
* 判斷是否需要丟棄當前幀
*/
- (CMSampleBufferRef) dropFrame:(CMSampleBufferRef)sample {
CMSampleBufferRef sampleBufferToWrite = NULL;
if (sample) {
if (_videoOutFrameIntervals == 0) {
// 不需要更改幀率的情況下揉稚,直接拷貝當前幀
CMSampleBufferCreateCopy(nil, sample, &sampleBufferToWrite);
} else {
// 是否跳過當前幀
BOOL drop = true;
// 獲取當前幀
CMTime presentationTime = CMSampleBufferGetPresentationTimeStamp(sample);
Float64 subPresentationTime = CMTimeGetSeconds(CMTimeSubtract(presentationTime, _previousPstTime));
if (subPresentationTime == 0 || subPresentationTime >= _videoOutFrameIntervals) {
// 首幀不跳過; 非首幀的情況下,判斷與前一幀的間距是否滿足輸出幀率(幀間距 >= 1/輸出幀率)
drop = false;
}
if (!drop) {
// 不跳過當前幀的情況下
CMSampleTimingInfo timeInfo = {0};
CMSampleBufferGetSampleTimingInfo(sample, 0, &timeInfo);
CMSampleBufferCreateCopyWithNewTiming(nil, sample, 1, &timeInfo, &sampleBufferToWrite);
// 更新前一幀的 presentation 時間
_previousPstTime = presentationTime;
}
}
}
return sampleBufferToWrite;
}