#ios #objective-c #tensorflow
#iOS #objective-c #tensorflow
Вопрос:
Я снимаю видео и выполняю некоторые анализы в captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer
delegate. но через короткое время этот метод не вызывается. затем вызывается captureOutput:(AVCaptureOutput *)output didDropSampleBuffer
делегат.
Когда я ничего не делаю в didOutputSampleBuffer, все в порядке.
Я запускаю модель тензорного потока в этом делегате. И это вызывает проблему.
Проблема:
Проблема в том, что при didDropSampleBuffer
вызове didOutputSampleBuffer больше не вызывается.
Мое решение:
Моим решением была остановка и запуск AVCaptureSession. но это привело к дополнительному использованию памяти! Что в конечном итоге привело к сбою моего приложения.
- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
// ****** do heavy work in this delegate *********
graph = [TensorflowGraph new];
predictions = [graph runModelOnPixelBuffer:pixelBuffer orientation: UIDeviceOrientationPortrait CardRect: _vwRect];
}
- (void)captureOutput:(AVCaptureOutput *)output didDropSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
CFTypeRef droppedFrameReason = CMGetAttachment(sampleBuffer, kCMSampleBufferAttachmentKey_DroppedFrameReason, NULL);
NSLog(@"dropped frame, reason: %@", droppedFrameReason);
}
—-> отброшенный кадр, причина: OutOfBuffers
Согласно [https://developer.apple.com/library/archive/technotes/tn2445/_index.html ]:
Это условие обычно вызывается тем, что клиент слишком долго удерживает буферы, и его можно устранить, вернув буферы поставщику.
Как я могу вернуть буфер поставщику?
Отредактировано
После выполнения 11 раз этой CGImageRef cgImage = [context createCGImage:resized fromRect:resized.extent];
строки вызывается didDropSampleBuffer
. комментирование CFRelease(pixelBuffer)
не имеет никакого значения в результате. Означает ли это, что PixelBuffer не выпущен?
CFRetain(pixelBuffer);
CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
CIImage* ciImage = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer];
ciImage = [ciImage imageByCroppingToRect:cropRect];
CGAffineTransform transform = CGAffineTransformIdentity;
CGFloat angle = 0.0;
transform = CGAffineTransformRotate(transform, angle);
CIImage* resized = [ciImage imageByApplyingTransform:transform];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef cgImage = [context createCGImage:resized fromRect:resized.extent]; // *********************************
UIImage* _res = [[UIImage alloc] initWithCGImage:cgImage];
CFRelease(pixelBuffer);
Комментарии:
1. Это может показаться излишним вопросом, но что вы ожидаете, что произойдет? С моей точки зрения, это то, что произойдет, если метод didOutputSampleBuffer не сможет поддерживать частоту кадров камеры.
2. Скорее всего, вы
CFRetain
включаетеsampleBuffer
что-то, что вы делаете, но не выпускаете это. Когда в конвейере захвата заканчиваются буферы, потому что все они сохранены, он прекращает вывод. Это утечка памяти. Но вам, вероятно, потребуется показать больше кода, чтобы определить проблему и убедиться, что ваши существующие фрагменты кода точны.3. @allenh Спасибо. Я обновил вопрос.
4. Вы можете проверить количество сохранений вашего пиксельного буфера с помощью
CFGetRetainCount
. При возврате вашего делегата должно быть 1.[CIImage initWithCVPixelBuffer:
на самом деле сохраняется пиксельный буфер, поэтому, если вы храните изображение где угодно, это может вызвать проблемы. Кроме того, я понятия не имею, что[TensorflowGraph runModelOnPixelBuffer:orientation:CardRect:]
происходит с пиксельным буфером. Вы также должны вызыватьCVPixelBufferUnlockBaseAddress
передCFRelease
.5. @allenh Спасибо. Это был действительно хороший комментарий. После [ciimage initWithCvPixelBuffer] как я должен освободить пиксельный буфер? Должен ли я что-то сделать, или это будет выпущено автоматически?