From 89e6018f6f45350924e3c5f7007f779b9ed4cdeb Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Fri, 27 Jul 2018 12:42:46 +0200 Subject: DirectShow: Postpone setting camera image processing param if not ready Setting camera image processing parameters fails if the graph builder is not ready. We avoid this race condition by having a list of pending parameter changes which is applied when graph builder has been created. Task-number: QTBUG-69143 Change-Id: I5702ea5a2dceacff333fcf8dce05372a0208b8d9 Reviewed-by: Oliver Wolff Reviewed-by: Maurice Kalinowski --- src/plugins/directshow/camera/dscamerasession.cpp | 13 ++++++++++--- src/plugins/directshow/camera/dscamerasession.h | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index ca3c47cb8..324ab44e2 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -208,8 +208,8 @@ QVariant DSCameraSession::imageProcessingParameter( QCameraImageProcessingControl::ProcessingParameter parameter) const { if (!m_graphBuilder) { - qWarning() << "failed to access to the graph builder"; - return QVariant(); + auto it = m_pendingImageProcessingParametrs.find(parameter); + return it != m_pendingImageProcessingParametrs.end() ? it.value() : QVariant(); } const QCameraImageProcessingControl::ProcessingParameter resultingParameter = @@ -249,7 +249,7 @@ void DSCameraSession::setImageProcessingParameter( const QVariant &value) { if (!m_graphBuilder) { - qWarning() << "failed to access to the graph builder"; + m_pendingImageProcessingParametrs.insert(parameter, value); return; } @@ -960,6 +960,13 @@ void DSCameraSession::updateImageProcessingParametersInfos() } pVideoProcAmp->Release(); + + for (auto it = m_pendingImageProcessingParametrs.cbegin(); + it != m_pendingImageProcessingParametrs.cend(); + ++it) { + setImageProcessingParameter(it.key(), it.value()); + } + m_pendingImageProcessingParametrs.clear(); } bool DSCameraSession::connectGraph() diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h index 07c3d9ef9..c3be6144e 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -230,6 +230,8 @@ private: // Internal state QCamera::Status m_status; + QMap m_pendingImageProcessingParametrs; + friend class SampleGrabberCallbackPrivate; }; -- cgit v1.2.3 From 1b58b96bdf32ab9a89cba0ae43170804c0571ede Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Wed, 9 May 2018 13:50:16 +0200 Subject: DirectShow: Notify if camera has been unplugged If being used camera has been disconnected, state and status will remain like it is still active. Also no events are sent. Previously to fix this the camera needed to be unloaded and loaded again manually. IMediaEvent provides an ability to catch device removal notification with EC_DEVICE_LOST event. Since ISampleGrabber is used to get buffers. Added a fix to check if no buffers received for some time afterwards check for EC_DEVICE_LOST event. In case if the device is lost, the camera should be unloaded. Change-Id: I3a5edf00ce8ee25d8b06800fdad833a722bdba0d Task-number: QTBUG-68035 Reviewed-by: VaL Doroshchuk Reviewed-by: Maurice Kalinowski --- src/plugins/directshow/camera/dscameracontrol.cpp | 8 +++++-- src/plugins/directshow/camera/dscamerasession.cpp | 28 +++++++++++++++++++++++ src/plugins/directshow/camera/dscamerasession.h | 3 ++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/plugins/directshow/camera/dscameracontrol.cpp b/src/plugins/directshow/camera/dscameracontrol.cpp index 8d923da9f..7a2b46a2c 100644 --- a/src/plugins/directshow/camera/dscameracontrol.cpp +++ b/src/plugins/directshow/camera/dscameracontrol.cpp @@ -51,8 +51,12 @@ DSCameraControl::DSCameraControl(QObject *parent) , m_captureMode(QCamera::CaptureStillImage) { m_session = qobject_cast(parent); - connect(m_session, SIGNAL(statusChanged(QCamera::Status)), - this, SIGNAL(statusChanged(QCamera::Status))); + connect(m_session, &DSCameraSession::statusChanged, + [&](QCamera::Status status) { + if (status == QCamera::UnloadedStatus) + m_state = QCamera::UnloadedState; + emit statusChanged(status); + }); connect(m_session, &DSCameraSession::cameraError, this, &DSCameraControl::error); } diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 324ab44e2..c309359ed 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -76,6 +76,30 @@ DSCameraSession::DSCameraSession(QObject *parent) { connect(this, SIGNAL(statusChanged(QCamera::Status)), this, SLOT(updateReadyForCapture())); + + m_deviceLostEventTimer.setSingleShot(true); + connect(&m_deviceLostEventTimer, &QTimer::timeout, [&]() { + IMediaEvent *pEvent = com_cast(m_filterGraph, IID_IMediaEvent); + if (!pEvent) + return; + + long eventCode; + LONG_PTR param1; + LONG_PTR param2; + while (pEvent->GetEvent(&eventCode, ¶m1, ¶m2, 0) == S_OK) { + switch (eventCode) { + case EC_DEVICE_LOST: + unload(); + break; + default: + break; + } + + pEvent->FreeEventParams(eventCode, param1, param2); + } + + pEvent->Release(); + }); } DSCameraSession::~DSCameraSession() @@ -582,6 +606,10 @@ void DSCameraSession::onFrameAvailable(double time, const QByteArray &data) m_presentMutex.lock(); + // If no frames provided from ISampleGrabber for some time + // the device might be potentially unplugged. + m_deviceLostEventTimer.start(100); + // (We should be getting only RGB32 data) int stride = m_previewSize.width() * 4; diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h index c3be6144e..433db8994 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -44,7 +44,7 @@ #include #include #include - +#include #include #include #include @@ -229,6 +229,7 @@ private: // Internal state QCamera::Status m_status; + QTimer m_deviceLostEventTimer; QMap m_pendingImageProcessingParametrs; -- cgit v1.2.3 From 02ac3f58721bb52db612acd3bb2e2c26bfc3e05b Mon Sep 17 00:00:00 2001 From: VaL Doroshchuk Date: Mon, 25 Jun 2018 15:21:10 +0200 Subject: AVFoundation: Use opengl context from surface as shared Since few opengl contexts could be used at the same time, CARenderer could use wrong context to render the video frame. If the video surface contains an opengl context then need to use it as shared regardless of existing of current context. Change-Id: Ie7e87682c73c0fd341b40c05e3f3c4a70d563242 Reviewed-by: Andy Nichols --- .../avfoundation/mediaplayer/avfvideoframerenderer.mm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm b/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm index 7e2f8722e..0759702e8 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm @@ -126,8 +126,14 @@ QOpenGLFramebufferObject *AVFVideoFrameRenderer::initRenderer(AVPlayerLayer *lay //Get size from AVPlayerLayer m_targetSize = QSize(layer.bounds.size.width, layer.bounds.size.height); + QOpenGLContext *shareContext = !m_glContext && m_surface + ? qobject_cast(m_surface->property("GLContext").value()) + : nullptr; + //Make sure we have an OpenGL context to make current - if (!QOpenGLContext::currentContext() && !m_glContext) { + if ((shareContext && shareContext != QOpenGLContext::currentContext()) + || (!QOpenGLContext::currentContext() && !m_glContext)) { + //Create Hidden QWindow surface to create context in this thread m_offscreenSurface = new QWindow(); m_offscreenSurface->setSurfaceType(QWindow::OpenGLSurface); @@ -135,12 +141,6 @@ QOpenGLFramebufferObject *AVFVideoFrameRenderer::initRenderer(AVPlayerLayer *lay m_offscreenSurface->setGeometry(0, 0, 1, 1); m_offscreenSurface->create(); - //Create OpenGL context and set share context from surface - QOpenGLContext *shareContext = 0; - if (m_surface) { - //QOpenGLContext *renderThreadContext = 0; - shareContext = qobject_cast(m_surface->property("GLContext").value()); - } m_glContext = new QOpenGLContext(); m_glContext->setFormat(m_offscreenSurface->requestedFormat()); -- cgit v1.2.3