Я могу получить кадры из видео, используя AVAssetImageGenerator
, и я делаю это, используя generateCGImagesAsynchronously
. Всякий раз, когда результат успешен, я печатаю requestedTime
в секундах, а также actualTime
для этого изображения. В итоге, однако, два сгенерированных изображения одинаковы и имеют одинаковое значение actualTimes
, хотя мое значение шага и кадры для времен равномерно распределены.
Вот фрагмент моего напечатанного запрошенного и фактического временив секундах для каждого изображения:
Requested: 0.9666666666666667
Actual: 0.9666666666666667
Requested: 1.0
Actual: 1.0
Requested: 1.0333333333333334
Actual: 1.0333333333333334
Requested: 1.0666666666666667
Actual: 1.0666666666666667
Requested: 1.1
Actual: 1.1
Requested: 1.1333333333333333
Actual: 1.1
Requested: 1.1666666666666667
Actual: 1.135
Кажется, что все идет хорошо, пока в видео не будет сгенерирован кадр, соответствующий 1,1 секундам, что приводит к двум одинаковым изображениям и задержке actualTime
для остальной части процесса.
Я уже пытался настроить способ, которым я вычисляю кадры, которые должны быть сгенерированы, но это кажется правильным. Я использую количество кадров в секунду и умножаю это на длительность видео, чтобы выяснить, сколько кадров мне нужно иметь в общей сложности, и делю общую продолжительность на счетчик отсчетов, чтобы убедиться, что cgImages генерируются равномерно.
let videoDuration = asset.duration
print("video duration: \(videoDuration.seconds)")
let videoTrack = asset.tracks(withMediaType: AVMediaType.video)[0]
let fps = videoTrack.nominalFrameRate
var frameForTimes = [NSValue]()
let sampleCounts = Int(videoDuration.seconds * Double(fps))
let totalTimeLength = Int(videoDuration.seconds * Double(videoDuration.timescale))
let step = totalTimeLength / sampleCounts
for i in 0 ..< sampleCounts {
let cmTime = CMTimeMake(value: Int64(i * step), timescale: Int32(videoDuration.timescale))
frameForTimes.append(NSValue(time: cmTime))
}
и способ, которым я создаю изображения ( смотри это ):
imageGenerator.generateCGImagesAsynchronously(forTimes: timeValues) { (requestedTime, cgImage, actualTime, result, error) in
if let cgImage = cgImage {
print("Requested: \(requestedTime.seconds), Actual: \(actualTime.seconds)")
let image = UIImage(cgImage: cgImage)
// scale image if you want
frames.append(image)
}
}
Я также установил допуск равным нулю перед вызовом generateCGImages
:
imageGenerator.requestedTimeToleranceBefore = CMTime.zero
imageGenerator.requestedTimeToleranceAfter = CMTime.zero
Я ожидал, что фактическое время будет соответствовать запрошенному времени, и для каждого получаемого изображения будет разным. Просматривая изображения, всегда есть дубликат, независимо от того, какое видео тестируется, и обычно это происходит к середине.
Редактировать:
Я нашел это , это и это , в которых упоминается та же проблема, но я не добился успеха ни с одним из них.