Дождитесь выполнения задач рендеринга CIContext неблокирующим образом

Я ищу способ дождаться завершения рендеринга CIContext без блокировки. Для простоты, вот пример, в котором я визуализирую один CVPixelBufferRef другому CVPixelBufferRef, используя CIImage и CIContext. Очевидно, мой настоящий конвейер мог бы сделать больше, но это простейший случай.

CIContext *context = [CIContext new];
// sourceBuffer provided from something like a camera
CIImage *image = [CIImage imageWithCVPixelBuffer:sourceBuffer];

CVPixelBufferRef output;
// pool was allocated elsewhere
CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, bufferPool, &output)
[context render:image toCVPixelBuffer:output];

Код в том виде, в котором он есть, блокируется до завершения рендеринга, потому что [CIContext render:toCVPixelBuffer:] блокирует.

Вы можете запустить задачу рендеринга неблокирующим способом, используя [CIContext startTaskToRender:toDestination:error:], вот так

CIContext *context = [CIContext new];
// sourceBuffer provided from something like a camera
CIImage *image = [CIImage imageWithCVPixelBuffer:sourceBuffer];

CVPixelBufferRef output;
// pool was allocated elsewhere
CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, bufferPool, &output)

CIRenderDestination *destination = [[CIRenderDestination alloc] initWithPixelBuffer:output];
[context startTaskToRender:image toDestination:destination error:nil];

Это на полпути, вызов не блокируется, но я понятия не имею, когда задача рендеринга завершена. Этот API возвращает CIRenderTask, но в нем есть только один метод экземпляра, который конечно же waitUntilCompletedAndReturnError, который будет блокироваться, пока задача не будет завершена.

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

Итак, мой вопрос: можно ли получить результаты CIContext рендеринга без блокировки?


person bclymer    schedule 24.02.2021    source источник


Ответы (1)


Первый render вызов на самом деле не должен быть блокирующим. Как упоминалось в ​​этом ответе,

Core Image откладывает рендеринг до тех пор, пока клиент не запросит доступ к буферу кадра, то есть CVPixelBufferLockBaseAddress.

Однако вы также можете использовать CIRenderDestiantion API и сделать его асинхронным самостоятельно следующим образом:

CIRenderTask *task = [context startTaskToRender:image toDestination:destination error:nil];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    [task waitUntilCompletedAndReturnError: NULL];
    // do async stuff here, e.g. call a callback block
});
person Frank Schlegel    schedule 24.02.2021
comment
Это очень интересно. При профилировании моего приложения на линию рендеринга приходится почти 80% моего общего использования ЦП. Похоже, что если бы он просто отложился до следующего раза, когда мне нужно было заблокировать буфер кадра, он бы немедленно вернулся, а нагрузка на ЦП была бы на следующем этапе конвейера (видеокодер). - person bclymer; 24.02.2021