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);
|
void setVideoOutput(AVFVideoRendererControl *output);
|
||||||
AVCaptureSession *captureSession() const { return m_captureSession; }
|
AVCaptureSession *captureSession() const { return m_captureSession; }
|
||||||
|
AVCaptureDevice *videoCaptureDevice() const;
|
||||||
|
|
||||||
QCamera::State state() const;
|
QCamera::State state() const;
|
||||||
QCamera::State requestedState() const { return m_state; }
|
QCamera::State requestedState() const { return m_state; }
|
||||||
|
|||||||
@@ -155,7 +155,15 @@ void AVFCameraSession::setVideoOutput(AVFVideoRendererControl *output)
|
|||||||
{
|
{
|
||||||
m_videoOutput = output;
|
m_videoOutput = output;
|
||||||
if (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
|
QCamera::State AVFCameraSession::state() const
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public:
|
|||||||
QAbstractVideoSurface *surface() const;
|
QAbstractVideoSurface *surface() const;
|
||||||
void setSurface(QAbstractVideoSurface *surface);
|
void setSurface(QAbstractVideoSurface *surface);
|
||||||
|
|
||||||
void configureAVCaptureSession(AVCaptureSession *captureSession);
|
void configureAVCaptureSession(AVFCameraSession *cameraSession);
|
||||||
void syncHandleViewfinderFrame(const QVideoFrame &frame);
|
void syncHandleViewfinderFrame(const QVideoFrame &frame);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
@@ -74,13 +74,16 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void handleViewfinderFrame();
|
void handleViewfinderFrame();
|
||||||
|
void updateCaptureConnection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QAbstractVideoSurface *m_surface;
|
QAbstractVideoSurface *m_surface;
|
||||||
AVFCaptureFramesDelegate *m_viewfinderFramesDelegate;
|
AVFCaptureFramesDelegate *m_viewfinderFramesDelegate;
|
||||||
AVCaptureSession *m_captureSession;
|
AVFCameraSession *m_cameraSession;
|
||||||
AVCaptureVideoDataOutput *m_videoDataOutput;
|
AVCaptureVideoDataOutput *m_videoDataOutput;
|
||||||
|
|
||||||
|
bool m_needsHorizontalMirroring;
|
||||||
|
|
||||||
QVideoFrame m_lastViewfinderFrame;
|
QVideoFrame m_lastViewfinderFrame;
|
||||||
QMutex m_vfMutex;
|
QMutex m_vfMutex;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -146,13 +146,14 @@ private:
|
|||||||
AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent)
|
AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent)
|
||||||
: QVideoRendererControl(parent)
|
: QVideoRendererControl(parent)
|
||||||
, m_surface(0)
|
, m_surface(0)
|
||||||
|
, m_needsHorizontalMirroring(false)
|
||||||
{
|
{
|
||||||
m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:this];
|
m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:this];
|
||||||
}
|
}
|
||||||
|
|
||||||
AVFVideoRendererControl::~AVFVideoRendererControl()
|
AVFVideoRendererControl::~AVFVideoRendererControl()
|
||||||
{
|
{
|
||||||
[m_captureSession removeOutput:m_videoDataOutput];
|
[m_cameraSession->captureSession() removeOutput:m_videoDataOutput];
|
||||||
[m_viewfinderFramesDelegate release];
|
[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];
|
m_videoDataOutput = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
|
||||||
|
|
||||||
@@ -188,7 +193,23 @@ void AVFVideoRendererControl::configureAVCaptureSession(AVCaptureSession *captur
|
|||||||
[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
|
[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
|
||||||
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
|
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
|
//can be called from non main thread
|
||||||
@@ -203,6 +224,22 @@ void AVFVideoRendererControl::syncHandleViewfinderFrame(const QVideoFrame &frame
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_lastViewfinderFrame = 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()
|
void AVFVideoRendererControl::handleViewfinderFrame()
|
||||||
|
|||||||
Reference in New Issue
Block a user