यह कोड मेमोरी लीक और ऐप क्रैश की ओर जाता है:
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 () का उपयोग नहीं कर सकते। ऑब्जेक्टिव-सी ओनली रूल का लिंक होने का कारण मेरी समझ से परे है।
क्या स्विफ्ट में मैन्युअल रूप से CMSampleBuffer जारी करने का कोई तरीका है?
2 जवाब
यह वास्तव में एक समाधान नहीं है, क्योंकि ऐसा लगता है कि मेमोरी को मैन्युअल रूप से जारी करना असंभव है और एसेट रीडर के साथ संयोजन के दौरान लूप का उपयोग करने से मेमोरी जारी नहीं होती है जब असुरक्षित म्यूटेबल बाइट्स पढ़े जाते हैं।
समस्या को एक वैकल्पिक हल द्वारा हल किया गया था: ऑडियो फ़ाइल को थोड़ी देर के लूप में उजागर करने से पहले सीएएफ प्रारूप में परिवर्तित करना।
नकारात्मक पक्ष: यह एक गर्म सेकंड लेता है, ऑडियो फ़ाइल जितनी लंबी होती है - उतना ही अधिक समय लगता है।
उल्टा: यह केवल कम मात्रा में स्मृति का उपयोग करता था, जो पहली जगह में समस्या थी।
इससे प्रेरित: https://stackoverflow.com/users/2907715/carpsen90 उत्तर ऑडियो फ़ाइल से मीटर स्तर निकालें
मैंने हाल ही में एक ऑटोरेलीजपूल का उपयोग करके इसी तरह की समस्या को हल किया है
उस क्षेत्र को लपेटने का प्रयास करें जहां ऑटोरिलीजपूल में 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
के दायरे से बाहर निकल जाएगा, तो नमूनाबफ़र जारी किया जाएगा