[英]AVAssetWriter AVVideoExpectedSourceFrameRateKey (frame rate) ignored
[英]AVAssetWriter - Set Custom frame rate
我正在使用AVAssetWriter使用委托從ARSession寫入視頻幀。
func session(_ session: ARSession, didUpdate frame: ARFrame)
參見下面用於寫入圖像的代碼。
如何根據需要設置自定義幀頻,例如24、30或60等。
在輸出設置中,AVVideoExpectedSourceFrameRateKey的值是30。但是,我們給它指定的值是什么,用VLC播放器檢查->媒體信息->編解碼器詳細信息時,始終將“幀頻”設為60。
我應該進行哪些更改以設置所需的幀速率? 提前致謝。
func writeImage(_ image: CVPixelBuffer, thisTimestamp: TimeInterval) {
guard let videoDirector = videoWriter else { return }
serialQueue.async(execute: {
let scale = CMTimeScale(NSEC_PER_SEC)
if (!self.seenTimestamps.contains(thisTimestamp)) {
self.seenTimestamps.append(thisTimestamp)
let pts = CMTime(value: CMTimeValue((thisTimestamp) * Double(scale)),
timescale: scale)
var timingInfo = CMSampleTimingInfo(duration: kCMTimeInvalid,
presentationTimeStamp: pts,
decodeTimeStamp: kCMTimeInvalid)
var vidInfo:CMVideoFormatDescription! = nil
CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, image, &vidInfo)
var sampleBuffer:CMSampleBuffer! = nil
CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault, image, true, nil, nil, vidInfo, &timingInfo, &sampleBuffer)
let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
if self.videoWriterInput == nil {
let width = CVPixelBufferGetWidth(imageBuffer)
let height = CVPixelBufferGetHeight(imageBuffer)
let numPixels: Double = Double(width * height);
let bitsPerPixel = 11.4;
let bitsPerSecond = Int(numPixels * bitsPerPixel)
// add video input
let outputSettings: [String: Any] = [
AVVideoCodecKey : AVVideoCodecType.h264,
AVVideoWidthKey : width,
AVVideoHeightKey : height,
AVVideoCompressionPropertiesKey : [
AVVideoExpectedSourceFrameRateKey: 30,
AVVideoAverageBitRateKey : bitsPerSecond,
AVVideoMaxKeyFrameIntervalKey : 1
]
]
self.videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: outputSettings)
self.videoWriterInput?.expectsMediaDataInRealTime = true
guard let input = self.videoWriterInput else { return }
if videoDirector.canAdd(input) {
videoDirector.add(input)
}
videoDirector.startWriting()
}
let writable = self.canWrite()
if writable, self.sessionAtSourceTime == nil {
let timeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
self.sessionAtSourceTime = timeStamp
videoDirector.startSession(atSourceTime: timeStamp)
}
if self.videoWriterInput?.isReadyForMoreMediaData == true {
let appendResult = self.videoWriterInput?.append(sampleBuffer)
if appendResult == false {
printDebug("writer status: \(videoDirector.status.rawValue)")
printDebug("writer error: \(videoDirector.error.debugDescription)")
}
}
}
})
}
func canWrite() -> Bool {
return isRecording && videoWriter?.status == .writing
}
Apple支持部門的回復:
如果要使用AVAssetWriter實際更改電影的幀速率,則必須在寫入每個視頻幀時正確設置其時間戳。
一種方法是使用AVAssetWriterInputPixelBufferAdaptor對象。 例如,您使用AVAssetWriterInputPixelBufferAdaptor將打包為CVPixelBuffer對象的視頻樣本附加到單個AVAssetWriterInput對象。
初始化代碼如下所示:
[dictionary setObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(NSString*) kCVPixelBufferPixelFormatTypeKey];
...
AVAssetWriterInputPixelBufferAdaptor *avAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:assetWriterInput sourcePixelBufferAttributes:dictionary];
然后,要為新電影指定某個回放幀速率(例如15 fps),則應將時間戳(表示為CMTime結構)指定為間隔為1/15秒。 這是一個代碼片段:
CMTime frameTime = CMTimeMake(1, 15);
result = [avAdaptor appendPixelBuffer:buffer withPresentationTime:frameTime];
另一種選擇是使用CMSampleBufferCreateCopyWithNewTiming對緩沖區重新計時,然后將其傳遞給AVAssetWriter。 這是一個粗略的輪廓:
CMSampleTimingInfo sampleTimingInfo = {0};
CMSampleBufferRef newBuffer = NULL;
CMSampleBufferGetSampleTimingInfo(existingSampleBuffer, 0, &sampleTimingInfo);
sampleTimingInfo.duration = CMTimeMake(1, 30) // Specify new frame rate.
sampleTimingInfo.presentationTimeStamp = CMTimeAdd(previousPresentationTimeStamp, sampleTimingInfo.duration);
previousPresentationTimeStamp = sampleTimingInfo.presentationTimeStamp;
OSStatus status = CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault, existingSampleBuffer, 1, &sampleTimingInfo, &newBuffer);
if (status == noErr) {
/* Write your newBuffer here */
}
//////////
我嘗試使用“ CMSampleBufferCreateCopyWithNewTiming”。 FPS設置正確。 但是得到了慢動作輸出。 以下是我的代碼。
autoreleasepool {
//set FPS
var sampleTimingInfo: CMSampleTimingInfo = CMSampleTimingInfo(duration: kCMTimeInvalid, presentationTimeStamp: CMTime(), decodeTimeStamp: kCMTimeInvalid)
var newBuffer: CMSampleBuffer! = nil
CMSampleBufferGetSampleTimingInfo(sampleBufferMain, 0, &sampleTimingInfo);
sampleTimingInfo.duration = CMTimeMake(1, 15) // Specify new frame rate.
sampleTimingInfo.presentationTimeStamp = CMTimeAdd(self.previousPresentationTimeStamp, sampleTimingInfo.duration)
self.previousPresentationTimeStamp = sampleTimingInfo.presentationTimeStamp
let status: OSStatus = CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault, sampleBufferMain, 1, &sampleTimingInfo, &newBuffer);
if status == noErr {
let appendResult = self.videoWriterInput?.append(newBuffer)
if appendResult == false {
printError("writer status: \(String(describing: self.videoWriter?.status.rawValue))")
printError("writer error: \(self.videoWriter?.error.debugDescription ?? "")")
}
} else {
print("write error")
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.