Как вручную выпустить CMSampleBuffer
Этот код приводит к утечке памяти и падению приложения:
var outputSamples = [Float]()
assetReader.startReading()
while assetReader.status == .reading {
let trackOutput = assetReader.outputs.first!
if let sampleBuffer = trackOutput.copyNextSampleBuffer(),
let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
let blockBufferLength = CMBlockBufferGetDataLength(blockBuffer)
let sampleLength = CMSampleBufferGetNumSamples(sampleBuffer) * channelCount(from: assetReader)
var data = Data(capacity: blockBufferLength)
data.withUnsafeMutableBytes { (blockSamples: UnsafeMutablePointer<Int16>) in
CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: blockBufferLength, destination: blockSamples)
CMSampleBufferInvalidate(sampleBuffer)
let processedSamples = process(blockSamples,
ofLength: sampleLength,
from: assetReader,
downsampledTo: targetSampleCount)
outputSamples += processedSamples
}
}
}
var paddedSamples = [Float](repeating: silenceDbThreshold, count: targetSampleCount)
paddedSamples.replaceSubrange(0..<min(targetSampleCount, outputSamples.count), with: outputSamples)
Это связано с copyNextSampleBuffer() и правилом создания.
В свою очередь, мы не можем использовать CFRelease() в Swift. Причина, по которой ссылка на правило Objective-C заключается в том, что я не понимаю.
Есть ли способ освободить CMSampleBuffer вручную в Swift?
0 ответов
Недавно я решил аналогичную проблему с помощью автозапуска
Попробуйте обернуть область, где sampleBuffer
используется в автовыпускном пуле. Что-то вроде этого:
var outputSamples = [Float]()
assetReader.startReading()
while assetReader.status == .reading {
let trackOutput = assetReader.outputs.first!
autoreleasepool {
if let sampleBuffer = trackOutput.copyNextSampleBuffer(),
let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
let blockBufferLength = CMBlockBufferGetDataLength(blockBuffer)
let sampleLength = CMSampleBufferGetNumSamples(sampleBuffer) * channelCount(from: assetReader)
var data = Data(capacity: blockBufferLength)
data.withUnsafeMutableBytes { (blockSamples: UnsafeMutablePointer<Int16>) in
CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: blockBufferLength, destination: blockSamples)
CMSampleBufferInvalidate(sampleBuffer)
let processedSamples = process(blockSamples,
ofLength: sampleLength,
from: assetReader,
downsampledTo: targetSampleCount)
outputSamples += processedSamples
}
}
}
}
var paddedSamples = [Float](repeating: silenceDbThreshold, count: targetSampleCount)
paddedSamples.replaceSubrange(0..<min(targetSampleCount, outputSamples.count), with: outputSamples)
Если я правильно понимаю, как только он выходит за рамки autoreleasepool
, sampleBuffer будет выпущен
Это не совсем решение, потому что кажется, что освобождение памяти вручную невозможно, и использование цикла while в сочетании с assetReader приводит к тому, что память не освобождается при чтении небезопасных изменяемых байтов.
Проблема была решена с помощью обходного пути: преобразование аудиофайла в формат CAF перед тем, как подвергнуть его циклу while.
Недостаток: требуется горячая секунда, чем длиннее аудиофайл - тем больше времени.
Перевернутый: он использовал только незначительное количество памяти, что было проблемой в первую очередь.
Вдохновлен: Carpsen90 ответ в Извлечь уровни счетчика из аудиофайла