我正在使用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
}
答案 0 :(得分:0)
从Apple支持部门回复:
如果要使用AVAssetWriter实际更改电影的帧速率,则必须在写入每个视频帧时正确设置它们的时间戳。
一种方法是使用AVAssetWriterInputPixelBufferAdaptor对象。例如,您使用AVAssetWriterInputPixelBufferAdaptor将打包为CVPixelBuffer对象的视频样本附加到单个AVAssetWriterInput对象。
初始化代码如下:
Id | Name |
------------------
101 | Health |
102 | Education |
103 | Sport |
104 | Family |
105 | Culture |
...
[dictionary setObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(NSString*) kCVPixelBufferPixelFormatTypeKey];
然后,要为新电影指定某个回放帧速率(例如15 fps),则应将时间戳记(表示为CMTime结构)指定为相隔1/15秒。这是一个代码段:
AVAssetWriterInputPixelBufferAdaptor *avAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:assetWriterInput sourcePixelBufferAttributes:dictionary];
另一种替代方法是使用CMSampleBufferCreateCopyWithNewTiming对缓冲区重新计时,然后将其传递给AVAssetWriter。这是一个粗略的轮廓:
CMTime frameTime = CMTimeMake(1, 15);
result = [avAdaptor appendPixelBuffer:buffer withPresentationTime:frameTime];
//////////
我尝试使用“ CMSampleBufferCreateCopyWithNewTiming”。 FPS设置正确。但是得到了慢动作输出。以下是我的代码。
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 */
}