AVFoundation - 如何在 Mac OS X 上从网络摄像头镜像视频

12

我正在尝试在Mac OS X上镜像从网络摄像头接收到的视频。我想要在接收视频缓冲后避免手动翻转/变换。因此,我希望设置AVCaptureSession,使得由AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput方法接收的视频缓冲自己被AVFoundation镜像处理。我不想使用预览图层。

在iMac(10.8.5)上,为了镜像视频,在设置videoMirrored属性之前成功测试AVCaptureConnection isVideoMirroringSupported。但是在captureOutput委托中接收到的视频缓冲没有被镜像。

注意:当我按照 SO答案操作时,iOS上的视频镜像是成功的。但这对于Mac OS X没有帮助。

以下是使用的代码。本文未包含错误检查。

    //create session
    _session = [[AVCaptureSession alloc] init];

    //get capture device
    _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    //create sesion input
    NSError * error;
    _sessionInput = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];

    //create session output
    _sessionOutput = [[AVCaptureVideoDataOutput alloc] init];
    [_sessionOutput setAlwaysDiscardsLateVideoFrames:YES];
    [[_sessionOutput connectionWithMediaType:AVMediaTypeVideo] setEnabled:YES];
    NSDictionary *videoSettings = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
    [_sessionOutput setVideoSettings:videoSettings];

    //serial queue to process video frames
    dispatch_queue_t videoOutputQueue = dispatch_queue_create("deviceeraQueue", DISPATCH_QUEUE_SERIAL);
    [_sessionOutput setSampleBufferDelegate:self queue:videoOutputQueue];

    //begin session configuration
    [_session beginConfiguration ];

    //input and output for session
    if( [_session canAddInput:_sessionInput]) {
        [_session addInput:_sessionInput];
    }
    if( [_session canAddOutput:_sessionOutput]) {
        [_session addOutput:_sessionOutput];

    }

    //set video mirroring
    AVCaptureConnection* avConnection = [_sessionOutput connectionWithMediaType:AVMediaTypeVideo];
    if( [avConnection isVideoMirroringSupported]) {
        avConnection.videoMirrored = YES;
        NSLog(@"Video mirroring Support: YES"); // this line is printed
    } else {
        NSLog(@"Video mirroring Support: NO");
    }

    //set session preset    
    [_session setSessionPreset:AVCaptureSessionPreset640x480];
    [ _session commitConfiguration ];

    ...........
    ...........

    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
    {
    .........
    //sampleBuffer is not mirrored video
    ........

其次 1 - 尽管我也尝试查看OpenCV的VideoCapture实现以了解如何镜像视频,但是OpenCV不支持从Mac镜像视频(使用翻转)。可选方案是libVlc / V4L。

其次 2 - 在这个2010年苹果公司的wwdc演示文稿第73页中提到,在“AVCaptureVideoDataOutput”连接上不支持“setVideoOrientation”。但是在2013年,苹果的文档进行了更新,并支持此方法。


isVideoMirrored API 上发现了相同的问题,我使用了一个预览层,预览层可以正确镜像设置,但我使用 AVCaptureAudioDataOutput 实际录制视频,在输出代理中:captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection),样本缓冲区没有被镜像。 - kakaiikaka
3个回答

6

在预览层上添加转换,以便在帧到达预览窗口之前翻转x值。

[[self previewLayer] setTransform:CATransform3DMakeScale(-1, 1, 1)];

然后,您可以通过导出会话运行记录的视频并进行相同的转换。这样,视频预览将与最终记录的视频匹配。有点麻烦,但它可以获得相同的结果。


谢谢。但是在问题中,我提到了不愿使用预览层(第1段)。 - kiranpradeep
2
OSX不尊重videoMirrored属性,可能是一个bug。使用预览层是我发现实现这种效果的唯一方法。 - tansk1

5

如果非常容易,为什么要黑进去呢?只需设置AVCaptureConnection的automaticallyAdjustVideoMirroring然后手动设置即可。

    aPreviewLayer.connection.automaticallyAdjustsVideoMirroring = NO;
    aPreviewLayer.connection.videoMirrored = YES;

谢谢。但请注意我在问题的第一段中提到的不愿意预览图层的问题。这个问题在我对之前答案的评论中再次提到了。 - kiranpradeep
我认为你不能不使用预览层来实现。但是你可以通过缩放等方式来达到相同的效果。通过将缓冲区按比例缩放(x,y,z)=(-1,1,1),就可以实现镜像效果 :) - Þorvaldur Rúnarsson
我认为你不能在不使用预览层的情况下完成。为了支持这一点,我们需要一个有效的源文件或者苹果公司接受的错误报告来证明。 - kiranpradeep

0

“Þorvaldur Rúnarsson”答案的Swift 5版本:

previewLayer.connection?.automaticallyAdjustsVideoMirroring = false
previewLayer.connection?.isVideoMirrored = true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接