How can I create CMSampleBuffers in Swift without a memory leak?

215 views Asked by At

I'm reading video data with an AVAssetReader and "looping" the content by reading it again and modifying the timestamps. The relevant code is:

  private func readFrame() -> CMSampleBuffer? {
    let buffer = output?.copyNextSampleBuffer()
    guard buffer != nil else {
      do {
        reader?.cancelReading()
        try loop()
      } catch let e {
        return nil
      }
      return readFrame()
    }
    
    // if we've looped, add previous loop times
    // MEMORY LEAK IS IN HERE
    if CMTimeCompare(offsetTime, .zero) > 0 {
      var newTiming = [CMSampleTimingInfo(
        duration: CMSampleBufferGetDuration(buffer!),
        presentationTimeStamp: CMTimeAdd(CMSampleBufferGetOutputPresentationTimeStamp(buffer!), offsetTime),
        decodeTimeStamp: CMTimeAdd(CMSampleBufferGetOutputDecodeTimeStamp(buffer!), offsetTime)
      )]
      
      CMSampleBufferCreateCopyWithNewTiming(allocator: kCFAllocatorDefault, sampleBuffer: buffer!, sampleTimingEntryCount: 1, sampleTimingArray: &newTiming, sampleBufferOut: &loopedBuffer)
      return loopedBuffer
    }
    
    return buffer
  }

  private func loop() throws {
    guard (reader?.status == .some(.completed)) else {
      throw FileError.cannotLoop(reader?.error)
    }
    offsetTime = CMTimeAdd(offsetTime, assetDuration)
    try createReader() // creates a new reader and calls reader.startReading()
  }

Once the video finishes its first loop (that is, once offsetTime is greater than zero), memory begins to blow up. Commenting out the code that creates a new buffer with updated timing fixes the memory leak (but that's not viable because I need the updated timing).

Presumably CMSampleBufferCreateCopyWithNewTiming is allocating new space for each buffer, and that buffer is never cleaned up. I've read about autoreleasepool as a potential option, but this buffer gets passed around a lot (it goes through a custom Publisher). Is there a way to remove the memory leak? I would be fine with allocating space for 1 buffer and just overwriting it again and again on each frame - is that possible?

0

There are 0 answers