0

Metal을 사용하여 비디오 출력 (CMPixelBuffer)을 조작하는 올바른 방법을 이해하려고합니다.AVCaptureSession 비디오 출력을 사용한 금속 사용 이해

내가 이해하는 한 MTKView이 있습니다. 비디오 출력의 각 CMPixelBufferMetal Texture의 일부에 할당됩니다. 따라서 최종 미리보기는 MTKView입니다. 전 화면의 최종 결과를 참조하면

, 그것이 :

1)CMSampleBuffer->Metal->CMSampleBuffer 

또는

2)CMSampleBuffer->Metal->MTKView 

꽤 혼란

. 누군가 물건을 현장에 놓을 수 있습니까?

답변

1

두 단계로 수행하는 것이 좋습니다. 먼저, Metal과 MTKView을 사용하여 편하게 화면에 무언가를 그립니다. 둘째, 메탈로 그리는 방법을 알고 (명령 버퍼를 생성하고 인코딩 할 수있는 드로잉 등), CMSampleBuffer에서 생성 한 텍스처를 전체 화면 쿼드 또는 원하는 다른 지오메트리에 적용 할 수 있습니다.

간단한 예제를 구현하는 @McZonk의 카메라 캡처 샘플 here이 있습니다. 두 개의 평면 YCbCr 샘플 버퍼를 사용하지만 가능한 경우 BGRA 형식의 샘플 버퍼를 요청할 수 있습니다. MTLTextureCVMetalTextureCacheCreateTextureFromImage으로 변환하고 추가 수동 변환없이 셰이더에서 샘플링 할 수 있습니다.

+0

Warrenm, 난 생각이 나는 금속 필드 : 감사에서 나의 멘토를 발견했습니다 당신은 당신의 상세한 답변을 원합니다. 10 분간의 콘 수마 채팅을 주선 할 수 있습니까? (필요한 경우 지불), 난 그냥 물음표를 잔뜩, 내가 해결하고 싶습니다, 그리고 불행히도 웹 아직 나에게 대답을주고있다. 어느 쪽이든 - 고맙습니다! –

+0

내가 연락 할게 :) – warrenm

+0

채팅을 만들기 위해이 답변을 스팸 메일로 보내려고합니다. –

0

금속 질감에 비디오 카메라에 의해 생성 된 샘플 버퍼로 변환하는 데 필요한 간단한, 베어 최소 코드 :

@import UIKit; 
@import AVFoundation; 
@import CoreMedia; 
#import <MetalKit/MetalKit.h> 
#import <Metal/Metal.h> 
#import <MetalPerformanceShaders/MetalPerformanceShaders.h> 

@interface ViewController : UIViewController <MTKViewDelegate, AVCaptureVideoDataOutputSampleBufferDelegate> { 
    NSString *_displayName; 
    NSString *serviceType; 
} 

@property (retain, nonatomic) SessionContainer *session; 
@property (retain, nonatomic) AVCaptureSession *avSession; 

@end; 

#import "ViewController.h" 

@interface ViewController() { 
    MTKView *_metalView; 

    id<MTLDevice> _device; 
    id<MTLCommandQueue> _commandQueue; 
    id<MTLTexture> _texture; 

    CVMetalTextureCacheRef _textureCache; 
} 

@property (strong, nonatomic) AVCaptureDevice *videoDevice; 
@property (nonatomic) dispatch_queue_t sessionQueue; 

@end 

@implementation ViewController 

- (void)viewDidLoad { 
    NSLog(@"%s", __PRETTY_FUNCTION__); 
    [super viewDidLoad]; 

    _device = MTLCreateSystemDefaultDevice(); 
    _metalView = [[MTKView alloc] initWithFrame:self.view.bounds]; 
    [_metalView setContentMode:UIViewContentModeScaleAspectFit]; 
    _metalView.device = _device; 
    _metalView.delegate = self; 
    _metalView.clearColor = MTLClearColorMake(1, 1, 1, 1); 
    _metalView.colorPixelFormat = MTLPixelFormatBGRA8Unorm; 
    _metalView.framebufferOnly = NO; 
    _metalView.autoResizeDrawable = NO; 

    CVMetalTextureCacheCreate(NULL, NULL, _device, NULL, &_textureCache); 

    [self.view addSubview:_metalView]; 

    self.sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL); 

    if ([self setupCamera]) { 
     [_avSession startRunning]; 
    } 
} 

- (BOOL)setupCamera { 
    NSLog(@"%s", __PRETTY_FUNCTION__); 
    @try { 
     NSError * error; 

      _avSession = [[AVCaptureSession alloc] init]; 
      [_avSession beginConfiguration]; 
      [_avSession setSessionPreset:AVCaptureSessionPreset640x480]; 

      // get list of devices; connect to front-facing camera 
      self.videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
      if (self.videoDevice == nil) return FALSE; 

      AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:self.videoDevice error:&error]; 
      [_avSession addInput:input]; 

      dispatch_queue_t sampleBufferQueue = dispatch_queue_create("CameraMulticaster", DISPATCH_QUEUE_SERIAL); 

      AVCaptureVideoDataOutput * dataOutput = [[AVCaptureVideoDataOutput alloc] init]; 
      [dataOutput setAlwaysDiscardsLateVideoFrames:YES]; 
      [dataOutput setVideoSettings:@{(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}]; 
      [dataOutput setSampleBufferDelegate:self queue:sampleBufferQueue]; 

      [_avSession addOutput:dataOutput]; 
      [_avSession commitConfiguration]; 
    } @catch (NSException *exception) { 
     NSLog(@"%s - %@", __PRETTY_FUNCTION__, exception.description); 
     return FALSE; 
    } @finally { 
     return TRUE; 
    } 

} 

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{ 
    CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    { 
     size_t width = CVPixelBufferGetWidth(pixelBuffer); 
     size_t height = CVPixelBufferGetHeight(pixelBuffer); 

     CVMetalTextureRef texture = NULL; 
     CVReturn status = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, _textureCache, pixelBuffer, NULL, MTLPixelFormatBGRA8Unorm, width, height, 0, &texture); 
     if(status == kCVReturnSuccess) 
     { 
      _metalView.drawableSize = CGSizeMake(width, height); 
      _texture = CVMetalTextureGetTexture(texture); 
      _commandQueue = [_device newCommandQueue]; 
      CFRelease(texture); 
     } 
    } 
} 

- (void)drawInMTKView:(MTKView *)view { 
    // creating command encoder 
    if (_texture) { 
     id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer]; 
     id<MTLTexture> drawingTexture = view.currentDrawable.texture; 

     // set up and encode the filter 
     MPSImageGaussianBlur *filter = [[MPSImageGaussianBlur alloc] initWithDevice:_device sigma:5]; 

     [filter encodeToCommandBuffer:commandBuffer sourceTexture:_texture destinationTexture:drawingTexture]; 

     // committing the drawing 
     [commandBuffer presentDrawable:view.currentDrawable]; 
     [commandBuffer commit]; 
     _texture = nil; 
    } 
} 

- (void)mtkView:(MTKView *)view drawableSizeWillChange:(CGSize)size { 

} 

@end 
관련 문제