AVFoundation: mirror viewfinder frames of front-facing cameras.
Change-Id: I95920aa459ff0931819cb6f8278ab296db542601 Reviewed-by: Andy Nichols <andy.nichols@digia.com>
This commit is contained in:
committed by
The Qt Project
parent
c6ec402d25
commit
54066d2c21
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user