Ответ от поддержки Apple:
Если вы действительно хотите изменить частоту кадров фильма с помощью AVAssetWriter, то вам придется правильно устанавливать временные метки для каждого отдельного видеокадра при их записи.
Один из способов сделать это - с помощью объекта AVAssetWriterInputPixelBufferAdaptor.Например, вы используете AVAssetWriterInputPixelBufferAdaptor, чтобы добавить образцы видео, упакованные как объекты CVPixelBuffer, в один объект AVAssetWriterInput.
Код инициализации выглядит примерно так:
[dictionary setObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(NSString*) kCVPixelBufferPixelFormatTypeKey];
...
AVAssetWriterInputPixelBufferAdaptor *avAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:assetWriterInput sourcePixelBufferAttributes:dictionary];
Затем, чтобы указать определенную частоту кадров воспроизведения (например, 15 к / с)) для нового фильма метки времени (представленные в виде структур 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")
}
}