CIContext.render(_ image: CIImage, в буфер: CVPixelBuffer) слишком много использования процессорного времениIOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Anonymous
 CIContext.render(_ image: CIImage, в буфер: CVPixelBuffer) слишком много использования процессорного времени

Сообщение Anonymous »

Итак, я пытаюсь записать видео с помощью AVAssetWriter, обработать каждый кадр камеры (например, добавить водяной знак или наложение текста), создав CIImage из буфера камеры (

Код: Выделить всё

 CVImageBuffer
), добавить несколько фильтров в CIImage (что очень быстро по производительности), а затем мне нужно получить новый CVPixelBuffer из CIImage, и это становится проблемой с высокими разрешениями например, 4K на базовом iPhone 11, потому что cIContext.render(compositedImage, to: PixelBuffer) занимает около 30 мс процессорного времени, поэтому приложение не сможет записывать 4K со скоростью 60 кадров в секунду.
Есть ли какие-нибудь решения по его улучшению?
Или единственный способ повысить производительность — использовать OpenGL/Metal? Но не уверен, насколько лучше, если нам все равно придется каким-то образом передавать буфер пикселей в AVAssetWriter. Есть ли какой-нибудь простой пример использования Metal и AVAssetWriter, аналогичный следующему примеру кода?

Код: Выделить всё

private let cIContext: CIContext = {
if let mtlDevice = MTLCreateSystemDefaultDevice() {
return CIContext(mtlDevice: mtlDevice) // makes no difference in perfomance for CIContext.render()
} else {
return CIContext()
}
}()

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let assetWriter = assetWriter, let videoWriterInput = videoWriterInput else { return }

if isRecording == false || assetWriter.status != .writing { return }

if CMSampleBufferDataIsReady(sampleBuffer) == false {
return
}

if output == videoOutput, videoWriterInput.isReadyForMoreMediaData {
let presentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)

if hasWritingSessionStarted == false {
assetWriter.startSession(atSourceTime: presentationTime)

hasWritingSessionStarted = true

guard let pixelBufferPool = pixelBufferAdaptor?.pixelBufferPool else { return }

let status = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferPool, &pixelBuffer)
guard status == kCVReturnSuccess else {
print("Failed to create pixel buffer")
return
}
}

guard let pixelBuffer = pixelBuffer else {
print("Pixel buffer is nil")
return
}
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
print("Failed to get image buffer.")
return
}

// fast, up to ~1 ms
let ciImage = CIImage(cvPixelBuffer: imageBuffer)

// fast, up to ~1 ms
let compositedImage = watemarkImage.composited(over: ciImage)

var tookTime = CFAbsoluteTimeGetCurrent()

// very slow, ~30 ms for 4K resolution on iPhone 11 (base)
cIContext.render(compositedImage, to: pixelBuffer)

tookTime = CFAbsoluteTimeGetCurrent() - tookTime

// fast, up to ~1 ms
pixelBufferAdaptor?.append(pixelBuffer, withPresentationTime: presentationTime)

print("cIContext.render took \(tookTime * 1000) ms")
}
}
Обновление:
Мне удалось преобразовать CIImage в MTLTexture, и затем MTLTexture в CVPixelBuffer, работает немного быстрее, но по какой-то причине изображение перевернуто по вертикали:

Код: Выделить всё

// before starting the recording:

let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(
pixelFormat: .bgra8Unorm, // Choose a suitable pixel format
width: Int(frameSize.width),
height: Int(frameSize.height),
mipmapped: false
)
textureDescriptor.usage = [.shaderWrite] // Important!

// Create the Metal texture
texture = mtlDevice.makeTexture(descriptor: textureDescriptor)

// in captureOutput function:

var ciImage = CIImage(cvPixelBuffer: imageBuffer)
// additionally process CIImage (add some filters) and get a new CIImage

let commandBuffer = commandQueue.makeCommandBuffer()

ciContext.render(
ciImage,
to: texture,
commandBuffer: commandBuffer,
bounds: CGRect(x: 0, y: 0, width: frameSize.width, height: frameSize.height),
colorSpace: CGColorSpaceCreateDeviceRGB()
)
commandBuffer.commit()
commandBuffer.waitUntilCompleted()

let width = texture.width
let height = texture.height

CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)
if let pixelBufferBaseAddress = CVPixelBufferGetBaseAddress(pixelBuffer) {
texture.getBytes(
pixelBufferBaseAddress,
bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer),
from: MTLRegionMake2D(0, 0, width, height),
mipmapLevel: 0
)
}
CVPixelBufferUnlockBaseAddress(pixelBuffer, .readOnly)

pixelBufferAdaptor?.append(pixelBuffer, withPresentationTime: presentationTime)
Что здесь может быть не так?
Обновление 2:
Это кажется, Металл работает именно так. В любом случае я только что использовал videoWriterInput.transform = CGAffineTransform(scaleX: 1, y: -1), чтобы «исправить это». Я пытался выполнить такое преобразование для CIImage перед преобразованием его в MLTexture, но по какой-то причине это не сработало.
Этот метод занимает около 23 мс вместо ~30 мс, так что это все еще не так. достаточно.
p.s.:
Я также собираюсь попытаться получить MLTexture непосредственно из CMSampleBuffer и добавить к нему фильтры (я думаю это будет сложнее по сравнению с фильтрами CIImage). Я попробовал следующий неожиданный результат преобразования CVPixelBuffer в код MTLTexture, но также столкнулся с проблемой, упомянутой автором
Обновление 3:
О прямой MLTexture из буфера камеры:
Потому что в принципе это может быть формат YUV (

Код: Выделить всё

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange
), поэтому нам нужно будет получить две текстуры:
var lumaTexture: CVMetalTexture?
var chromaTexture: CVMetalTexture?
и объединить их в два, преобразовать YUV в RGB с помощью Metal Shader.
Мне тоже удалось это сделать, и производительность очень хорошая, около 6-7 мс на все вещи (включая кодирование видео) в функции captureOutput.
Теперь появилась новая задача: как-то добавить водяной знак/наложение текста в MLTexture, потому что теперь у меня нет CIImage больше

Подробнее здесь: https://stackoverflow.com/questions/790 ... cpu-time-u
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «IOS»