Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVFoundation - how to mirror video from webcam - Mac OS X

I am trying to mirror video received from webcam on mac os x. I would like to avoid doing a manual flip/tranform after receiving the video buffer . So, I want to setup AVCaptureSession such that video buffer received in captureOutput method of AVCaptureVideoDataOutputSampleBufferDelegate is mirrored by AVFoundation itself. I don't want to use the preview layer.

On an iMac(10.8.5), to mirror video, AVCaptureConnection isVideoMirroringSupported is successfully tested before setting the videoMirrored property. But video buffer received in captureOutput delegate isn't mirrored.

Note: Video mirroring on iOS was successful, when I followed this SO answer. But it isn't helping on mac os x.

Code used is below. Error checking is left out for this post.

    //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
    ........

Of lesser importance 1 - though C++, I also tried looking into OpenCV's VideoCapture implementation for way to mirror video. But, OpenCV don't mirror video from Mac(uses flip). Left is libVlc/V4L.

Of lesser importance 2 - In slide 73 of this 2010 wwdc apple presentation (3Mb pdf), there is a mention that setVideoOrientation is not supported on 'AVCaptureVideoDataOutput` connection. But in 2013, apple docs are updated and supports this method.

like image 600
kiranpradeep Avatar asked May 16 '14 13:05

kiranpradeep


2 Answers

Why hack it when it's very easy. Just set automaticallyAdjustVideoMirroring of your AVCaptureConnection then set it manually.

    aPreviewLayer.connection.automaticallyAdjustsVideoMirroring = NO;
    aPreviewLayer.connection.videoMirrored = YES;
like image 179
Þorvaldur Rúnarsson Avatar answered Sep 23 '22 10:09

Þorvaldur Rúnarsson


You can add a transform on the preview layer to flip x value of the frames before they get to the preview window.

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

Then you can run the recorded video through export session and do the same transformation. That way the video preview will match the final recorded video. Bit of a hack, but it gets the same results.

like image 6
tansk1 Avatar answered Sep 24 '22 10:09

tansk1