From 54066d2c216e871e3f4c08590f0e010dd2e76e69 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 7 Feb 2014 14:23:32 +0100 Subject: AVFoundation: mirror viewfinder frames of front-facing cameras. Change-Id: I95920aa459ff0931819cb6f8278ab296db542601 Reviewed-by: Andy Nichols --- src/plugins/avfoundation/camera/avfcamerasession.h | 1 + .../avfoundation/camera/avfcamerasession.mm | 10 ++++- .../avfoundation/camera/avfvideorenderercontrol.h | 7 +++- .../avfoundation/camera/avfvideorenderercontrol.mm | 45 ++++++++++++++++++++-- 4 files changed, 56 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h index 48681aae7..2630a35f7 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.h +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -64,6 +64,7 @@ public: void setVideoOutput(AVFVideoRendererControl *output); AVCaptureSession *captureSession() const { return m_captureSession; } + AVCaptureDevice *videoCaptureDevice() const; QCamera::State state() const; QCamera::State requestedState() const { return m_state; } diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index 5f1385a7e..93c2bacd0 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -155,7 +155,15 @@ void AVFCameraSession::setVideoOutput(AVFVideoRendererControl *output) { m_videoOutput = output; if (output) - output->configureAVCaptureSession(m_captureSession); + output->configureAVCaptureSession(this); +} + +AVCaptureDevice *AVFCameraSession::videoCaptureDevice() const +{ + if (m_videoInput) + return m_videoInput.device; + + return 0; } QCamera::State AVFCameraSession::state() const diff --git a/src/plugins/avfoundation/camera/avfvideorenderercontrol.h b/src/plugins/avfoundation/camera/avfvideorenderercontrol.h index 57978c05a..c080451c3 100644 --- a/src/plugins/avfoundation/camera/avfvideorenderercontrol.h +++ b/src/plugins/avfoundation/camera/avfvideorenderercontrol.h @@ -66,7 +66,7 @@ public: QAbstractVideoSurface *surface() const; void setSurface(QAbstractVideoSurface *surface); - void configureAVCaptureSession(AVCaptureSession *captureSession); + void configureAVCaptureSession(AVFCameraSession *cameraSession); void syncHandleViewfinderFrame(const QVideoFrame &frame); Q_SIGNALS: @@ -74,13 +74,16 @@ Q_SIGNALS: private Q_SLOTS: void handleViewfinderFrame(); + void updateCaptureConnection(); private: QAbstractVideoSurface *m_surface; AVFCaptureFramesDelegate *m_viewfinderFramesDelegate; - AVCaptureSession *m_captureSession; + AVFCameraSession *m_cameraSession; AVCaptureVideoDataOutput *m_videoDataOutput; + bool m_needsHorizontalMirroring; + QVideoFrame m_lastViewfinderFrame; QMutex m_vfMutex; }; diff --git a/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm b/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm index 6efa3cbf8..1a2054452 100644 --- a/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm +++ b/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm @@ -146,13 +146,14 @@ private: AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent) : QVideoRendererControl(parent) , m_surface(0) + , m_needsHorizontalMirroring(false) { m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:this]; } AVFVideoRendererControl::~AVFVideoRendererControl() { - [m_captureSession removeOutput:m_videoDataOutput]; + [m_cameraSession->captureSession() removeOutput:m_videoDataOutput]; [m_viewfinderFramesDelegate release]; } @@ -169,9 +170,13 @@ void AVFVideoRendererControl::setSurface(QAbstractVideoSurface *surface) } } -void AVFVideoRendererControl::configureAVCaptureSession(AVCaptureSession *captureSession) +void AVFVideoRendererControl::configureAVCaptureSession(AVFCameraSession *cameraSession) { - m_captureSession = captureSession; + m_cameraSession = cameraSession; + connect(m_cameraSession, SIGNAL(readyToConfigureConnections()), + this, SLOT(updateCaptureConnection())); + + m_needsHorizontalMirroring = false; m_videoDataOutput = [[[AVCaptureVideoDataOutput alloc] init] autorelease]; @@ -188,7 +193,23 @@ void AVFVideoRendererControl::configureAVCaptureSession(AVCaptureSession *captur [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]; - [m_captureSession addOutput:m_videoDataOutput]; + [m_cameraSession->captureSession() addOutput:m_videoDataOutput]; +} + +void AVFVideoRendererControl::updateCaptureConnection() +{ + AVCaptureConnection *connection = [m_videoDataOutput connectionWithMediaType:AVMediaTypeVideo]; + if (connection == nil || !m_cameraSession->videoCaptureDevice()) + return; + + // Frames of front-facing cameras should be mirrored horizontally (it's the default when using + // AVCaptureVideoPreviewLayer but not with AVCaptureVideoDataOutput) + if (connection.isVideoMirroringSupported) + connection.videoMirrored = m_cameraSession->videoCaptureDevice().position == AVCaptureDevicePositionFront; + + // If the connection does't support mirroring, we'll have to do it ourselves + m_needsHorizontalMirroring = !connection.isVideoMirrored + && m_cameraSession->videoCaptureDevice().position == AVCaptureDevicePositionFront; } //can be called from non main thread @@ -203,6 +224,22 @@ void AVFVideoRendererControl::syncHandleViewfinderFrame(const QVideoFrame &frame } m_lastViewfinderFrame = frame; + + if (m_needsHorizontalMirroring) { + m_lastViewfinderFrame.map(QAbstractVideoBuffer::ReadOnly); + + // no deep copy + QImage image(m_lastViewfinderFrame.bits(), + m_lastViewfinderFrame.size().width(), + m_lastViewfinderFrame.size().height(), + m_lastViewfinderFrame.bytesPerLine(), + QImage::Format_RGB32); + + QImage mirrored = image.mirrored(true, false); + + m_lastViewfinderFrame.unmap(); + m_lastViewfinderFrame = QVideoFrame(mirrored); + } } void AVFVideoRendererControl::handleViewfinderFrame() -- cgit v1.2.3