¿Cuántos pasos se requieren para grabar SCNView en video?

idea principal

A través de la devolución de llamada de SCNView, obtenga id<SCNSceneRenderer>la textura de destino de representación de metal renderPass, copie la textura de destino de representación en la textura de metal creada en base a CVPixelBuffer y luego escriba CVPixelBuffer en el archivo de video.

Preparar la herramienta de escritura de video

La creación de videos se puede realizar fácilmente utilizando el propio AVAssetWritercódigo integrado del sistema, que se puede crear y configurar a través del siguiente códigoAVAssetWriter

self.videoWriter = [AVAssetWriter assetWriterWithURL:outputURL fileType:AVFileTypeQuickTimeMovie error:&error];

NSDictionary *writerInputParams = [NSDictionary dictionaryWithObjectsAndKeys:
                                               AVVideoCodecTypeH264, AVVideoCodecKey,
                                                         [NSNumber numberWithInt:width], AVVideoWidthKey,
                                                         [NSNumber numberWithInt:height], AVVideoHeightKey,
                                                         AVVideoScalingModeResizeAspectFill, AVVideoScalingModeKey,
                                                         nil];
               
self.assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:writerInputParams];
if ([self.videoWriter canAddInput:self.assetWriterInput]) {
    [self.videoWriter addInput:self.assetWriterInput];
} else {
    // show error message
}

NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
                            [NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange], (NSString*)kCVPixelBufferPixelFormatTypeKey,
                            [NSNumber numberWithBool:YES], (NSString *)kCVPixelBufferCGImageCompatibilityKey,
                            [NSNumber numberWithBool:YES], (NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey,
                            nil];
self.writerAdaptor = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:self.assetWriterInput sourcePixelBufferAttributes:attributes];
复制代码

CVPixelBuffer se puede escribir en un archivo de video a través de la siguiente API

[self.writerAdaptor appendPixelBuffer:cvBuffer withPresentationTime:presentationTime]
复制代码

CVPixelBuffer listo para aceptar datos de imagen

Cree CVPixelBuffer y cree MTLTexture a partir de CVPixelBuffer para copiar la textura de destino de procesamiento de SCNView

int imageWidth = size.width;
int imageHeight = size.height;

NSDictionary *pixelAttributes = @{( id )kCVPixelBufferIOSurfacePropertiesKey : @{}};
CVPixelBufferCreate(
            kCFAllocatorDefault,
                    imageWidth,
                    imageHeight,
            kCVPixelFormatType_32BGRA,
                    (__bridge CFDictionaryRef)pixelAttributes,
                    &_renderTargetPixelBuffer);

CVReturn ret = CVMetalTextureCacheCreate(kCFAllocatorDefault, nil, _mtlDevice, nil, &_textureCache);

CVMetalTextureRef renderTargetMetalTextureRef;
ret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, _renderTargetPixelBuffer, nil, MTLPixelFormatBGRA8Unorm, imageWidth, imageHeight, 0, &renderTargetMetalTextureRef);

id<MTLTexture> mtlTexture = CVMetalTextureGetTexture(renderTargetMetalTextureRef);
CFRelease(renderTargetMetalTextureRef);
复制代码

Copie el resultado de renderizado de SCNView a CVPixelBuffer

Necesitamos - (void)renderer:(id<SCNSceneRenderer>)renderer didRenderScene:(SCNScene *)scene atTime:(NSTimeInterval)timecopiar el resultado de renderizado en la devolución de llamada de SCNView. Para copiar la textura de destino de renderizado de SCNView, se deben realizar las siguientes configuraciones

CAMetalLayer *metalLayer = (CAMetalLayer *)self.sceneView.layer;
[metalLayer setAllowsNextDrawableTimeout:NO];
metalLayer.framebufferOnly = NO;
复制代码

En la devolución de llamada, MTLBlitCommandEncodercopiamos la textura de destino del renderizado en nuestra propia textura .

MTLRenderPassDescriptor *renderPassDesc = renderer.currentRenderPassDescriptor;
id<MTLTexture> readTexture = renderPassDesc.colorAttachments[0].texture;
if (readTexture.width != _renderTargetTexture.width || readTexture.height != _renderTargetTexture.height) {
    _renderTargetTexture = [self createRenderTargetTexture:CGSizeMake(readTexture.width, readTexture.height)];
}

id<MTLCommandBuffer> blitCommandBuffer = [renderer.commandQueue commandBuffer];
id <MTLBlitCommandEncoder> blitEncoder = [blitCommandBuffer blitCommandEncoder];
[blitEncoder copyFromTexture:readTexture toTexture:_renderTargetTexture];
[blitEncoder endEncoding];

[blitCommandBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull buffer) {
    [self updateWithFrame:self->_renderTargetPixelBuffer];
}];
[blitCommandBuffer commit];
复制代码

blitCommandBufferViene de SCNView commandQueue, por lo que el comando para copiar la textura se ejecutará después de renderizar SCNView, lo que garantiza que la textura copiada sea una renderización completa. Tenga en cuenta que blitCommandBufferno se pueden usar subprocesos de bloqueo waitUntilCompleted, lo que conducirá a interbloqueos. Finalmente, updateWithFrameescribe el CVPixelBuffer AVAssetWriter.

Supongo que te gusta

Origin juejin.im/post/7119884702999117854
Recomendado
Clasificación