Проблема с настройкой частоты кадров видео с помощью AVAssetWriter / AVAssetReader - PullRequest
18 голосов
/ 15 июня 2019

Положение:

Я пытаюсь экспортировать видео с некоторыми параметрами, такими как скорость передачи видео, скорость передачи звука, частота кадров, изменение разрешения видео и т. Д. Обратите внимание, что я позволяю пользователю устанавливать частоту кадров видео; Как пользователь может установить частоту кадров видео скажем, 23,98.

Я использую AVAssetWriter и AVAssetReader для этой операции. Я использую AVAssetWriterInputPixelBufferAdaptor для записи выборочных буферов.

Все остальное работает просто отлично, кроме: частота кадров видео .

Что я пробовал:

  1. Установка AVAssetWriter.movieTimeScale в соответствии с рекомендациями здесь . Что меняет частоту кадров видео, но также делает видео вялым. ( Суть здесь )

  1. Настройка AVVideoExpectedSourceFrameRateKey . Который не помогает. ( Суть здесь )

  1. Настройка AVAssetWriterInput.mediaTimeScale . Опять же, он изменяет частоту кадров видео, но замедляет видео, как AVAssetWriter.movieTimeScale . Видео показывает другой кадр в какой-то момент, а иногда оно снова залипает и возобновляется. ( Суть здесь )

  1. Использование AVAssetReaderVideoCompositionOutput и настройка AVMutableVideoComposition.frameDuration ; как SDAVAssetExportSession . По иронии судьбы с кодом SDAVAssetExportSession видео экспортируется только с нужной частотой кадров, что мне нужно, но оно просто не работает в моем коде. Суть здесь

Я не уверен, почему это не будет работать с моим кодом. Проблема этого подхода в том, что он всегда возвращает nil из AVAssetReaderVideoCompositionOutput.copyNextSampleBuffer () .


  1. Изменение временной метки кадров вручную с помощью CMSampleTimingInfo , как предлагается здесь Что-то вроде:
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)

При таком подходе я правильно устанавливаю частоту кадров, но это увеличивает продолжительность видео (как упоминалось в комментарии к ответу на этот вопрос). Я думаю, что в какой-то момент мне, возможно, придется отказаться от некоторых кадров (если целевая частота кадров ниже; в большинстве случаев мне нужно снизить частоту кадров).

Если я знаю, что если я хочу 30 кадров в секунду, а моя текущая частота кадров составляет 60 кадров в секунду, то просто отбрасывать каждый второй кадр и соответственно устанавливать время SampleBuffer.

Если я пойду с этим подходом (т. Е. Установлю 23,98 кадров в секунду), как мне решить, какой кадр отбрасывать, и если целевая частота кадров выше, какой кадр дублировать? Напоминание: частота кадров может быть в долях.


...