diff options
Diffstat (limited to 'src')
3 files changed, 67 insertions, 125 deletions
diff --git a/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp b/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp index 3852c8cad..040509bb1 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp +++ b/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp @@ -3,6 +3,7 @@ // GPL-3.0-only #include "qffmpegscreencapture_dxgi_p.h" +#include "qffmpegscreencapturethread_p.h" #include <private/qabstractvideobuffer_p.h> #include <private/qmultimediautils_p.h> #include <private/qwindowsmultimediautils_p.h> @@ -152,64 +153,40 @@ static QMaybe<QWindowsIUPointer<ID3D11Texture2D>> getNextFrame(ID3D11Device *dev return texCopy; } -class DxgiScreenGrabberActive : public QThread +class QFFmpegScreenCaptureDxgi::Grabber : public QFFmpegScreenCaptureThread { public: - DxgiScreenGrabberActive(QPlatformScreenCapture &screenCapture, QWindowsIUPointer<ID3D11Device> &device, - QWindowsIUPointer<IDXGIOutputDuplication> &duplication, qreal maxFrameRate) - : QThread() - , m_screenCapture(screenCapture) + Grabber(QFFmpegScreenCaptureDxgi &screenCapture, QScreen *screen, QWindowsIUPointer<ID3D11Device> &device, + QWindowsIUPointer<IDXGIOutputDuplication> &duplication) + : QFFmpegScreenCaptureThread() , m_duplication(duplication) , m_device(device) - , m_maxFrameRate(maxFrameRate) - {} - - void run() override + , m_ctxMutex(std::make_shared<QMutex>()) { - // TODO: refactor with QTimer + setFrameRate(screen->refreshRate()); + addFrameCallback(screenCapture, &QFFmpegScreenCaptureDxgi::newVideoFrame); + connect(this, &Grabber::errorUpdated, &screenCapture, &QFFmpegScreenCaptureDxgi::updateError); + } - qCDebug(qLcScreenCaptureDxgi) << "ScreenGrabberActive started"; + ~Grabber() { + stop(); + } + void run() override + { DXGI_OUTDUPL_DESC outputDesc = {}; m_duplication->GetDesc(&outputDesc); - QSize frameSize = { int(outputDesc.ModeDesc.Width), int(outputDesc.ModeDesc.Height) }; - QVideoFrameFormat format(frameSize, QVideoFrameFormat::Format_BGRA8888); + m_frameSize = { int(outputDesc.ModeDesc.Width), int(outputDesc.ModeDesc.Height) }; + QVideoFrameFormat frameFormat(m_frameSize, QVideoFrameFormat::Format_BGRA8888); m_formatMutex.lock(); - m_format = format; - m_format.setFrameRate(int(m_maxFrameRate)); + m_format = frameFormat; + m_format.setFrameRate(int(frameRate())); m_formatMutex.unlock(); m_waitForFormat.wakeAll(); - const microseconds frameTime(quint64(1000000. / m_maxFrameRate)); - time_point frameStopTime = steady_clock::now(); - time_point frameStartTime = frameStopTime - frameTime; - - std::shared_ptr<QMutex> ctxMutex(new QMutex); - while (!isInterruptionRequested()) { - ctxMutex->lock(); - auto maybeTex = getNextFrame(m_device.get(), m_duplication.get()); - ctxMutex->unlock(); - - if (maybeTex) { - auto buffer = new QD3D11TextureVideoBuffer(m_device, ctxMutex, maybeTex.value(), frameSize); - QVideoFrame frame(buffer, format); - frame.setStartTime(duration_cast<microseconds>(frameStartTime.time_since_epoch()).count()); - frame.setEndTime(duration_cast<microseconds>(frameStopTime.time_since_epoch()).count()); - emit m_screenCapture.newVideoFrame(frame); - } else { - emit m_screenCapture.updateError(maybeTex.error().isEmpty() ? QScreenCapture::NoError - : QScreenCapture::CaptureFailed, - maybeTex.error()); - } - - frameStartTime = frameStopTime; - std::this_thread::sleep_until(frameStartTime + frameTime); - frameStopTime = steady_clock::now(); - } - - qCDebug(qLcScreenCaptureDxgi) << "ScreenGrabberActive finished"; + QFFmpegScreenCaptureThread::run(); } QVideoFrameFormat format() { @@ -219,14 +196,30 @@ public: return m_format; } + QVideoFrame grabFrame() override { + m_ctxMutex->lock(); + auto maybeTex = getNextFrame(m_device.get(), m_duplication.get()); + m_ctxMutex->unlock(); + + if (maybeTex) { + auto buffer = new QD3D11TextureVideoBuffer(m_device, m_ctxMutex, maybeTex.value(), m_frameSize); + return QVideoFrame(buffer, format()); + } else { + const auto status = maybeTex.error().isEmpty() ? QScreenCapture::NoError + : QScreenCapture::CaptureFailed; + updateError(status, maybeTex.error()); + } + return {}; + }; + private: - QPlatformScreenCapture &m_screenCapture; QWindowsIUPointer<IDXGIOutputDuplication> m_duplication; QWindowsIUPointer<ID3D11Device> m_device; - qreal m_maxFrameRate; QWaitCondition m_waitForFormat; QVideoFrameFormat m_format; QMutex m_formatMutex; + std::shared_ptr<QMutex> m_ctxMutex; + QSize m_frameSize; }; static QMaybe<QWindowsIUPointer<IDXGIOutputDuplication>> duplicateOutput(ID3D11Device* device, IDXGIOutput *output) @@ -291,94 +284,52 @@ static QMaybe<QWindowsIUPointer<ID3D11Device>> createD3D11Device(IDXGIAdapter1 * } QFFmpegScreenCaptureDxgi::QFFmpegScreenCaptureDxgi(QScreenCapture *screenCapture) - : QPlatformScreenCapture(screenCapture) -{ -} - -QFFmpegScreenCaptureDxgi::~QFFmpegScreenCaptureDxgi() + : QFFmpegScreenCaptureBase(screenCapture) { - resetGrabber(); } QVideoFrameFormat QFFmpegScreenCaptureDxgi::frameFormat() const { - if (m_active) - return m_active->format(); + if (m_grabber) + return m_grabber->format(); else return {}; } -void QFFmpegScreenCaptureDxgi::setScreen(QScreen *screen) +bool QFFmpegScreenCaptureDxgi::setActiveInternal(bool active) { - QScreen *oldScreen = m_screen; - if (oldScreen == screen) - return; + if (bool(m_grabber) == active) + return true; - bool active = bool(m_active); - if (active) - setActiveInternal(false); - - m_screen = screen; - if (active) - setActiveInternal(true); - - emit screenCapture()->screenChanged(screen); -} - -void QFFmpegScreenCaptureDxgi::setActiveInternal(bool active) -{ - if (bool(m_active) == active) - return; - - if (m_active) { - resetGrabber(); + if (m_grabber) { + m_grabber.reset(); + return true; } else { - QScreen *screen = m_screen ? m_screen : QGuiApplication::primaryScreen(); + QScreen *screen = this->screen() ? this->screen() : QGuiApplication::primaryScreen(); auto maybeDxgiScreen = findDxgiScreen(screen); if (!maybeDxgiScreen) { qCDebug(qLcScreenCaptureDxgi) << maybeDxgiScreen.error(); - emit updateError(QScreenCapture::NotFound, maybeDxgiScreen.error()); - return; + updateError(QScreenCapture::NotFound, maybeDxgiScreen.error()); + return false; } auto maybeDev = createD3D11Device(maybeDxgiScreen.value().adapter.get()); if (!maybeDev) { qCDebug(qLcScreenCaptureDxgi) << maybeDev.error(); - emit updateError(QScreenCapture::InternalError, maybeDev.error()); - return; + updateError(QScreenCapture::InternalError, maybeDev.error()); + return false; } auto maybeDupOutput = duplicateOutput(maybeDev.value().get(), maybeDxgiScreen.value().output.get()); if (!maybeDupOutput) { qCDebug(qLcScreenCaptureDxgi) << maybeDupOutput.error(); - emit updateError(QScreenCapture::InternalError, maybeDupOutput.error()); - return; + updateError(QScreenCapture::InternalError, maybeDupOutput.error()); + return false; } - qreal maxFrameRate = screen->refreshRate(); - m_active.reset(new DxgiScreenGrabberActive(*this, maybeDev.value(), maybeDupOutput.value(), maxFrameRate)); - m_active->start(); - } -} - -void QFFmpegScreenCaptureDxgi::setActive(bool active) -{ - if (bool(m_active) == active) - return; - - emit updateError(QScreenCapture::NoError, {}); - - setActiveInternal(active); - emit screenCapture()->activeChanged(active); -} - -void QFFmpegScreenCaptureDxgi::resetGrabber() -{ - if (m_active) { - m_active->requestInterruption(); - m_active->quit(); - m_active->wait(); - m_active.reset(); + m_grabber.reset(new Grabber(*this, screen, maybeDev.value(), maybeDupOutput.value())); + m_grabber->start(); + return true; } } diff --git a/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi_p.h b/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi_p.h index 0bb5079b2..4c9c75a07 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi_p.h +++ b/src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi_p.h @@ -17,35 +17,26 @@ // #include "qvideoframeformat.h" +#include "qffmpegscreencapturebase_p.h" #include <private/qwindowsiupointer_p.h> #include <private/qplatformscreencapture_p.h> #include <memory> QT_BEGIN_NAMESPACE -class DxgiScreenGrabberActive; -class QFFmpegScreenCaptureDxgi : public QPlatformScreenCapture +class QFFmpegScreenCaptureDxgi : public QFFmpegScreenCaptureBase { public: - explicit QFFmpegScreenCaptureDxgi(QScreenCapture *screenCapture); - ~QFFmpegScreenCaptureDxgi(); + QFFmpegScreenCaptureDxgi(QScreenCapture *screenCapture); - void setActive(bool active) override; - bool isActive() const override { return bool(m_active); } QVideoFrameFormat frameFormat() const override; - void setScreen(QScreen *screen) override; - QScreen *screen() const override { return m_screen; } - private: - void setActiveInternal(bool active); - - void resetGrabber(); + bool setActiveInternal(bool active) override; private: - std::unique_ptr<DxgiScreenGrabberActive> m_active; - QScreen *m_screen = nullptr; - QVideoFrameFormat m_format; + class Grabber; + std::unique_ptr<Grabber> m_grabber; }; QT_END_NAMESPACE diff --git a/src/plugins/multimedia/ffmpeg/qffmpegscreencapturethread_p.h b/src/plugins/multimedia/ffmpeg/qffmpegscreencapturethread_p.h index 0715263dd..cb5dcb03f 100644 --- a/src/plugins/multimedia/ffmpeg/qffmpegscreencapturethread_p.h +++ b/src/plugins/multimedia/ffmpeg/qffmpegscreencapturethread_p.h @@ -44,10 +44,6 @@ public: ~QFFmpegScreenCaptureThread() override; - void setFrameRate(qreal rate); - - qreal frameRate() const; - void stop(); template<typename Object, typename Method> @@ -69,6 +65,10 @@ protected: virtual QVideoFrame grabFrame() = 0; protected: + void setFrameRate(qreal rate); + + qreal frameRate() const; + void updateTimerInterval(); private: |