Мое приложение страдает от OutOfBuffers как причина пропуска кадров

После интенсивного использования моего приложения, которое работает AVCaptureSession экземпляр Это страдание

DroppedFrameReason(P) = OutOfBuffers

Это детали из объекта SampleBuffer в - (void)captureOutput:(AVCaptureOutput *)captureOutput didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection

CMSampleBuffer 0x10de70770 retainCount: 1 allocator: 0x1b45e2bb8
    invalid = NO
    dataReady = YES
    makeDataReadyCallback = 0x0
    makeDataReadyRefcon = 0x0
    buffer-level attachments:
        DroppedFrameReason(P) = OutOfBuffers
    formatDescription = <CMVideoFormatDescription 0x174441e90 [0x1b45e2bb8]> {
    mediaType:'vide' 
    mediaSubType:'BGRA' 
    mediaSpecific: {
        codecType: 'BGRA'       dimensions: 480 x 360 
    } 
    extensions: {<CFBasicHash 0x174a61100 [0x1b45e2bb8]>{type = immutable dict, count = 5,
entries =>
    0 : <CFString 0x1ae9fa7c8 [0x1b45e2bb8]>{contents = "CVImageBufferYCbCrMatrix"} = <CFString 0x1ae9fa808 [0x1b45e2bb8]>{contents = "ITU_R_601_4"}
    1 : <CFString 0x1ae9fa928 [0x1b45e2bb8]>{contents = "CVImageBufferTransferFunction"} = <CFString 0x1ae9fa7e8 [0x1b45e2bb8]>{contents = "ITU_R_709_2"}
    2 : <CFString 0x1aea2c3e0 [0x1b45e2bb8]>{contents = "CVBytesPerRow"} = <CFNumber 0xb000000000007802 [0x1b45e2bb8]>{value = +1920, type = kCFNumberSInt32Type}
    3 : <CFString 0x1aea2c460 [0x1b45e2bb8]>{contents = "Version"} = <CFNumber 0xb000000000000022 [0x1b45e2bb8]>{value = +2, type = kCFNumberSInt32Type}
    5 : <CFString 0x1ae9fa8a8 [0x1b45e2bb8]>{contents = "CVImageBufferColorPrimaries"} = <CFString 0x1ae9fa7e8 [0x1b45e2bb8]>{contents = "ITU_R_709_2"}
}
}
}
    sbufToTrackReadiness = 0x0
    numSamples = 0
    sampleTimingArray[1] = {
        {PTS = {3825121221333/1000000000 = 3825.121}, DTS = {INVALID}, duration = {INVALID}},
    }
    dataBuffer = 0x0

Я покопался и нашел это

В модуле, обеспечивающем выборочные буферы, закончились исходные буферы. Это условие обычно вызывается тем, что клиент слишком долго удерживает буферы и может быть смягчено путем возврата буферов поставщику.

Что они подразумевают под: возвратом буферов провайдеру?? Есть ли какое-то решение, которое я могу сделать?

3 ответа

Недавно наткнулся на это и нашел решение после прочтения этого сообщения. Думаю, этим стоит поделиться.

Документация Apple по ссылке, представленной в OP, довольно неконкретна в том, что они подразумевают под «удержанием буферов» и «провайдером», но вот что они означают.

Поставщик - это объект VideoOutput, который отправляет вам CMSampleBuffer через свой метод AVCaptureVideoDataOutputSampleBufferDelegate:

      func captureOutput(
    _ output: AVCaptureOutput,
    didOutput sampleBuffer: CMSampleBuffer,
    from connection: AVCaptureConnection
) {
    //do stuff with frames here
}

Однако в документации Apple говорится, что существует ограниченное количество буферов сэмплов, которые он может хранить в памяти одновременно. Это означает, что если вы удерживаете буфер выборки дольше, чем требуется для поступления следующего кадра, вы столкнетесь с узким местом, где будет заполнена память SampleBuffer. Он должен дождаться, пока один из старых отправленных им файлов будет удален из стека и освобожден в любом процессе, с которым он выполняется.

Так, например, если вы снимаете кадры со скоростью 60 кадров в секунду и удерживаете кадры в процессе, который занимает больше 17 мс, вы получите уменьшение кадра.

Вы должны либо найти способ более эффективно выполнять свои задачи с фреймами, либо, как мы (при использовании CoreML), найти способ заставить ваш процесс работать с меньшим количеством фреймов. Это означает, что вы отправляете только кадры с меньшей скоростью, чем они поступают. Мы смогли заставить наши модели работать с частотой кадров примерно 10 кадров в секунду, поэтому мы отправляли только один каждые 6 кадров на заднюю камеру.

Честно говоря, Apple говорит, что это обычно является виновником любых выпадений кадров в той публикации документации, но они не очень хороши в передаче того, что именно это означает.

Я заметил, что в Swift 5 и Xcode 12.4 и iOS 14.3:

Я использовал CVMetalTextureCacheCreateTextureFromImage для создания текстур из CVPixelBuffer сеанса захвата, и это вызвало бы ошибку outofbuffers после 10-кратного чтения. Кажется, вопрос в том, существуют ли текстуры постоянно или слишком долго, а затем пул буферов переполняется.

Любопытно, что если я установлю для вновь созданного metalTexture значение nil сразу после его чтения, ошибка исчезнет, ​​предположительно из-за того, что память освободится раньше. Таким образом, можно скопировать текстуру, а затем установить исходную на ноль, чтобы избежать этой проблемы. Все еще изучаю это ...

здесь вы на самом деле упомянули проблему и ответ

"Это условие обычно вызывается тем, что клиент слишком долго удерживает буферы и может быть смягчено путем возврата буферов поставщику".

Другие вопросы по тегам