Самый быстрый способ записи видео из SCNView - PullRequest
0 голосов
/ 07 мая 2018

У меня есть SCNView с некоторым объектом в центре экрана, пользователь может вращать его, масштабировать и т. Д.

Я хочу записать все эти движения в видео и добавить звук в реальном времени. Также я хочу записать только среднюю часть SCNView (например, кадр SCNView 375x812, но я хочу только среднюю 375x375 без верхней и нижней границы). Также я хочу показать его на экране одновременно с захватом видео.

Мои текущие варианты:

func renderer(_ renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: TimeInterval) {
    DispatchQueue.main.async {
        if let metalLayer = self.sceneView.layer as? CAMetalLayer, let texture = metalLayer.currentSceneDrawable?.texture, let pixelBufferPool = self.pixelBufferPool {
            //1
            var maybePixelBuffer: CVPixelBuffer? = nil
            let status  = CVPixelBufferPoolCreatePixelBuffer(nil, pixelBufferPool, &maybePixelBuffer)

            guard let pixelBuffer = maybePixelBuffer else { return }

            CVPixelBufferLockBaseAddress(pixelBuffer, [])

            let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
            let region = MTLRegionMake2D(Int(self.fieldOfView.origin.x * UIScreen.main.scale),
                                         Int(self.fieldOfView.origin.y * UIScreen.main.scale),
                                         Int(self.fieldOfView.width * UIScreen.main.scale),
                                         Int(self.fieldOfView.height * UIScreen.main.scale))

            let pixelBufferBytes = CVPixelBufferGetBaseAddress(pixelBuffer)!
            texture.getBytes(pixelBufferBytes, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0)

            let uiImage = self.image(from: pixelBuffer)

            CVPixelBufferUnlockBaseAddress(pixelBuffer, [])

            //2
            if #available(iOS 11.0, *) {
                var pixelBuffer: Unmanaged<CVPixelBuffer>? = nil
                CVPixelBufferCreateWithIOSurface(kCFAllocatorDefault, texture.iosurface!, nil, UnsafeMutablePointer<Unmanaged<CVPixelBuffer>?>(&pixelBuffer))
                let imageBuffer = pixelBuffer!.takeUnretainedValue()
            } else {
                // Fallback on earlier versions
            }

            //3
            var pb: CVPixelBuffer? = nil
            let result = CVPixelBufferCreate(kCFAllocatorDefault, texture.width, texture.height, kCVPixelFormatType_32BGRA, nil, &pb)
            print(result)
            let ciImage = CIImage(mtlTexture: texture, options: nil)
            let context = CIContext()
            context.render(ciImage!, to: pb!)                
        }
    }
}

Полученный CVPixelBuffer будет добавлен в AVAssetWriter.

но все эти методы имеют некоторые недостатки.

1) MTLTexture имеет colorPixelFormat == 555 (bgra10_XR_sRGB, если я правильно помню), и я не знаю, как преобразовать его в BGR (чтобы добавить его в aseetWriter), ни как изменить этот colorPixelFormat, ни как добавить bgra10_XR_sRGB в aseetWriter.

2) Как реализовать версию для iOS10?

2,3) Какой самый быстрый способ обрезать изображение? Используя эти методы, я могу получить только полное изображение вместо обрезанного. И я не хочу конвертировать его в UIImage, потому что он слишком медленный.

P.S. мой предыдущий просмотрщик был на OpenGL ES (GLKView), и я успешно сделал это, используя этот метод (накладные расходы 1 мс вместо 30 мс с использованием метода .screenshot)

...