此代码会导致内存泄漏和应用崩溃:
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()和The Create Rule造成的。
反过来,我们不能在Swift中使用CFRelease()。我之所以无法理解为何仅与Objective-C规则相关联。
是否可以在Swift中手动释放CMSampleBuffer?
答案 0 :(得分:3)
我最近通过使用自动释放池解决了类似的问题
尝试包装自动释放池中使用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将被释放
答案 1 :(得分:0)
这并不是真正的解决方案,因为似乎无法手动释放内存,并且将while循环与assetReader结合使用会导致在读取不安全的可变字节时不会释放内存。
此问题已通过一种解决方法解决:将音频文件转换为CAF格式,然后再将其暴露给while循环。
缺点:需要花费很长时间,音频文件越长-花费的时间越多。
上行:它只使用了很小的内存,这首先就是问题。
灵感来自:https://stackoverflow.com/users/2907715/carpsen90的Extract meter levels from audio file答案