AVFoundation: mirror viewfinder frames of front-facing cameras.

Change-Id: I95920aa459ff0931819cb6f8278ab296db542601
Reviewed-by: Andy Nichols <andy.nichols@digia.com>
This commit is contained in:
Yoann Lopes
2014-02-07 14:23:32 +01:00
committed by The Qt Project
parent c6ec402d25
commit 54066d2c21
4 changed files with 56 additions and 7 deletions

View File

@@ -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; }

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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()