diff options
Diffstat (limited to 'src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp')
-rw-r--r-- | src/plugins/multimedia/ffmpeg/qffmpegscreencapture_dxgi.cpp | 163 |
1 files changed, 57 insertions, 106 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; } } |